mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2026-01-15 16:33:35 -03:00
Unminify using 1.5.323
Repo with tag: https://github.com/MediaBrowser/emby-webcomponents/tree/1.5.323
This commit is contained in:
@@ -1,158 +1,113 @@
|
||||
.actionSheet,
|
||||
.actionSheetContent {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex
|
||||
}
|
||||
|
||||
.actionSheetContent,
|
||||
.actionSheetScroller {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal
|
||||
}
|
||||
|
||||
.actionSheet {
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
border: none;
|
||||
max-height: 84%;
|
||||
-webkit-border-radius: .1em !important;
|
||||
border-radius: .1em !important
|
||||
border-radius: .1em !important;
|
||||
}
|
||||
|
||||
.actionsheet-not-fullscreen {
|
||||
max-width: 90%;
|
||||
max-height: 90%
|
||||
max-height: 90%;
|
||||
}
|
||||
|
||||
.actionsheet-fullscreen {
|
||||
max-height: none;
|
||||
-webkit-border-radius: 0 !important;
|
||||
border-radius: 0 !important
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.actionSheetContent-centered {
|
||||
text-align: center;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.actionSheetContent {
|
||||
margin: 0 !important;
|
||||
padding: .4em 0 !important;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
overflow: hidden
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.actionSheetMenuItem {
|
||||
font-weight: inherit;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.actionSheetMenuItem:focus {
|
||||
-webkit-transform: none !important;
|
||||
transform: none !important
|
||||
}
|
||||
.actionSheetMenuItem:focus {
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.actionsheetListItemBody {
|
||||
padding: .4em 1em .4em .6em !important
|
||||
padding: .4em 1em .4em .6em !important;
|
||||
}
|
||||
|
||||
.actionSheetItemText {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: start;
|
||||
-webkit-justify-content: flex-start;
|
||||
justify-content: flex-start
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.actionSheetItemAsideText {
|
||||
opacity: .7;
|
||||
font-size: 90%;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
margin-left: 5em;
|
||||
margin-right: .5em
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.actionSheetScroller {
|
||||
/* Override default style being applied by polymer */
|
||||
margin-bottom: 0 !important;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
width: 100%
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.actionSheetScroller-tv {
|
||||
max-height: 64%;
|
||||
max-width: 60%;
|
||||
width: auto
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.actionsheetDivider {
|
||||
height: .07em;
|
||||
margin: .25em 0;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.actionSheetTitle {
|
||||
margin: .6em 0 .7em !important;
|
||||
padding: 0 .9em;
|
||||
-webkit-box-flex: 0;
|
||||
-webkit-flex-grow: 0;
|
||||
flex-grow: 0
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.actionSheetText {
|
||||
padding: 0 1em;
|
||||
-webkit-box-flex: 0;
|
||||
-webkit-flex-grow: 0;
|
||||
flex-grow: 0
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.actionsheetMenuItemIcon {
|
||||
margin: 0 .85em 0 .45em !important;
|
||||
padding: 0 !important
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.actionsheet-xlargeFont {
|
||||
font-size: 112% !important
|
||||
font-size: 112%!important;
|
||||
}
|
||||
|
||||
.btnCloseActionSheet {
|
||||
position: fixed;
|
||||
top: .75em;
|
||||
left: .5em
|
||||
}
|
||||
left: .5em;
|
||||
}
|
||||
|
||||
@@ -1,93 +1,363 @@
|
||||
define(["dialogHelper", "layoutManager", "globalize", "browser", "dom", "emby-button", "css!./actionsheet", "material-icons", "scrollStyles", "listViewStyle"], function(dialogHelper, layoutManager, globalize, browser, dom) {
|
||||
"use strict";
|
||||
define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-button', 'css!./actionsheet', 'material-icons', 'scrollStyles', 'listViewStyle'], function (dialogHelper, layoutManager, globalize, browser, dom) {
|
||||
'use strict';
|
||||
|
||||
function getOffsets(elems) {
|
||||
var doc = document,
|
||||
results = [];
|
||||
if (!doc) return results;
|
||||
for (var box, elem, i = 0, length = elems.length; i < length; i++) elem = elems[i], box = elem.getBoundingClientRect ? elem.getBoundingClientRect() : {
|
||||
top: 0,
|
||||
left: 0
|
||||
}, results[i] = {
|
||||
top: box.top,
|
||||
left: box.left,
|
||||
width: box.width,
|
||||
height: box.height
|
||||
};
|
||||
return results
|
||||
|
||||
var doc = document;
|
||||
var results = [];
|
||||
|
||||
if (!doc) {
|
||||
return results;
|
||||
}
|
||||
|
||||
var box;
|
||||
var elem;
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elem = elems[i];
|
||||
// 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();
|
||||
} else {
|
||||
box = { top: 0, left: 0 };
|
||||
}
|
||||
|
||||
results[i] = {
|
||||
top: box.top,
|
||||
left: box.left,
|
||||
width: box.width,
|
||||
height: box.height
|
||||
};
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function getPosition(options, dlg) {
|
||||
var windowSize = dom.getWindowSize(),
|
||||
windowHeight = windowSize.innerHeight,
|
||||
windowWidth = windowSize.innerWidth;
|
||||
if (windowWidth < 600 || windowHeight < 600) return null;
|
||||
|
||||
var windowSize = dom.getWindowSize();
|
||||
var windowHeight = windowSize.innerHeight;
|
||||
var windowWidth = windowSize.innerWidth;
|
||||
|
||||
if (windowWidth < 600 || windowHeight < 600) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var pos = getOffsets([options.positionTo])[0];
|
||||
"top" !== options.positionY && (pos.top += (pos.height || 0) / 2), pos.left += (pos.width || 0) / 2;
|
||||
var height = dlg.offsetHeight || 300,
|
||||
width = dlg.offsetWidth || 160;
|
||||
pos.top -= height / 2, pos.left -= width / 2;
|
||||
var overflowX = pos.left + width - windowWidth,
|
||||
overflowY = pos.top + height - windowHeight;
|
||||
return overflowX > 0 && (pos.left -= overflowX + 20), overflowY > 0 && (pos.top -= overflowY + 20), pos.top += options.offsetTop || 0, pos.left += options.offsetLeft || 0, pos.top = Math.max(pos.top, 10), pos.left = Math.max(pos.left, 10), pos
|
||||
|
||||
if (options.positionY !== 'top') {
|
||||
pos.top += (pos.height || 0) / 2;
|
||||
}
|
||||
|
||||
pos.left += (pos.width || 0) / 2;
|
||||
|
||||
var height = dlg.offsetHeight || 300;
|
||||
var width = dlg.offsetWidth || 160;
|
||||
|
||||
// Account for popup size
|
||||
pos.top -= height / 2;
|
||||
pos.left -= width / 2;
|
||||
|
||||
// Avoid showing too close to the bottom
|
||||
var overflowX = pos.left + width - windowWidth;
|
||||
var overflowY = pos.top + height - windowHeight;
|
||||
|
||||
if (overflowX > 0) {
|
||||
pos.left -= (overflowX + 20);
|
||||
}
|
||||
if (overflowY > 0) {
|
||||
pos.top -= (overflowY + 20);
|
||||
}
|
||||
|
||||
pos.top += (options.offsetTop || 0);
|
||||
pos.left += (options.offsetLeft || 0);
|
||||
|
||||
// Do some boundary checking
|
||||
pos.top = Math.max(pos.top, 10);
|
||||
pos.left = Math.max(pos.left, 10);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(["scrollHelper"], function(scrollHelper) {
|
||||
var fn = on ? "on" : "off";
|
||||
scrollHelper.centerFocus[fn](elem, horiz)
|
||||
})
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function show(options) {
|
||||
var isFullscreen, dialogOptions = {
|
||||
removeOnClose: !0,
|
||||
|
||||
// items
|
||||
// positionTo
|
||||
// showCancel
|
||||
// title
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
enableHistory: options.enableHistory,
|
||||
scrollY: !1
|
||||
scrollY: false
|
||||
};
|
||||
layoutManager.tv ? (dialogOptions.size = "fullscreen", isFullscreen = !0, !0, dialogOptions.autoFocus = !0) : (dialogOptions.modal = !1, dialogOptions.entryAnimation = options.entryAnimation, dialogOptions.exitAnimation = options.exitAnimation, dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140, dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100, dialogOptions.autoFocus = !1);
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
isFullscreen ? dlg.classList.add("actionsheet-fullscreen") : dlg.classList.add("actionsheet-not-fullscreen"), dlg.classList.add("actionSheet"), options.dialogClass && dlg.classList.add(options.dialogClass);
|
||||
var html = "",
|
||||
scrollClassName = layoutManager.tv ? "scrollY smoothScrollY hiddenScrollY" : "scrollY",
|
||||
style = "";
|
||||
if (options.items.length > 20) {
|
||||
style += "min-width:" + (dom.getWindowSize().innerWidth >= 300 ? 240 : 200) + "px;"
|
||||
|
||||
var backButton = false;
|
||||
var isFullscreen;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
isFullscreen = true;
|
||||
backButton = true;
|
||||
dialogOptions.autoFocus = true;
|
||||
} else {
|
||||
|
||||
dialogOptions.modal = false;
|
||||
dialogOptions.entryAnimation = options.entryAnimation;
|
||||
dialogOptions.exitAnimation = options.exitAnimation;
|
||||
dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140;
|
||||
dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100;
|
||||
dialogOptions.autoFocus = false;
|
||||
}
|
||||
var i, length, option, itemIcon, renderIcon = !1,
|
||||
icons = [];
|
||||
for (i = 0, length = options.items.length; i < length; i++) option = options.items[i], itemIcon = option.icon || (option.selected ? "check" : null), itemIcon && (renderIcon = !0), icons.push(itemIcon || "");
|
||||
layoutManager.tv && (html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><i class="md-icon"></i></button>');
|
||||
var center = options.title && !renderIcon;
|
||||
center || layoutManager.tv ? html += '<div class="actionSheetContent actionSheetContent-centered">' : html += '<div class="actionSheetContent">', options.title && (html += '<h1 class="actionSheetTitle">', html += options.title, html += "</h1>"), options.text && (html += '<p class="actionSheetText">', html += options.text, html += "</p>");
|
||||
var scrollerClassName = "actionSheetScroller";
|
||||
layoutManager.tv && (scrollerClassName += " actionSheetScroller-tv focuscontainer-x focuscontainer-y"), html += '<div class="' + scrollerClassName + " " + scrollClassName + '" style="' + style + '">';
|
||||
var menuItemClass = "listItem listItem-button actionSheetMenuItem";
|
||||
for ((options.border || options.shaded) && (menuItemClass += " listItem-border"), options.menuItemClass && (menuItemClass += " " + options.menuItemClass), layoutManager.tv && (menuItemClass += " listItem-focusscale"), layoutManager.mobile && (menuItemClass += " actionsheet-xlargeFont"), i = 0, length = options.items.length; i < length; i++)
|
||||
if (option = options.items[i], option.divider) html += '<div class="actionsheetDivider"></div>';
|
||||
else {
|
||||
var autoFocus = option.selected && layoutManager.tv ? " autoFocus" : "",
|
||||
optionId = null == option.id || "" === option.id ? option.value : option.id;
|
||||
html += "<button" + autoFocus + ' is="emby-button" type="button" class="' + menuItemClass + '" data-id="' + optionId + '">', itemIcon = icons[i], itemIcon ? html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon">' + itemIcon + "</i>" : renderIcon && !center && (html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon" style="visibility:hidden;">check</i>'), html += '<div class="listItemBody actionsheetListItemBody">', html += '<div class="listItemBodyText actionSheetItemText">', html += option.name || option.textContent || option.innerText, html += "</div>", option.secondaryText && (html += '<div class="listItemBodyText secondary">', html += option.secondaryText, html += "</div>"), html += "</div>", option.asideText && (html += '<div class="listItemAside actionSheetItemAsideText">', html += option.asideText, html += "</div>"), html += "</button>"
|
||||
} options.showCancel && (html += '<div class="buttons">', html += '<button is="emby-button" type="button" class="btnCloseActionSheet">' + globalize.translate("sharedcomponents#ButtonCancel") + "</button>", html += "</div>"), html += "</div>", dlg.innerHTML = html, layoutManager.tv && centerFocus(dlg.querySelector(".actionSheetScroller"), !1, !0), dlg.querySelector(".btnCloseActionSheet") && dlg.querySelector(".btnCloseActionSheet").addEventListener("click", function() {
|
||||
dialogHelper.close(dlg)
|
||||
});
|
||||
var selectedId, timeout;
|
||||
return options.timeout && (timeout = setTimeout(function() {
|
||||
dialogHelper.close(dlg)
|
||||
}, options.timeout)), new Promise(function(resolve, reject) {
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
if (isFullscreen) {
|
||||
dlg.classList.add('actionsheet-fullscreen');
|
||||
} else {
|
||||
dlg.classList.add('actionsheet-not-fullscreen');
|
||||
}
|
||||
|
||||
dlg.classList.add('actionSheet');
|
||||
|
||||
if (options.dialogClass) {
|
||||
dlg.classList.add(options.dialogClass);
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
var scrollClassName = layoutManager.tv ? 'scrollY smoothScrollY hiddenScrollY' : 'scrollY';
|
||||
var style = '';
|
||||
|
||||
// Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation
|
||||
if (options.items.length > 20) {
|
||||
var minWidth = dom.getWindowSize().innerWidth >= 300 ? 240 : 200;
|
||||
style += "min-width:" + minWidth + "px;";
|
||||
}
|
||||
|
||||
var i, length, option;
|
||||
var renderIcon = false;
|
||||
var icons = [];
|
||||
var itemIcon;
|
||||
for (i = 0, length = options.items.length; i < length; i++) {
|
||||
|
||||
option = options.items[i];
|
||||
|
||||
itemIcon = option.icon || (option.selected ? 'check' : null);
|
||||
|
||||
if (itemIcon) {
|
||||
renderIcon = true;
|
||||
}
|
||||
icons.push(itemIcon || '');
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
}
|
||||
|
||||
// If any items have an icon, give them all an icon just to make sure they're all lined up evenly
|
||||
var center = options.title && (!renderIcon /*|| itemsWithIcons.length != options.items.length*/);
|
||||
|
||||
if (center || layoutManager.tv) {
|
||||
html += '<div class="actionSheetContent actionSheetContent-centered">';
|
||||
} else {
|
||||
html += '<div class="actionSheetContent">';
|
||||
}
|
||||
|
||||
if (options.title) {
|
||||
|
||||
html += '<h1 class="actionSheetTitle">';
|
||||
html += options.title;
|
||||
html += '</h1>';
|
||||
}
|
||||
if (options.text) {
|
||||
html += '<p class="actionSheetText">';
|
||||
html += options.text;
|
||||
html += '</p>';
|
||||
}
|
||||
|
||||
var scrollerClassName = 'actionSheetScroller';
|
||||
if (layoutManager.tv) {
|
||||
scrollerClassName += ' actionSheetScroller-tv focuscontainer-x focuscontainer-y';
|
||||
}
|
||||
html += '<div class="' + scrollerClassName + ' ' + scrollClassName + '" style="' + style + '">';
|
||||
|
||||
var menuItemClass = 'listItem listItem-button actionSheetMenuItem';
|
||||
|
||||
if (options.border || options.shaded) {
|
||||
menuItemClass += ' listItem-border';
|
||||
}
|
||||
|
||||
if (options.menuItemClass) {
|
||||
menuItemClass += ' ' + options.menuItemClass;
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
menuItemClass += ' listItem-focusscale';
|
||||
}
|
||||
|
||||
if (layoutManager.mobile) {
|
||||
menuItemClass += ' actionsheet-xlargeFont';
|
||||
}
|
||||
|
||||
for (i = 0, length = options.items.length; i < length; i++) {
|
||||
|
||||
option = options.items[i];
|
||||
|
||||
if (option.divider) {
|
||||
|
||||
html += '<div class="actionsheetDivider"></div>';
|
||||
continue;
|
||||
}
|
||||
|
||||
var autoFocus = option.selected && layoutManager.tv ? ' autoFocus' : '';
|
||||
|
||||
// Check for null in case int 0 was passed in
|
||||
var optionId = option.id == null || option.id === '' ? option.value : option.id;
|
||||
html += '<button' + autoFocus + ' is="emby-button" type="button" class="' + menuItemClass + '" data-id="' + optionId + '">';
|
||||
|
||||
itemIcon = icons[i];
|
||||
|
||||
if (itemIcon) {
|
||||
|
||||
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon">' + itemIcon + '</i>';
|
||||
}
|
||||
else if (renderIcon && !center) {
|
||||
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon" style="visibility:hidden;">check</i>';
|
||||
}
|
||||
|
||||
html += '<div class="listItemBody actionsheetListItemBody">';
|
||||
|
||||
html += '<div class="listItemBodyText actionSheetItemText">';
|
||||
html += (option.name || option.textContent || option.innerText);
|
||||
html += '</div>';
|
||||
|
||||
if (option.secondaryText) {
|
||||
html += '<div class="listItemBodyText secondary">';
|
||||
html += option.secondaryText;
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
if (option.asideText) {
|
||||
html += '<div class="listItemAside actionSheetItemAsideText">';
|
||||
html += option.asideText;
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</button>';
|
||||
}
|
||||
|
||||
if (options.showCancel) {
|
||||
html += '<div class="buttons">';
|
||||
html += '<button is="emby-button" type="button" class="btnCloseActionSheet">' + globalize.translate('sharedcomponents#ButtonCancel') + '</button>';
|
||||
html += '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
|
||||
}
|
||||
|
||||
var btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
if (btnCloseActionSheet) {
|
||||
dlg.querySelector('.btnCloseActionSheet').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
||||
// Seeing an issue in some non-chrome browsers where this is requiring a double click
|
||||
//var eventName = browser.firefox ? 'mousedown' : 'click';
|
||||
var selectedId;
|
||||
|
||||
var timeout;
|
||||
if (options.timeout) {
|
||||
timeout = setTimeout(function () {
|
||||
dialogHelper.close(dlg);
|
||||
}, options.timeout);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var isResolved;
|
||||
dlg.addEventListener("click", function(e) {
|
||||
var actionSheetMenuItem = dom.parentWithClass(e.target, "actionSheetMenuItem");
|
||||
actionSheetMenuItem && (selectedId = actionSheetMenuItem.getAttribute("data-id"), options.resolveOnClick && (options.resolveOnClick.indexOf ? -1 !== options.resolveOnClick.indexOf(selectedId) && (resolve(selectedId), isResolved = !0) : (resolve(selectedId), isResolved = !0)), dialogHelper.close(dlg))
|
||||
}), dlg.addEventListener("close", function() {
|
||||
layoutManager.tv && centerFocus(dlg.querySelector(".actionSheetScroller"), !1, !1), timeout && (clearTimeout(timeout), timeout = null), isResolved || (null != selectedId ? (options.callback && options.callback(selectedId), resolve(selectedId)) : reject())
|
||||
}), dialogHelper.open(dlg);
|
||||
var pos = options.positionTo && "fullscreen" !== dialogOptions.size ? getPosition(options, dlg) : null;
|
||||
pos && (dlg.style.position = "fixed", dlg.style.margin = 0, dlg.style.left = pos.left + "px", dlg.style.top = pos.top + "px")
|
||||
})
|
||||
|
||||
dlg.addEventListener('click', function (e) {
|
||||
|
||||
var actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
|
||||
|
||||
if (actionSheetMenuItem) {
|
||||
selectedId = actionSheetMenuItem.getAttribute('data-id');
|
||||
|
||||
if (options.resolveOnClick) {
|
||||
|
||||
if (options.resolveOnClick.indexOf) {
|
||||
|
||||
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
|
||||
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
}
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
}
|
||||
|
||||
if (!isResolved) {
|
||||
if (selectedId != null) {
|
||||
if (options.callback) {
|
||||
options.callback(selectedId);
|
||||
}
|
||||
|
||||
resolve(selectedId);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
var pos = options.positionTo && dialogOptions.size !== 'fullscreen' ? getPosition(options, dlg) : null;
|
||||
|
||||
if (pos) {
|
||||
dlg.style.position = 'fixed';
|
||||
dlg.style.margin = 0;
|
||||
dlg.style.left = pos.left + 'px';
|
||||
dlg.style.top = pos.top + 'px';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: show
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,18 +1,34 @@
|
||||
define(["dialog", "globalize"], function(dialog, globalize) {
|
||||
"use strict";
|
||||
return function(text, title) {
|
||||
define(['dialog', 'globalize'], function (dialog, globalize) {
|
||||
'use strict';
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
options = "string" == typeof text ? {
|
||||
title: title,
|
||||
text: text
|
||||
} : text;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
text: text
|
||||
};
|
||||
} else {
|
||||
options = text;
|
||||
}
|
||||
|
||||
var items = [];
|
||||
return items.push({
|
||||
name: globalize.translate("sharedcomponents#ButtonGotIt"),
|
||||
id: "ok",
|
||||
type: "submit"
|
||||
}), options.buttons = items, dialog(options).then(function(result) {
|
||||
return "ok" === result ? Promise.resolve() : Promise.reject()
|
||||
})
|
||||
}
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('sharedcomponents#ButtonGotIt'),
|
||||
id: 'ok',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
return dialog(options).then(function (result) {
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -1,14 +1,23 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.split(find).join(replace)
|
||||
}
|
||||
return function(options) {
|
||||
"string" == typeof options && (options = {
|
||||
text: options
|
||||
});
|
||||
var text = replaceAll(options.text || "", "<br/>", "\n");
|
||||
return alert(text), Promise.resolve()
|
||||
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
|
||||
return function (options) {
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
text: options
|
||||
};
|
||||
}
|
||||
|
||||
var text = replaceAll(options.text || '', '<br/>', '\n');
|
||||
|
||||
alert(text);
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
||||
@@ -1,59 +1,130 @@
|
||||
define(["dom", "focusManager"], function(dom, focusManager) {
|
||||
"use strict";
|
||||
define(['dom', 'focusManager'], function (dom, focusManager) {
|
||||
'use strict';
|
||||
|
||||
var inputDisplayElement;
|
||||
var currentDisplayText = '';
|
||||
var currentDisplayTextContainer;
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (!e.ctrlKey && !e.shiftKey && !e.altKey) {
|
||||
var key = e.key,
|
||||
chr = key ? alphanumeric(key) : null;
|
||||
chr && (chr = chr.toString().toUpperCase(), 1 === chr.length && (currentDisplayTextContainer = this.options.itemsContainer, onAlphanumericKeyPress(e, chr)))
|
||||
|
||||
if (e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
if (!!e.shiftKey) {
|
||||
return;
|
||||
}
|
||||
if (e.altKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = e.key;
|
||||
var chr = key ? alphanumeric(key) : null;
|
||||
|
||||
if (chr) {
|
||||
|
||||
chr = chr.toString().toUpperCase();
|
||||
|
||||
if (chr.length === 1) {
|
||||
currentDisplayTextContainer = this.options.itemsContainer;
|
||||
onAlphanumericKeyPress(e, chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function alphanumeric(value) {
|
||||
var letterNumber = /^[0-9a-zA-Z]+$/;
|
||||
return value.match(letterNumber)
|
||||
return value.match(letterNumber);
|
||||
}
|
||||
|
||||
function ensureInputDisplayElement() {
|
||||
inputDisplayElement || (inputDisplayElement = document.createElement("div"), inputDisplayElement.classList.add("alphanumeric-shortcut"), inputDisplayElement.classList.add("hide"), document.body.appendChild(inputDisplayElement))
|
||||
if (!inputDisplayElement) {
|
||||
inputDisplayElement = document.createElement('div');
|
||||
inputDisplayElement.classList.add('alphanumeric-shortcut');
|
||||
inputDisplayElement.classList.add('hide');
|
||||
|
||||
document.body.appendChild(inputDisplayElement);
|
||||
}
|
||||
}
|
||||
|
||||
var alpanumericShortcutTimeout;
|
||||
function clearAlphaNumericShortcutTimeout() {
|
||||
alpanumericShortcutTimeout && (clearTimeout(alpanumericShortcutTimeout), alpanumericShortcutTimeout = null)
|
||||
if (alpanumericShortcutTimeout) {
|
||||
clearTimeout(alpanumericShortcutTimeout);
|
||||
alpanumericShortcutTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function resetAlphaNumericShortcutTimeout() {
|
||||
clearAlphaNumericShortcutTimeout(), alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2e3)
|
||||
clearAlphaNumericShortcutTimeout();
|
||||
alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2000);
|
||||
}
|
||||
|
||||
function onAlphanumericKeyPress(e, chr) {
|
||||
currentDisplayText.length >= 3 || (ensureInputDisplayElement(), currentDisplayText += chr, inputDisplayElement.innerHTML = currentDisplayText, inputDisplayElement.classList.remove("hide"), resetAlphaNumericShortcutTimeout())
|
||||
if (currentDisplayText.length >= 3) {
|
||||
return;
|
||||
}
|
||||
ensureInputDisplayElement();
|
||||
currentDisplayText += chr;
|
||||
inputDisplayElement.innerHTML = currentDisplayText;
|
||||
inputDisplayElement.classList.remove('hide');
|
||||
resetAlphaNumericShortcutTimeout();
|
||||
}
|
||||
|
||||
function onAlphanumericShortcutTimeout() {
|
||||
var value = currentDisplayText,
|
||||
container = currentDisplayTextContainer;
|
||||
currentDisplayText = "", currentDisplayTextContainer = null, inputDisplayElement.innerHTML = "", inputDisplayElement.classList.add("hide"), clearAlphaNumericShortcutTimeout(), selectByShortcutValue(container, value)
|
||||
var value = currentDisplayText;
|
||||
var container = currentDisplayTextContainer;
|
||||
|
||||
currentDisplayText = '';
|
||||
currentDisplayTextContainer = null;
|
||||
inputDisplayElement.innerHTML = '';
|
||||
inputDisplayElement.classList.add('hide');
|
||||
clearAlphaNumericShortcutTimeout();
|
||||
selectByShortcutValue(container, value);
|
||||
}
|
||||
|
||||
function selectByShortcutValue(container, value) {
|
||||
|
||||
value = value.toUpperCase();
|
||||
|
||||
var focusElem;
|
||||
"#" === value && (focusElem = container.querySelector("*[data-prefix]")), focusElem || (focusElem = container.querySelector("*[data-prefix^='" + value + "']")), focusElem && focusManager.focus(focusElem)
|
||||
if (value === '#') {
|
||||
|
||||
focusElem = container.querySelector('*[data-prefix]');
|
||||
}
|
||||
|
||||
if (!focusElem) {
|
||||
focusElem = container.querySelector('*[data-prefix^=\'' + value + '\']');
|
||||
}
|
||||
|
||||
if (focusElem) {
|
||||
focusManager.focus(focusElem);
|
||||
}
|
||||
}
|
||||
|
||||
function AlphaNumericShortcuts(options) {
|
||||
|
||||
this.options = options;
|
||||
|
||||
var keyDownHandler = onKeyDown.bind(this);
|
||||
dom.addEventListener(window, "keydown", keyDownHandler, {
|
||||
passive: !0
|
||||
}), this.keyDownHandler = keyDownHandler
|
||||
|
||||
dom.addEventListener(window, 'keydown', keyDownHandler, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
this.keyDownHandler = keyDownHandler;
|
||||
}
|
||||
var inputDisplayElement, currentDisplayTextContainer, alpanumericShortcutTimeout, currentDisplayText = "";
|
||||
return AlphaNumericShortcuts.prototype.destroy = function() {
|
||||
|
||||
AlphaNumericShortcuts.prototype.destroy = function () {
|
||||
|
||||
var keyDownHandler = this.keyDownHandler;
|
||||
keyDownHandler && (dom.removeEventListener(window, "keydown", keyDownHandler, {
|
||||
passive: !0
|
||||
}), this.keyDownHandler = null), this.options = null
|
||||
}, AlphaNumericShortcuts
|
||||
|
||||
if (keyDownHandler) {
|
||||
dom.removeEventListener(window, 'keydown', keyDownHandler, {
|
||||
passive: true
|
||||
});
|
||||
this.keyDownHandler = null;
|
||||
}
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return AlphaNumericShortcuts;
|
||||
});
|
||||
@@ -1,127 +1,324 @@
|
||||
define(["focusManager", "layoutManager", "dom", "css!./style.css", "paper-icon-button-light", "material-icons"], function(focusManager, layoutManager, dom) {
|
||||
"use strict";
|
||||
define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-button-light', 'material-icons'], function (focusManager, layoutManager, dom) {
|
||||
'use strict';
|
||||
|
||||
var selectedButtonClass = 'alphaPickerButton-selected';
|
||||
|
||||
function focus() {
|
||||
var scope = this,
|
||||
selected = scope.querySelector("." + selectedButtonClass);
|
||||
selected ? focusManager.focus(selected) : focusManager.autoFocus(scope, !0)
|
||||
var scope = this;
|
||||
var selected = scope.querySelector('.' + selectedButtonClass);
|
||||
|
||||
if (selected) {
|
||||
focusManager.focus(selected);
|
||||
} else {
|
||||
focusManager.autoFocus(scope, true);
|
||||
}
|
||||
}
|
||||
|
||||
function getAlphaPickerButtonClassName(vertical) {
|
||||
var alphaPickerButtonClassName = "alphaPickerButton";
|
||||
return layoutManager.tv && (alphaPickerButtonClassName += " alphaPickerButton-tv"), vertical && (alphaPickerButtonClassName += " alphaPickerButton-vertical"), alphaPickerButtonClassName
|
||||
|
||||
var alphaPickerButtonClassName = 'alphaPickerButton';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
alphaPickerButtonClassName += ' alphaPickerButton-tv';
|
||||
}
|
||||
|
||||
if (vertical) {
|
||||
alphaPickerButtonClassName += ' alphaPickerButton-vertical';
|
||||
}
|
||||
|
||||
return alphaPickerButtonClassName;
|
||||
}
|
||||
|
||||
function getLetterButton(l, vertical) {
|
||||
return '<button data-value="' + l + '" class="' + getAlphaPickerButtonClassName(vertical) + '">' + l + "</button>"
|
||||
return '<button data-value="' + l + '" class="' + getAlphaPickerButtonClassName(vertical) + '">' + l + '</button>';
|
||||
}
|
||||
|
||||
function mapLetters(letters, vertical) {
|
||||
return letters.map(function(l) {
|
||||
return getLetterButton(l, vertical)
|
||||
})
|
||||
|
||||
return letters.map(function (l) {
|
||||
return getLetterButton(l, vertical);
|
||||
});
|
||||
}
|
||||
|
||||
function render(element, options) {
|
||||
element.classList.add("alphaPicker"), layoutManager.tv && element.classList.add("alphaPicker-tv");
|
||||
var vertical = element.classList.contains("alphaPicker-vertical");
|
||||
vertical || element.classList.add("focuscontainer-x");
|
||||
var letters, html = "",
|
||||
alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical),
|
||||
rowClassName = "alphaPickerRow";
|
||||
vertical && (rowClassName += " alphaPickerRow-vertical"), html += '<div class="' + rowClassName + '">', "keyboard" === options.mode ? html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon"></i></button>' : (letters = ["#"], html += mapLetters(letters, vertical).join("")), letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], html += mapLetters(letters, vertical).join(""), "keyboard" === options.mode ? (html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon"></i></button>', html += "</div>", letters = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], html += '<div class="' + rowClassName + '">', html += "<br/>", html += mapLetters(letters, vertical).join(""), html += "</div>") : html += "</div>", element.innerHTML = html, element.classList.add("focusable"), element.focus = focus
|
||||
|
||||
element.classList.add('alphaPicker');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
element.classList.add('alphaPicker-tv');
|
||||
}
|
||||
|
||||
var vertical = element.classList.contains('alphaPicker-vertical');
|
||||
|
||||
if (vertical) {
|
||||
|
||||
} else {
|
||||
element.classList.add('focuscontainer-x');
|
||||
}
|
||||
|
||||
var html = '';
|
||||
var letters;
|
||||
|
||||
var alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical);
|
||||
|
||||
var rowClassName = 'alphaPickerRow';
|
||||
|
||||
if (vertical) {
|
||||
rowClassName += ' alphaPickerRow-vertical';
|
||||
}
|
||||
|
||||
html += '<div class="' + rowClassName + '">';
|
||||
if (options.mode === 'keyboard') {
|
||||
// space_bar icon
|
||||
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon"></i></button>';
|
||||
} else {
|
||||
letters = ['#'];
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
}
|
||||
|
||||
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
|
||||
if (options.mode === 'keyboard') {
|
||||
// backspace icon
|
||||
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon"></i></button>';
|
||||
html += '</div>';
|
||||
|
||||
letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
html += '<div class="' + rowClassName + '">';
|
||||
html += '<br/>';
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
html += '</div>';
|
||||
} else {
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
element.innerHTML = html;
|
||||
|
||||
element.classList.add('focusable');
|
||||
element.focus = focus;
|
||||
}
|
||||
|
||||
function AlphaPicker(options) {
|
||||
|
||||
var self = this;
|
||||
this.options = options;
|
||||
|
||||
var element = options.element;
|
||||
var itemsContainer = options.itemsContainer;
|
||||
var itemClass = options.itemClass;
|
||||
|
||||
var itemFocusValue;
|
||||
var itemFocusTimeout;
|
||||
|
||||
function onItemFocusTimeout() {
|
||||
itemFocusTimeout = null, self.value(itemFocusValue)
|
||||
itemFocusTimeout = null;
|
||||
self.value(itemFocusValue);
|
||||
}
|
||||
|
||||
var alphaFocusedElement;
|
||||
var alphaFocusTimeout;
|
||||
|
||||
function onAlphaFocusTimeout() {
|
||||
if (alphaFocusTimeout = null, document.activeElement === alphaFocusedElement) {
|
||||
var value = alphaFocusedElement.getAttribute("data-value");
|
||||
self.value(value, !0)
|
||||
|
||||
alphaFocusTimeout = null;
|
||||
|
||||
if (document.activeElement === alphaFocusedElement) {
|
||||
var value = alphaFocusedElement.getAttribute('data-value');
|
||||
self.value(value, true);
|
||||
}
|
||||
}
|
||||
|
||||
function onAlphaPickerInKeyboardModeClick(e) {
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton");
|
||||
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
var value = alphaPickerButton.getAttribute("data-value");
|
||||
var value = alphaPickerButton.getAttribute('data-value');
|
||||
|
||||
element.dispatchEvent(new CustomEvent("alphavalueclicked", {
|
||||
cancelable: !1,
|
||||
cancelable: false,
|
||||
detail: {
|
||||
value: value
|
||||
}
|
||||
}))
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function onAlphaPickerClick(e) {
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton");
|
||||
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
var value = alphaPickerButton.getAttribute("data-value");
|
||||
(this._currentValue || "").toUpperCase() === value.toUpperCase() ? self.value(null, !0) : self.value(value, !0)
|
||||
var value = alphaPickerButton.getAttribute('data-value');
|
||||
if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
|
||||
self.value(null, true);
|
||||
} else {
|
||||
self.value(value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onAlphaPickerFocusIn(e) {
|
||||
alphaFocusTimeout && (clearTimeout(alphaFocusTimeout), alphaFocusTimeout = null);
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton");
|
||||
alphaPickerButton && (alphaFocusedElement = alphaPickerButton, alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600))
|
||||
|
||||
if (alphaFocusTimeout) {
|
||||
clearTimeout(alphaFocusTimeout);
|
||||
alphaFocusTimeout = null;
|
||||
}
|
||||
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
alphaFocusedElement = alphaPickerButton;
|
||||
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
|
||||
}
|
||||
}
|
||||
|
||||
function onItemsFocusIn(e) {
|
||||
|
||||
var item = dom.parentWithClass(e.target, itemClass);
|
||||
|
||||
if (item) {
|
||||
var prefix = item.getAttribute("data-prefix");
|
||||
prefix && prefix.length && (itemFocusValue = prefix[0], itemFocusTimeout && clearTimeout(itemFocusTimeout), itemFocusTimeout = setTimeout(onItemFocusTimeout, 100))
|
||||
var prefix = item.getAttribute('data-prefix');
|
||||
if (prefix && prefix.length) {
|
||||
|
||||
itemFocusValue = prefix[0];
|
||||
if (itemFocusTimeout) {
|
||||
clearTimeout(itemFocusTimeout);
|
||||
}
|
||||
itemFocusTimeout = setTimeout(onItemFocusTimeout, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
var self = this;
|
||||
this.options = options;
|
||||
var itemFocusValue, itemFocusTimeout, alphaFocusedElement, alphaFocusTimeout, element = options.element,
|
||||
itemsContainer = options.itemsContainer,
|
||||
itemClass = options.itemClass;
|
||||
self.enabled = function(enabled) {
|
||||
enabled ? (itemsContainer && itemsContainer.addEventListener("focus", onItemsFocusIn, !0), "keyboard" === options.mode && element.addEventListener("click", onAlphaPickerInKeyboardModeClick), "click" !== options.valueChangeEvent ? element.addEventListener("focus", onAlphaPickerFocusIn, !0) : element.addEventListener("click", onAlphaPickerClick.bind(this))) : (itemsContainer && itemsContainer.removeEventListener("focus", onItemsFocusIn, !0), element.removeEventListener("click", onAlphaPickerInKeyboardModeClick), element.removeEventListener("focus", onAlphaPickerFocusIn, !0), element.removeEventListener("click", onAlphaPickerClick.bind(this)))
|
||||
}, render(element, options), this.enabled(!0), this.visible(!0)
|
||||
}
|
||||
var selectedButtonClass = "alphaPickerButton-selected";
|
||||
return AlphaPicker.prototype.value = function(value, applyValue) {
|
||||
var btn, selected, element = this.options.element;
|
||||
if (void 0 !== value)
|
||||
if (null != value) {
|
||||
if (value = value.toUpperCase(), this._currentValue = value, "keyboard" !== this.options.mode) {
|
||||
selected = element.querySelector("." + selectedButtonClass);
|
||||
try {
|
||||
btn = element.querySelector(".alphaPickerButton[data-value='" + value + "']")
|
||||
} catch (err) {
|
||||
console.log("Error in querySelector: " + err)
|
||||
}
|
||||
btn && btn !== selected && btn.classList.add(selectedButtonClass), selected && selected !== btn && selected.classList.remove(selectedButtonClass)
|
||||
|
||||
self.enabled = function (enabled) {
|
||||
|
||||
if (enabled) {
|
||||
|
||||
if (itemsContainer) {
|
||||
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
} else this._currentValue = value, (selected = element.querySelector("." + selectedButtonClass)) && selected.classList.remove(selectedButtonClass);
|
||||
return applyValue && element.dispatchEvent(new CustomEvent("alphavaluechanged", {
|
||||
cancelable: !1,
|
||||
detail: {
|
||||
value: value
|
||||
|
||||
if (options.mode === 'keyboard') {
|
||||
element.addEventListener('click', onAlphaPickerInKeyboardModeClick);
|
||||
}
|
||||
|
||||
if (options.valueChangeEvent !== 'click') {
|
||||
element.addEventListener('focus', onAlphaPickerFocusIn, true);
|
||||
} else {
|
||||
element.addEventListener('click', onAlphaPickerClick.bind(this));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (itemsContainer) {
|
||||
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
|
||||
element.removeEventListener('click', onAlphaPickerInKeyboardModeClick);
|
||||
element.removeEventListener('focus', onAlphaPickerFocusIn, true);
|
||||
element.removeEventListener('click', onAlphaPickerClick.bind(this));
|
||||
}
|
||||
})), this._currentValue
|
||||
}, AlphaPicker.prototype.on = function(name, fn) {
|
||||
this.options.element.addEventListener(name, fn)
|
||||
}, AlphaPicker.prototype.off = function(name, fn) {
|
||||
this.options.element.removeEventListener(name, fn)
|
||||
}, AlphaPicker.prototype.visible = function(visible) {
|
||||
this.options.element.style.visibility = visible ? "visible" : "hidden"
|
||||
}, AlphaPicker.prototype.values = function() {
|
||||
for (var element = this.options.element, elems = element.querySelectorAll(".alphaPickerButton"), values = [], i = 0, length = elems.length; i < length; i++) values.push(elems[i].getAttribute("data-value"));
|
||||
return values
|
||||
}, AlphaPicker.prototype.focus = function() {
|
||||
};
|
||||
|
||||
render(element, options);
|
||||
|
||||
this.enabled(true);
|
||||
this.visible(true);
|
||||
}
|
||||
|
||||
AlphaPicker.prototype.value = function (value, applyValue) {
|
||||
|
||||
var element = this.options.element;
|
||||
focusManager.autoFocus(element, !0)
|
||||
}, AlphaPicker.prototype.destroy = function() {
|
||||
var btn, selected;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (value != null) {
|
||||
|
||||
value = value.toUpperCase();
|
||||
this._currentValue = value;
|
||||
|
||||
if (this.options.mode !== 'keyboard') {
|
||||
selected = element.querySelector('.' + selectedButtonClass);
|
||||
|
||||
try {
|
||||
btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']');
|
||||
} catch (err) {
|
||||
console.log('Error in querySelector: ' + err);
|
||||
}
|
||||
|
||||
if (btn && btn !== selected) {
|
||||
btn.classList.add(selectedButtonClass);
|
||||
}
|
||||
if (selected && selected !== btn) {
|
||||
selected.classList.remove(selectedButtonClass);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this._currentValue = value;
|
||||
|
||||
selected = element.querySelector('.' + selectedButtonClass);
|
||||
if (selected) {
|
||||
selected.classList.remove(selectedButtonClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (applyValue) {
|
||||
element.dispatchEvent(new CustomEvent("alphavaluechanged", {
|
||||
cancelable: false,
|
||||
detail: {
|
||||
value: value
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
return this._currentValue;
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.on = function (name, fn) {
|
||||
var element = this.options.element;
|
||||
this.enabled(!1), element.classList.remove("focuscontainer-x"), this.options = null
|
||||
}, AlphaPicker
|
||||
element.addEventListener(name, fn);
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.off = function (name, fn) {
|
||||
var element = this.options.element;
|
||||
element.removeEventListener(name, fn);
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.visible = function (visible) {
|
||||
|
||||
var element = this.options.element;
|
||||
element.style.visibility = visible ? 'visible' : 'hidden';
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.values = function () {
|
||||
|
||||
var element = this.options.element;
|
||||
var elems = element.querySelectorAll('.alphaPickerButton');
|
||||
var values = [];
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
values.push(elems[i].getAttribute('data-value'));
|
||||
|
||||
}
|
||||
|
||||
return values;
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.focus = function () {
|
||||
|
||||
var element = this.options.element;
|
||||
focusManager.autoFocus(element, true);
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.destroy = function () {
|
||||
|
||||
var element = this.options.element;
|
||||
this.enabled(false);
|
||||
element.classList.remove('focuscontainer-x');
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return AlphaPicker;
|
||||
});
|
||||
@@ -1,59 +1,35 @@
|
||||
.alphaPicker,
|
||||
.alphaPickerRow {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
-webkit-box-direction: normal
|
||||
}
|
||||
|
||||
.alphaPicker,
|
||||
.alphaPickerRow,
|
||||
.alphaPickerRow-vertical {
|
||||
-webkit-box-direction: normal
|
||||
}
|
||||
|
||||
.alphaPicker {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-align-self: center;
|
||||
align-self: center
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.alphaPicker-vertical {
|
||||
line-height: 1
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed {
|
||||
position: fixed;
|
||||
bottom: 5.5em;
|
||||
z-index: 999999
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
.alphaPickerRow {
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.alphaPickerRow-vertical {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.alphaPickerButton {
|
||||
border: 0 !important;
|
||||
cursor: pointer;
|
||||
outline: 0 !important;
|
||||
outline: none !important;
|
||||
vertical-align: middle;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
@@ -61,103 +37,103 @@
|
||||
margin: 0;
|
||||
padding: .1em .4em;
|
||||
width: auto;
|
||||
-webkit-border-radius: .1em;
|
||||
border-radius: .1em;
|
||||
font-weight: 400;
|
||||
-webkit-flex-shrink: 0;
|
||||
font-weight: normal;
|
||||
flex-shrink: 0;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
@media all and (max-height:50em) {
|
||||
@media all and (max-height: 50em) {
|
||||
|
||||
.alphaPicker-fixed {
|
||||
bottom: 5em
|
||||
bottom: 5em;
|
||||
}
|
||||
|
||||
.alphaPickerButton-vertical {
|
||||
padding-top: 1px !important;
|
||||
padding-bottom: 1px !important
|
||||
padding-bottom: 1px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height:49em) {
|
||||
@media all and (max-height: 49em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 94%
|
||||
font-size: 94%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height:44em) {
|
||||
@media all and (max-height: 44em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 90%
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.alphaPickerButton-vertical {
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height:37em) {
|
||||
@media all and (max-height: 37em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 82%
|
||||
font-size: 82%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height:32em) {
|
||||
@media all and (max-height: 32em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 74%
|
||||
font-size: 74%;
|
||||
}
|
||||
}
|
||||
|
||||
.alphaPicker-vertical.alphaPicker-tv {
|
||||
font-size: 86%
|
||||
font-size: 86%;
|
||||
}
|
||||
|
||||
.alphaPickerButton-tv.alphaPickerButton-vertical {
|
||||
padding: 0
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.alphaPickerButton-vertical {
|
||||
/* Assign a fixed width to ensure they have the same dimensions and avoid throwing off directional navigation */
|
||||
width: 1.5em;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
text-align: center
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.alphaPickerButtonIcon {
|
||||
font-size: 100% !important
|
||||
font-size: 100% !important;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed.alphaPicker-tv {
|
||||
bottom: 1%
|
||||
bottom: 1%;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-left {
|
||||
left: .4em
|
||||
left: .4em;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-right {
|
||||
right: .4em
|
||||
right: .4em;
|
||||
}
|
||||
|
||||
@media all and (min-width:62.5em) {
|
||||
@media all and (min-width: 62.5em) {
|
||||
|
||||
.alphaPicker-fixed-left {
|
||||
left: 1em
|
||||
left: 1em;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-right {
|
||||
right: 1em
|
||||
right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height:31.25em) {
|
||||
@media all and (max-height: 31.25em) {
|
||||
|
||||
.alphaPicker-fixed {
|
||||
display: none !important
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
.appfooter {
|
||||
.appfooter {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
bottom: 0;
|
||||
-webkit-transition: -webkit-transform 180ms linear;
|
||||
-o-transition: transform 180ms linear;
|
||||
transition: transform 180ms linear;
|
||||
contain: layout style
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
.appfooter.headroom--unpinned {
|
||||
-webkit-transform: translateY(100%) !important;
|
||||
transform: translateY(100%) !important
|
||||
}
|
||||
.appfooter.headroom--unpinned {
|
||||
transform: translateY(100%)!important;
|
||||
}
|
||||
@@ -1,20 +1,46 @@
|
||||
define(["browser", "css!./appfooter"], function(browser) {
|
||||
"use strict";
|
||||
define(['browser', 'css!./appfooter'], function (browser) {
|
||||
'use strict';
|
||||
|
||||
function render(options) {
|
||||
var elem = document.createElement("div");
|
||||
return elem.classList.add("appfooter"), browser.chrome || elem.classList.add("appfooter-blurred"), document.body.appendChild(elem), elem
|
||||
|
||||
var elem = document.createElement('div');
|
||||
|
||||
elem.classList.add('appfooter');
|
||||
|
||||
if (!browser.chrome) {
|
||||
// chrome does not display this properly
|
||||
elem.classList.add('appfooter-blurred');
|
||||
}
|
||||
|
||||
document.body.appendChild(elem);
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function appFooter(options) {
|
||||
|
||||
var self = this;
|
||||
self.element = render(options), self.add = function(elem) {
|
||||
self.element.appendChild(elem)
|
||||
}, self.insert = function(elem) {
|
||||
"string" == typeof elem ? self.element.insertAdjacentHTML("afterbegin", elem) : self.element.insertBefore(elem, self.element.firstChild)
|
||||
}
|
||||
|
||||
self.element = render(options);
|
||||
|
||||
self.add = function (elem) {
|
||||
self.element.appendChild(elem);
|
||||
};
|
||||
|
||||
self.insert = function (elem) {
|
||||
if (typeof elem === 'string') {
|
||||
self.element.insertAdjacentHTML('afterbegin', elem);
|
||||
} else {
|
||||
self.element.insertBefore(elem, self.element.firstChild);
|
||||
}
|
||||
};
|
||||
}
|
||||
return appFooter.prototype.destroy = function() {
|
||||
this.element = null
|
||||
}, appFooter
|
||||
|
||||
appFooter.prototype.destroy = function () {
|
||||
var self = this;
|
||||
|
||||
self.element = null;
|
||||
};
|
||||
|
||||
return appFooter;
|
||||
});
|
||||
@@ -1,39 +1,156 @@
|
||||
define(["appStorage", "events"], function(appStorage, events) {
|
||||
"use strict";
|
||||
define(['appStorage', 'events'], function (appStorage, events) {
|
||||
'use strict';
|
||||
|
||||
function getKey(name, userId) {
|
||||
return userId && (name = userId + "-" + name), name
|
||||
|
||||
if (userId) {
|
||||
name = userId + '-' + name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
function AppSettings() {}
|
||||
return AppSettings.prototype.enableAutoLogin = function(val) {
|
||||
return null != val && this.set("enableAutoLogin", val.toString()), "false" !== this.get("enableAutoLogin")
|
||||
}, AppSettings.prototype.enableAutomaticBitrateDetection = function(isInNetwork, mediaType, val) {
|
||||
var key = "enableautobitratebitrate-" + mediaType + "-" + isInNetwork;
|
||||
return null != val && (isInNetwork && "Audio" === mediaType && (val = !0), this.set(key, val.toString())), !(!isInNetwork || "Audio" !== mediaType) || "false" !== this.get(key)
|
||||
}, AppSettings.prototype.maxStreamingBitrate = function(isInNetwork, mediaType, val) {
|
||||
var key = "maxbitrate-" + mediaType + "-" + isInNetwork;
|
||||
return null != val && (isInNetwork && "Audio" === mediaType || this.set(key, val)), isInNetwork && "Audio" === mediaType ? 15e7 : parseInt(this.get(key) || "0") || 15e5
|
||||
}, AppSettings.prototype.maxStaticMusicBitrate = function(val) {
|
||||
void 0 !== val && this.set("maxStaticMusicBitrate", val);
|
||||
var defaultValue = 32e4;
|
||||
return parseInt(this.get("maxStaticMusicBitrate") || defaultValue.toString()) || defaultValue
|
||||
}, AppSettings.prototype.maxChromecastBitrate = function(val) {
|
||||
return null != val && this.set("chromecastBitrate1", val), val = this.get("chromecastBitrate1"), val ? parseInt(val) : null
|
||||
}, AppSettings.prototype.syncOnlyOnWifi = function(val) {
|
||||
return null != val && this.set("syncOnlyOnWifi", val.toString()), "false" !== this.get("syncOnlyOnWifi")
|
||||
}, AppSettings.prototype.syncPath = function(val) {
|
||||
return null != val && this.set("syncPath", val), this.get("syncPath")
|
||||
}, AppSettings.prototype.cameraUploadServers = function(val) {
|
||||
return null != val && this.set("cameraUploadServers", val.join(",")), val = this.get("cameraUploadServers"), val ? val.split(",") : []
|
||||
}, AppSettings.prototype.runAtStartup = function(val) {
|
||||
return null != val && this.set("runatstartup", val.toString()), "true" === this.get("runatstartup")
|
||||
}, AppSettings.prototype.set = function(name, value, userId) {
|
||||
function AppSettings() {
|
||||
|
||||
}
|
||||
|
||||
AppSettings.prototype.enableAutoLogin = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('enableAutoLogin', val.toString());
|
||||
}
|
||||
|
||||
return this.get('enableAutoLogin') !== 'false';
|
||||
};
|
||||
|
||||
AppSettings.prototype.enableAutomaticBitrateDetection = function (isInNetwork, mediaType, val) {
|
||||
|
||||
var key = 'enableautobitratebitrate-' + mediaType + '-' + isInNetwork;
|
||||
|
||||
if (val != null) {
|
||||
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
val = true;
|
||||
}
|
||||
|
||||
this.set(key, val.toString());
|
||||
}
|
||||
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
return true;
|
||||
} else {
|
||||
return this.get(key) !== 'false';
|
||||
}
|
||||
};
|
||||
|
||||
AppSettings.prototype.maxStreamingBitrate = function (isInNetwork, mediaType, val) {
|
||||
|
||||
var key = 'maxbitrate-' + mediaType + '-' + isInNetwork;
|
||||
|
||||
if (val != null) {
|
||||
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
// nothing to do, this is always a max value
|
||||
} else {
|
||||
this.set(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
// return a huge number so that it always direct plays
|
||||
return 150000000;
|
||||
} else {
|
||||
return parseInt(this.get(key) || '0') || 1500000;
|
||||
}
|
||||
};
|
||||
|
||||
AppSettings.prototype.maxStaticMusicBitrate = function (val) {
|
||||
|
||||
if (val !== undefined) {
|
||||
this.set('maxStaticMusicBitrate', val);
|
||||
}
|
||||
|
||||
var defaultValue = 320000;
|
||||
return parseInt(this.get('maxStaticMusicBitrate') || defaultValue.toString()) || defaultValue;
|
||||
};
|
||||
|
||||
AppSettings.prototype.maxChromecastBitrate = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('chromecastBitrate1', val);
|
||||
}
|
||||
|
||||
val = this.get('chromecastBitrate1');
|
||||
|
||||
return val ? parseInt(val) : null;
|
||||
};
|
||||
|
||||
AppSettings.prototype.syncOnlyOnWifi = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('syncOnlyOnWifi', val.toString());
|
||||
}
|
||||
|
||||
return this.get('syncOnlyOnWifi') !== 'false';
|
||||
};
|
||||
|
||||
AppSettings.prototype.syncPath = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('syncPath', val);
|
||||
}
|
||||
|
||||
return this.get('syncPath');
|
||||
};
|
||||
|
||||
AppSettings.prototype.cameraUploadServers = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('cameraUploadServers', val.join(','));
|
||||
}
|
||||
|
||||
val = this.get('cameraUploadServers');
|
||||
|
||||
if (val) {
|
||||
return val.split(',');
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
AppSettings.prototype.runAtStartup = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('runatstartup', val.toString());
|
||||
}
|
||||
|
||||
return this.get('runatstartup') === 'true';
|
||||
};
|
||||
|
||||
AppSettings.prototype.set = function (name, value, userId) {
|
||||
|
||||
var currentValue = this.get(name, userId);
|
||||
appStorage.setItem(getKey(name, userId), value), currentValue !== value && events.trigger(this, "change", [name])
|
||||
}, AppSettings.prototype.get = function(name, userId) {
|
||||
return appStorage.getItem(getKey(name, userId))
|
||||
}, AppSettings.prototype.enableSystemExternalPlayers = function(val) {
|
||||
return null != val && this.set("enableSystemExternalPlayers", val.toString()), "true" === this.get("enableSystemExternalPlayers")
|
||||
}, new AppSettings
|
||||
|
||||
appStorage.setItem(getKey(name, userId), value);
|
||||
|
||||
if (currentValue !== value) {
|
||||
events.trigger(this, 'change', [name]);
|
||||
}
|
||||
};
|
||||
|
||||
AppSettings.prototype.get = function (name, userId) {
|
||||
|
||||
return appStorage.getItem(getKey(name, userId));
|
||||
};
|
||||
|
||||
AppSettings.prototype.enableSystemExternalPlayers = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('enableSystemExternalPlayers', val.toString());
|
||||
}
|
||||
|
||||
return this.get('enableSystemExternalPlayers') === 'true';
|
||||
};
|
||||
|
||||
return new AppSettings();
|
||||
});
|
||||
@@ -1,150 +1,358 @@
|
||||
define(["browser", "connectionManager", "playbackManager", "dom", "css!./style"], function(browser, connectionManager, playbackManager, dom) {
|
||||
"use strict";
|
||||
define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./style'], function (browser, connectionManager, playbackManager, dom) {
|
||||
'use strict';
|
||||
|
||||
function enableAnimation(elem) {
|
||||
return !browser.slow
|
||||
|
||||
if (browser.slow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function enableRotation() {
|
||||
return !browser.tv && !browser.firefox
|
||||
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Causes high cpu usage
|
||||
if (browser.firefox) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function Backdrop() {}
|
||||
function Backdrop() {
|
||||
|
||||
}
|
||||
|
||||
Backdrop.prototype.load = function (url, parent, existingBackdropImage) {
|
||||
|
||||
var img = new Image();
|
||||
|
||||
var self = this;
|
||||
|
||||
img.onload = function () {
|
||||
|
||||
if (self.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
var backdropImage = document.createElement('div');
|
||||
backdropImage.classList.add('backdropImage');
|
||||
backdropImage.classList.add('displayingBackdropImage');
|
||||
backdropImage.style.backgroundImage = "url('" + url + "')";
|
||||
backdropImage.setAttribute('data-url', url);
|
||||
|
||||
backdropImage.classList.add('backdropImageFadeIn');
|
||||
parent.appendChild(backdropImage);
|
||||
|
||||
if (!enableAnimation(backdropImage)) {
|
||||
if (existingBackdropImage && existingBackdropImage.parentNode) {
|
||||
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
|
||||
}
|
||||
internalBackdrop(true);
|
||||
return;
|
||||
}
|
||||
|
||||
var onAnimationComplete = function () {
|
||||
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
if (backdropImage === self.currentAnimatingElement) {
|
||||
self.currentAnimatingElement = null;
|
||||
}
|
||||
if (existingBackdropImage && existingBackdropImage.parentNode) {
|
||||
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
|
||||
}
|
||||
};
|
||||
|
||||
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
|
||||
internalBackdrop(true);
|
||||
};
|
||||
img.src = url;
|
||||
};
|
||||
|
||||
Backdrop.prototype.cancelAnimation = function () {
|
||||
var elem = this.currentAnimatingElement;
|
||||
if (elem) {
|
||||
elem.classList.remove('backdropImageFadeIn');
|
||||
this.currentAnimatingElement = null;
|
||||
}
|
||||
};
|
||||
|
||||
Backdrop.prototype.destroy = function () {
|
||||
|
||||
this.isDestroyed = true;
|
||||
this.cancelAnimation();
|
||||
};
|
||||
|
||||
var backdropContainer;
|
||||
function getBackdropContainer() {
|
||||
return backdropContainer || (backdropContainer = document.querySelector(".backdropContainer")), backdropContainer || (backdropContainer = document.createElement("div"), backdropContainer.classList.add("backdropContainer"), document.body.insertBefore(backdropContainer, document.body.firstChild)), backdropContainer
|
||||
|
||||
if (!backdropContainer) {
|
||||
backdropContainer = document.querySelector('.backdropContainer');
|
||||
}
|
||||
|
||||
if (!backdropContainer) {
|
||||
backdropContainer = document.createElement('div');
|
||||
backdropContainer.classList.add('backdropContainer');
|
||||
document.body.insertBefore(backdropContainer, document.body.firstChild);
|
||||
}
|
||||
|
||||
return backdropContainer;
|
||||
}
|
||||
|
||||
function clearBackdrop(clearAll) {
|
||||
clearRotation(), currentLoadingBackdrop && (currentLoadingBackdrop.destroy(), currentLoadingBackdrop = null), getBackdropContainer().innerHTML = "", clearAll && (hasExternalBackdrop = !1), internalBackdrop(!1)
|
||||
}
|
||||
|
||||
function getBackgroundContainer() {
|
||||
return backgroundContainer || (backgroundContainer = document.querySelector(".backgroundContainer")), backgroundContainer
|
||||
}
|
||||
clearRotation();
|
||||
|
||||
function setBackgroundContainerBackgroundEnabled() {
|
||||
hasInternalBackdrop || hasExternalBackdrop ? getBackgroundContainer().classList.add("withBackdrop") : getBackgroundContainer().classList.remove("withBackdrop")
|
||||
}
|
||||
|
||||
function internalBackdrop(enabled) {
|
||||
hasInternalBackdrop = enabled, setBackgroundContainerBackgroundEnabled()
|
||||
}
|
||||
|
||||
function externalBackdrop(enabled) {
|
||||
hasExternalBackdrop = enabled, setBackgroundContainerBackgroundEnabled()
|
||||
}
|
||||
|
||||
function setBackdropImage(url) {
|
||||
currentLoadingBackdrop && (currentLoadingBackdrop.destroy(), currentLoadingBackdrop = null);
|
||||
var elem = getBackdropContainer(),
|
||||
existingBackdropImage = elem.querySelector(".displayingBackdropImage");
|
||||
if (existingBackdropImage && existingBackdropImage.getAttribute("data-url") === url) {
|
||||
if (existingBackdropImage.getAttribute("data-url") === url) return;
|
||||
existingBackdropImage.classList.remove("displayingBackdropImage")
|
||||
if (currentLoadingBackdrop) {
|
||||
currentLoadingBackdrop.destroy();
|
||||
currentLoadingBackdrop = null;
|
||||
}
|
||||
var instance = new Backdrop;
|
||||
instance.load(url, elem, existingBackdropImage), currentLoadingBackdrop = instance
|
||||
|
||||
var elem = getBackdropContainer();
|
||||
elem.innerHTML = '';
|
||||
|
||||
if (clearAll) {
|
||||
hasExternalBackdrop = false;
|
||||
}
|
||||
internalBackdrop(false);
|
||||
}
|
||||
|
||||
var backgroundContainer;
|
||||
function getBackgroundContainer() {
|
||||
if (!backgroundContainer) {
|
||||
backgroundContainer = document.querySelector('.backgroundContainer');
|
||||
}
|
||||
return backgroundContainer;
|
||||
}
|
||||
function setBackgroundContainerBackgroundEnabled() {
|
||||
|
||||
if (hasInternalBackdrop || hasExternalBackdrop) {
|
||||
getBackgroundContainer().classList.add('withBackdrop');
|
||||
} else {
|
||||
getBackgroundContainer().classList.remove('withBackdrop');
|
||||
}
|
||||
}
|
||||
|
||||
var hasInternalBackdrop;
|
||||
function internalBackdrop(enabled) {
|
||||
hasInternalBackdrop = enabled;
|
||||
setBackgroundContainerBackgroundEnabled();
|
||||
}
|
||||
|
||||
var hasExternalBackdrop;
|
||||
function externalBackdrop(enabled) {
|
||||
hasExternalBackdrop = enabled;
|
||||
setBackgroundContainerBackgroundEnabled();
|
||||
}
|
||||
|
||||
function getRandom(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
}
|
||||
|
||||
var currentLoadingBackdrop;
|
||||
function setBackdropImage(url) {
|
||||
|
||||
if (currentLoadingBackdrop) {
|
||||
currentLoadingBackdrop.destroy();
|
||||
currentLoadingBackdrop = null;
|
||||
}
|
||||
|
||||
var elem = getBackdropContainer();
|
||||
var existingBackdropImage = elem.querySelector('.displayingBackdropImage');
|
||||
|
||||
if (existingBackdropImage && existingBackdropImage.getAttribute('data-url') === url) {
|
||||
if (existingBackdropImage.getAttribute('data-url') === url) {
|
||||
return;
|
||||
}
|
||||
existingBackdropImage.classList.remove('displayingBackdropImage');
|
||||
}
|
||||
|
||||
var instance = new Backdrop();
|
||||
instance.load(url, elem, existingBackdropImage);
|
||||
currentLoadingBackdrop = instance;
|
||||
}
|
||||
|
||||
var standardWidths = [480, 720, 1280, 1440, 1920];
|
||||
function getBackdropMaxWidth() {
|
||||
|
||||
var width = dom.getWindowSize().innerWidth;
|
||||
if (-1 !== standardWidths.indexOf(width)) return width;
|
||||
return width = 100 * Math.floor(width / 100), Math.min(width, 1920)
|
||||
|
||||
if (standardWidths.indexOf(width) !== -1) {
|
||||
return width;
|
||||
}
|
||||
|
||||
var roundScreenTo = 100;
|
||||
width = Math.floor(width / roundScreenTo) * roundScreenTo;
|
||||
|
||||
return Math.min(width, 1920);
|
||||
}
|
||||
|
||||
function getItemImageUrls(item, imageOptions) {
|
||||
|
||||
imageOptions = imageOptions || {};
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
return item.BackdropImageTags && item.BackdropImageTags.length > 0 ? item.BackdropImageTags.map(function(imgTag, index) {
|
||||
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
|
||||
type: "Backdrop",
|
||||
tag: imgTag,
|
||||
maxWidth: getBackdropMaxWidth(),
|
||||
index: index
|
||||
}))
|
||||
}) : item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length ? item.ParentBackdropImageTags.map(function(imgTag, index) {
|
||||
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
|
||||
type: "Backdrop",
|
||||
tag: imgTag,
|
||||
maxWidth: getBackdropMaxWidth(),
|
||||
index: index
|
||||
}))
|
||||
}) : []
|
||||
|
||||
if (item.BackdropImageTags && item.BackdropImageTags.length > 0) {
|
||||
|
||||
return item.BackdropImageTags.map(function (imgTag, index) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
|
||||
type: "Backdrop",
|
||||
tag: imgTag,
|
||||
maxWidth: getBackdropMaxWidth(),
|
||||
index: index
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
|
||||
|
||||
return item.ParentBackdropImageTags.map(function (imgTag, index) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
|
||||
type: "Backdrop",
|
||||
tag: imgTag,
|
||||
maxWidth: getBackdropMaxWidth(),
|
||||
index: index
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function getImageUrls(items, imageOptions) {
|
||||
for (var list = [], onImg = function(img) {
|
||||
list.push(img)
|
||||
}, i = 0, length = items.length; i < length; i++) {
|
||||
getItemImageUrls(items[i], imageOptions).forEach(onImg)
|
||||
|
||||
var list = [];
|
||||
|
||||
var onImg = function (img) {
|
||||
list.push(img);
|
||||
};
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var itemImages = getItemImageUrls(items[i], imageOptions);
|
||||
|
||||
itemImages.forEach(onImg);
|
||||
}
|
||||
return list
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function arraysEqual(a, b) {
|
||||
if (a === b) return !0;
|
||||
if (null == a || null == b) return !1;
|
||||
if (a.length !== b.length) return !1;
|
||||
for (var i = 0; i < a.length; ++i)
|
||||
if (a[i] !== b[i]) return !1;
|
||||
return !0
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
if (a == null || b == null) {
|
||||
return false;
|
||||
}
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If you don't care about the order of the elements inside
|
||||
// the array, you should sort both arrays here.
|
||||
|
||||
for (var i = 0; i < a.length; ++i) {
|
||||
if (a[i] !== b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var rotationInterval;
|
||||
var currentRotatingImages = [];
|
||||
var currentRotationIndex = -1;
|
||||
function setBackdrops(items, imageOptions, enableImageRotation) {
|
||||
|
||||
var images = getImageUrls(items, imageOptions);
|
||||
images.length ? startRotation(images, enableImageRotation) : clearBackdrop()
|
||||
|
||||
if (images.length) {
|
||||
|
||||
startRotation(images, enableImageRotation);
|
||||
|
||||
} else {
|
||||
clearBackdrop();
|
||||
}
|
||||
}
|
||||
|
||||
function startRotation(images, enableImageRotation) {
|
||||
arraysEqual(images, currentRotatingImages) || (clearRotation(), currentRotatingImages = images, currentRotationIndex = -1, images.length > 1 && !1 !== enableImageRotation && enableRotation() && (rotationInterval = setInterval(onRotationInterval, 24e3)), onRotationInterval())
|
||||
|
||||
if (arraysEqual(images, currentRotatingImages)) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearRotation();
|
||||
|
||||
currentRotatingImages = images;
|
||||
currentRotationIndex = -1;
|
||||
|
||||
if (images.length > 1 && enableImageRotation !== false && enableRotation()) {
|
||||
rotationInterval = setInterval(onRotationInterval, 24000);
|
||||
}
|
||||
onRotationInterval();
|
||||
}
|
||||
|
||||
function onRotationInterval() {
|
||||
if (!playbackManager.isPlayingLocally(["Video"])) {
|
||||
var newIndex = currentRotationIndex + 1;
|
||||
newIndex >= currentRotatingImages.length && (newIndex = 0), currentRotationIndex = newIndex, setBackdropImage(currentRotatingImages[newIndex])
|
||||
|
||||
if (playbackManager.isPlayingLocally(['Video'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
var newIndex = currentRotationIndex + 1;
|
||||
if (newIndex >= currentRotatingImages.length) {
|
||||
newIndex = 0;
|
||||
}
|
||||
|
||||
currentRotationIndex = newIndex;
|
||||
setBackdropImage(currentRotatingImages[newIndex]);
|
||||
}
|
||||
|
||||
function clearRotation() {
|
||||
var interval = rotationInterval;
|
||||
interval && clearInterval(interval), rotationInterval = null, currentRotatingImages = [], currentRotationIndex = -1
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
rotationInterval = null;
|
||||
currentRotatingImages = [];
|
||||
currentRotationIndex = -1;
|
||||
}
|
||||
|
||||
function setBackdrop(url, imageOptions) {
|
||||
url && "string" != typeof url && (url = getImageUrls([url], imageOptions)[0]), url ? (clearRotation(), setBackdropImage(url)) : clearBackdrop()
|
||||
}
|
||||
Backdrop.prototype.load = function(url, parent, existingBackdropImage) {
|
||||
var img = new Image,
|
||||
self = this;
|
||||
img.onload = function() {
|
||||
if (!self.isDestroyed) {
|
||||
var backdropImage = document.createElement("div");
|
||||
if (backdropImage.classList.add("backdropImage"), backdropImage.classList.add("displayingBackdropImage"), backdropImage.style.backgroundImage = "url('" + url + "')", backdropImage.setAttribute("data-url", url), backdropImage.classList.add("backdropImageFadeIn"), parent.appendChild(backdropImage), !enableAnimation(backdropImage)) return existingBackdropImage && existingBackdropImage.parentNode && existingBackdropImage.parentNode.removeChild(existingBackdropImage), void internalBackdrop(!0);
|
||||
var onAnimationComplete = function() {
|
||||
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: !0
|
||||
}), backdropImage === self.currentAnimatingElement && (self.currentAnimatingElement = null), existingBackdropImage && existingBackdropImage.parentNode && existingBackdropImage.parentNode.removeChild(existingBackdropImage)
|
||||
};
|
||||
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: !0
|
||||
}), internalBackdrop(!0)
|
||||
|
||||
if (url) {
|
||||
if (typeof url !== 'string') {
|
||||
url = getImageUrls([url], imageOptions)[0];
|
||||
}
|
||||
}, img.src = url
|
||||
}, Backdrop.prototype.cancelAnimation = function() {
|
||||
var elem = this.currentAnimatingElement;
|
||||
elem && (elem.classList.remove("backdropImageFadeIn"), this.currentAnimatingElement = null)
|
||||
}, Backdrop.prototype.destroy = function() {
|
||||
this.isDestroyed = !0, this.cancelAnimation()
|
||||
};
|
||||
var backdropContainer, backgroundContainer, hasInternalBackdrop, hasExternalBackdrop, currentLoadingBackdrop, rotationInterval, standardWidths = [480, 720, 1280, 1440, 1920],
|
||||
currentRotatingImages = [],
|
||||
currentRotationIndex = -1;
|
||||
}
|
||||
|
||||
if (url) {
|
||||
clearRotation();
|
||||
|
||||
setBackdropImage(url);
|
||||
|
||||
} else {
|
||||
clearBackdrop();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
setBackdrops: setBackdrops,
|
||||
setBackdrop: setBackdrop,
|
||||
clear: clearBackdrop,
|
||||
externalBackdrop: externalBackdrop
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -1,41 +1,29 @@
|
||||
.backdropContainer {
|
||||
contain: layout style size
|
||||
contain: layout style size;
|
||||
}
|
||||
|
||||
.backdropImage {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-webkit-background-size: cover;
|
||||
background-size: cover;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
contain: layout style
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
.backdropImageFadeIn {
|
||||
-webkit-animation: backdrop-fadein .8s ease-in normal both;
|
||||
animation: backdrop-fadein .8s ease-in normal both
|
||||
}
|
||||
|
||||
@-webkit-keyframes backdrop-fadein {
|
||||
from {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1
|
||||
}
|
||||
animation: backdrop-fadein 800ms ease-in normal both;
|
||||
}
|
||||
|
||||
@keyframes backdrop-fadein {
|
||||
from {
|
||||
opacity: 0
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
367
src/bower_components/emby-webcomponents/browser.js
vendored
367
src/bower_components/emby-webcomponents/browser.js
vendored
@@ -1,69 +1,310 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function supportsCssAnimation(allowPrefix) {
|
||||
if (allowPrefix) {
|
||||
if (!0 === _supportsCssAnimationWithPrefix || !1 === _supportsCssAnimationWithPrefix) return _supportsCssAnimationWithPrefix
|
||||
} else if (!0 === _supportsCssAnimation || !1 === _supportsCssAnimation) return _supportsCssAnimation;
|
||||
var animation = !1,
|
||||
domPrefixes = ["Webkit", "O", "Moz"],
|
||||
pfx = "",
|
||||
elm = document.createElement("div");
|
||||
if (void 0 !== elm.style.animationName && (animation = !0), !1 === animation && allowPrefix)
|
||||
for (var i = 0; i < domPrefixes.length; i++)
|
||||
if (void 0 !== elm.style[domPrefixes[i] + "AnimationName"]) {
|
||||
pfx = domPrefixes[i], pfx + "Animation", "-" + pfx.toLowerCase() + "-", animation = !0;
|
||||
break
|
||||
} return allowPrefix ? _supportsCssAnimationWithPrefix = animation : _supportsCssAnimation = animation
|
||||
function isTv() {
|
||||
|
||||
// This is going to be really difficult to get right
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
if (userAgent.indexOf('tv') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userAgent.indexOf('samsungbrowser') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userAgent.indexOf('nintendo') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userAgent.indexOf('viera') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userAgent.indexOf('webos') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
var _supportsCssAnimation, _supportsCssAnimationWithPrefix, userAgent = navigator.userAgent,
|
||||
matched = function(ua) {
|
||||
ua = ua.toLowerCase();
|
||||
var match = /(edge)[ \/]([\w.]+)/.exec(ua) || /(opera)[ \/]([\w.]+)/.exec(ua) || /(opr)[ \/]([\w.]+)/.exec(ua) || /(chrome)[ \/]([\w.]+)/.exec(ua) || /(safari)[ \/]([\w.]+)/.exec(ua) || /(firefox)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [],
|
||||
versionMatch = /(version)[ \/]([\w.]+)/.exec(ua),
|
||||
platform_match = /(ipad)/.exec(ua) || /(iphone)/.exec(ua) || /(windows)/.exec(ua) || /(android)/.exec(ua) || [],
|
||||
browser = match[1] || "";
|
||||
"edge" === browser ? platform_match = [""] : -1 !== ua.indexOf("windows phone") || -1 !== ua.indexOf("iemobile") ? browser = "msie" : -1 !== ua.indexOf("like gecko") && -1 === ua.indexOf("webkit") && -1 === ua.indexOf("opera") && -1 === ua.indexOf("chrome") && -1 === ua.indexOf("safari") && (browser = "msie"), "opr" === browser && (browser = "opera");
|
||||
var version;
|
||||
versionMatch && versionMatch.length > 2 && (version = versionMatch[2]), version = version || match[2] || "0";
|
||||
var versionMajor = parseInt(version.split(".")[0]);
|
||||
return isNaN(versionMajor) && (versionMajor = 0), {
|
||||
browser: browser,
|
||||
version: version,
|
||||
platform: platform_match[0] || "",
|
||||
versionMajor: versionMajor
|
||||
|
||||
function isMobile(userAgent) {
|
||||
|
||||
var terms = [
|
||||
'mobi',
|
||||
'ipad',
|
||||
'iphone',
|
||||
'ipod',
|
||||
'silk',
|
||||
'gt-p1000',
|
||||
'nexus 7',
|
||||
'kindle fire',
|
||||
'opera mini'
|
||||
];
|
||||
|
||||
var lower = userAgent.toLowerCase();
|
||||
|
||||
for (var i = 0, length = terms.length; i < length; i++) {
|
||||
if (lower.indexOf(terms[i]) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}(userAgent),
|
||||
browser = {};
|
||||
return matched.browser && (browser[matched.browser] = !0, browser.version = matched.version, browser.versionMajor = matched.versionMajor), matched.platform && (browser[matched.platform] = !0), browser.chrome || browser.msie || browser.edge || browser.opera || -1 === userAgent.toLowerCase().indexOf("webkit") || (browser.safari = !0), -1 !== userAgent.toLowerCase().indexOf("playstation 4") && (browser.ps4 = !0, browser.tv = !0),
|
||||
function(userAgent) {
|
||||
for (var terms = ["mobi", "ipad", "iphone", "ipod", "silk", "gt-p1000", "nexus 7", "kindle fire", "opera mini"], lower = userAgent.toLowerCase(), i = 0, length = terms.length; i < length; i++)
|
||||
if (-1 !== lower.indexOf(terms[i])) return !0;
|
||||
return !1
|
||||
}(userAgent) && (browser.mobile = !0), browser.xboxOne = -1 !== userAgent.toLowerCase().indexOf("xbox"), browser.animate = "undefined" != typeof document && null != document.documentElement.animate, browser.tizen = -1 !== userAgent.toLowerCase().indexOf("tizen") || null != self.tizen, browser.web0s = -1 !== userAgent.toLowerCase().indexOf("Web0S".toLowerCase()), browser.edgeUwp = browser.edge && (-1 !== userAgent.toLowerCase().indexOf("msapphost") || -1 !== userAgent.toLowerCase().indexOf("webview")), browser.tizen || (browser.orsay = -1 !== userAgent.toLowerCase().indexOf("smarthub")), browser.edgeUwp && (browser.edge = !0), browser.tv = function() {
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
return -1 !== userAgent.indexOf("tv") || (-1 !== userAgent.indexOf("samsungbrowser") || (-1 !== userAgent.indexOf("nintendo") || (-1 !== userAgent.indexOf("viera") || -1 !== userAgent.indexOf("webos"))))
|
||||
}(), browser.operaTv = browser.tv && -1 !== userAgent.toLowerCase().indexOf("opr/"),
|
||||
function(prop, value) {
|
||||
if ("undefined" == typeof window) return !1;
|
||||
if (value = 2 === arguments.length ? value : "inherit", "CSS" in window && "supports" in window.CSS) return window.CSS.supports(prop, value);
|
||||
if ("supportsCSS" in window) return window.supportsCSS(prop, value);
|
||||
try {
|
||||
var camel = prop.replace(/-([a-z]|[0-9])/gi, function(all, letter) {
|
||||
return (letter + "").toUpperCase()
|
||||
}),
|
||||
support = camel in el.style,
|
||||
el = document.createElement("div");
|
||||
return el.style.cssText = prop + ":" + value, support && "" !== el.style[camel]
|
||||
} catch (err) {
|
||||
return !1
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isStyleSupported(prop, value) {
|
||||
|
||||
if (typeof window === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If no value is supplied, use "inherit"
|
||||
value = arguments.length === 2 ? value : 'inherit';
|
||||
// Try the native standard method first
|
||||
if ('CSS' in window && 'supports' in window.CSS) {
|
||||
return window.CSS.supports(prop, value);
|
||||
}
|
||||
// Check Opera's native method
|
||||
if ('supportsCSS' in window) {
|
||||
return window.supportsCSS(prop, value);
|
||||
}
|
||||
|
||||
// need try/catch because it's failing on tizen
|
||||
|
||||
try {
|
||||
// Convert to camel-case for DOM interactions
|
||||
var camel = prop.replace(/-([a-z]|[0-9])/ig, function (all, letter) {
|
||||
return (letter + '').toUpperCase();
|
||||
});
|
||||
// Check if the property is supported
|
||||
var support = (camel in el.style);
|
||||
// Create test element
|
||||
var el = document.createElement('div');
|
||||
// Assign the property and value to invoke
|
||||
// the CSS interpreter
|
||||
el.style.cssText = prop + ':' + value;
|
||||
// Ensure both the property and value are
|
||||
// supported and return
|
||||
return support && (el.style[camel] !== '');
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function hasKeyboard(browser) {
|
||||
|
||||
if (browser.touch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.ps4) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
// This is OK for now, but this won't always be true
|
||||
// Should we use this?
|
||||
// https://gist.github.com/wagonli/40d8a31bd0d6f0dd7a5d
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.tv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function iOSversion() {
|
||||
if (/iP(hone|od|ad)/.test(navigator.platform)) {
|
||||
// supports iOS 2.0 and later: <http://bit.ly/TJjs1V>
|
||||
var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
|
||||
return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)];
|
||||
}
|
||||
}
|
||||
|
||||
var _supportsCssAnimation;
|
||||
var _supportsCssAnimationWithPrefix;
|
||||
function supportsCssAnimation(allowPrefix) {
|
||||
|
||||
if (allowPrefix) {
|
||||
if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) {
|
||||
return _supportsCssAnimationWithPrefix;
|
||||
}
|
||||
}("display", "flex") || (browser.noFlex = !0), (browser.mobile || browser.tv) && (browser.slow = !0), "undefined" != typeof document && ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch) && (browser.touch = !0), browser.keyboard = function(browser) {
|
||||
return !!browser.touch || (!!browser.xboxOne || (!!browser.ps4 || (!!browser.edgeUwp || !!browser.tv)))
|
||||
}(browser), browser.supportsCssAnimation = supportsCssAnimation, browser.osx = -1 !== userAgent.toLowerCase().indexOf("os x"), browser.iOS = browser.ipad || browser.iphone || browser.ipod, browser.iOS && (browser.iOSVersion = function() {
|
||||
if (/iP(hone|od|ad)/.test(navigator.platform)) {
|
||||
var v = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
|
||||
return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)]
|
||||
} else {
|
||||
if (_supportsCssAnimation === true || _supportsCssAnimation === false) {
|
||||
return _supportsCssAnimation;
|
||||
}
|
||||
}(), browser.iOSVersion = browser.iOSVersion[0] + browser.iOSVersion[1] / 10), browser.chromecast = browser.chrome && -1 !== userAgent.toLowerCase().indexOf("crkey"), browser
|
||||
}
|
||||
|
||||
var animation = false,
|
||||
animationstring = 'animation',
|
||||
keyframeprefix = '',
|
||||
domPrefixes = ['Webkit', 'O', 'Moz'],
|
||||
pfx = '',
|
||||
elm = document.createElement('div');
|
||||
|
||||
if (elm.style.animationName !== undefined) { animation = true; }
|
||||
|
||||
if (animation === false && allowPrefix) {
|
||||
for (var i = 0; i < domPrefixes.length; i++) {
|
||||
if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
|
||||
pfx = domPrefixes[i];
|
||||
animationstring = pfx + 'Animation';
|
||||
keyframeprefix = '-' + pfx.toLowerCase() + '-';
|
||||
animation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowPrefix) {
|
||||
_supportsCssAnimationWithPrefix = animation;
|
||||
return _supportsCssAnimationWithPrefix;
|
||||
} else {
|
||||
_supportsCssAnimation = animation;
|
||||
return _supportsCssAnimation;
|
||||
}
|
||||
}
|
||||
|
||||
var uaMatch = function (ua) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(edge)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(opera)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(opr)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(safari)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(firefox)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(msie) ([\w.]+)/.exec(ua) ||
|
||||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
||||
[];
|
||||
|
||||
var versionMatch = /(version)[ \/]([\w.]+)/.exec(ua);
|
||||
|
||||
var platform_match = /(ipad)/.exec(ua) ||
|
||||
/(iphone)/.exec(ua) ||
|
||||
/(windows)/.exec(ua) ||
|
||||
/(android)/.exec(ua) ||
|
||||
[];
|
||||
|
||||
var browser = match[1] || "";
|
||||
|
||||
if (browser === "edge") {
|
||||
platform_match = [""];
|
||||
} else {
|
||||
if (ua.indexOf("windows phone") !== -1 || ua.indexOf("iemobile") !== -1) {
|
||||
|
||||
// http://www.neowin.net/news/ie11-fakes-user-agent-to-fool-gmail-in-windows-phone-81-gdr1-update
|
||||
browser = "msie";
|
||||
}
|
||||
else if (ua.indexOf("like gecko") !== -1 && ua.indexOf('webkit') === -1 && ua.indexOf('opera') === -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') === -1) {
|
||||
browser = "msie";
|
||||
}
|
||||
}
|
||||
|
||||
if (browser === 'opr') {
|
||||
browser = 'opera';
|
||||
}
|
||||
|
||||
var version;
|
||||
if (versionMatch && versionMatch.length > 2) {
|
||||
version = versionMatch[2];
|
||||
}
|
||||
|
||||
version = version || match[2] || "0";
|
||||
|
||||
var versionMajor = parseInt(version.split('.')[0]);
|
||||
|
||||
if (isNaN(versionMajor)) {
|
||||
versionMajor = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
browser: browser,
|
||||
version: version,
|
||||
platform: platform_match[0] || "",
|
||||
versionMajor: versionMajor
|
||||
};
|
||||
};
|
||||
|
||||
var userAgent = navigator.userAgent;
|
||||
|
||||
var matched = uaMatch(userAgent);
|
||||
var browser = {};
|
||||
|
||||
if (matched.browser) {
|
||||
browser[matched.browser] = true;
|
||||
browser.version = matched.version;
|
||||
browser.versionMajor = matched.versionMajor;
|
||||
}
|
||||
|
||||
if (matched.platform) {
|
||||
browser[matched.platform] = true;
|
||||
}
|
||||
|
||||
if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf("webkit") !== -1) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
if (userAgent.toLowerCase().indexOf("playstation 4") !== -1) {
|
||||
browser.ps4 = true;
|
||||
browser.tv = true;
|
||||
}
|
||||
|
||||
if (isMobile(userAgent)) {
|
||||
browser.mobile = true;
|
||||
}
|
||||
|
||||
browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1;
|
||||
browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null;
|
||||
browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || self.tizen != null;
|
||||
browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1;
|
||||
browser.edgeUwp = browser.edge && (userAgent.toLowerCase().indexOf('msapphost') !== -1 || userAgent.toLowerCase().indexOf('webview') !== -1);
|
||||
|
||||
if (!browser.tizen) {
|
||||
browser.orsay = userAgent.toLowerCase().indexOf('smarthub') !== -1;
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
browser.edge = true;
|
||||
}
|
||||
|
||||
browser.tv = isTv();
|
||||
browser.operaTv = browser.tv && userAgent.toLowerCase().indexOf('opr/') !== -1;
|
||||
|
||||
if (!isStyleSupported('display', 'flex')) {
|
||||
browser.noFlex = true;
|
||||
}
|
||||
|
||||
if (browser.mobile || browser.tv) {
|
||||
browser.slow = true;
|
||||
}
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
|
||||
browser.touch = true;
|
||||
}
|
||||
}
|
||||
|
||||
browser.keyboard = hasKeyboard(browser);
|
||||
browser.supportsCssAnimation = supportsCssAnimation;
|
||||
|
||||
browser.osx = userAgent.toLowerCase().indexOf('os x') !== -1;
|
||||
browser.iOS = browser.ipad || browser.iphone || browser.ipod;
|
||||
|
||||
if (browser.iOS) {
|
||||
browser.iOSVersion = iOSversion();
|
||||
browser.iOSVersion = browser.iOSVersion[0] + (browser.iOSVersion[1] / 10);
|
||||
}
|
||||
|
||||
browser.chromecast = browser.chrome && userAgent.toLowerCase().indexOf('crkey') !== -1;
|
||||
|
||||
return browser;
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,59 +1,140 @@
|
||||
define(["datetime", "imageLoader", "connectionManager", "layoutManager", "browser"], function(datetime, imageLoader, connectionManager, layoutManager, browser) {
|
||||
"use strict";
|
||||
define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) {
|
||||
'use strict';
|
||||
|
||||
function buildChapterCardsHtml(item, chapters, options) {
|
||||
var className = "card itemAction chapterCard";
|
||||
layoutManager.tv && (browser.animate || browser.edge) && (className += " card-focusscale");
|
||||
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [],
|
||||
videoStream = mediaStreams.filter(function(i) {
|
||||
return "Video" === i.Type
|
||||
})[0] || {},
|
||||
shape = options.backdropShape || "backdrop";
|
||||
videoStream.Width && videoStream.Height && videoStream.Width / videoStream.Height <= 1.2 && (shape = options.squareShape || "square"), className += " " + shape + "Card", (options.block || options.rows) && (className += " block");
|
||||
for (var html = "", itemsInRow = 0, apiClient = connectionManager.getApiClient(item.ServerId), i = 0, length = chapters.length; i < length; i++) {
|
||||
options.rows && 0 === itemsInRow && (html += '<div class="cardColumn">');
|
||||
html += buildChapterCard(item, apiClient, chapters[i], i, options, className, shape), itemsInRow++, options.rows && itemsInRow >= options.rows && (itemsInRow = 0, html += "</div>")
|
||||
|
||||
var className = 'card itemAction chapterCard';
|
||||
|
||||
if (layoutManager.tv && (browser.animate || browser.edge)) {
|
||||
className += ' card-focusscale';
|
||||
}
|
||||
return html
|
||||
|
||||
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [];
|
||||
var videoStream = mediaStreams.filter(function (i) {
|
||||
return i.Type === 'Video';
|
||||
})[0] || {};
|
||||
|
||||
var shape = (options.backdropShape || 'backdrop');
|
||||
|
||||
if (videoStream.Width && videoStream.Height) {
|
||||
|
||||
if ((videoStream.Width / videoStream.Height) <= 1.2) {
|
||||
shape = (options.squareShape || 'square');
|
||||
}
|
||||
}
|
||||
|
||||
className += ' ' + shape + 'Card';
|
||||
|
||||
if (options.block || options.rows) {
|
||||
className += ' block';
|
||||
}
|
||||
|
||||
var html = '';
|
||||
var itemsInRow = 0;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
for (var i = 0, length = chapters.length; i < length; i++) {
|
||||
|
||||
if (options.rows && itemsInRow === 0) {
|
||||
html += '<div class="cardColumn">';
|
||||
}
|
||||
|
||||
var chapter = chapters[i];
|
||||
|
||||
html += buildChapterCard(item, apiClient, chapter, i, options, className, shape);
|
||||
itemsInRow++;
|
||||
|
||||
if (options.rows && itemsInRow >= options.rows) {
|
||||
itemsInRow = 0;
|
||||
html += '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function getImgUrl(item, chapter, index, maxWidth, apiClient) {
|
||||
return chapter.ImageTag ? apiClient.getScaledImageUrl(item.Id, {
|
||||
maxWidth: maxWidth,
|
||||
tag: chapter.ImageTag,
|
||||
type: "Chapter",
|
||||
index: index
|
||||
}) : null
|
||||
|
||||
if (chapter.ImageTag) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.Id, {
|
||||
|
||||
maxWidth: maxWidth,
|
||||
tag: chapter.ImageTag,
|
||||
type: "Chapter",
|
||||
index: index
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildChapterCard(item, apiClient, chapter, index, options, className, shape) {
|
||||
var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient),
|
||||
cardImageContainerClass = "cardContent cardContent-shadow cardImageContainer chapterCardImageContainer";
|
||||
options.coverImage && (cardImageContainerClass += " coveredImage");
|
||||
var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"',
|
||||
cardImageContainer = imgUrl ? '<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">' : '<div class="' + cardImageContainerClass + '">';
|
||||
imgUrl || (cardImageContainer += '<i class="md-icon cardImageIcon">local_movies</i>');
|
||||
var nameHtml = "";
|
||||
nameHtml += '<div class="cardText">' + chapter.Name + "</div>", nameHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + "</div>";
|
||||
var cardBoxCssClass = "cardBox",
|
||||
cardScalableClass = "cardScalable";
|
||||
|
||||
var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient);
|
||||
|
||||
var cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
|
||||
if (options.coverImage) {
|
||||
cardImageContainerClass += ' coveredImage';
|
||||
}
|
||||
var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"';
|
||||
var cardImageContainer = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
|
||||
|
||||
if (!imgUrl) {
|
||||
cardImageContainer += '<i class="md-icon cardImageIcon">local_movies</i>';
|
||||
}
|
||||
|
||||
var nameHtml = '';
|
||||
nameHtml += '<div class="cardText">' + chapter.Name + '</div>';
|
||||
nameHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + '</div>';
|
||||
|
||||
var cardBoxCssClass = 'cardBox';
|
||||
var cardScalableClass = 'cardScalable';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
var enableFocusTransfrom = !browser.slow && !browser.edge;
|
||||
cardScalableClass += " card-focuscontent", enableFocusTransfrom ? cardBoxCssClass += " cardBox-focustransform cardBox-withfocuscontent" : (cardBoxCssClass += " cardBox-withfocuscontent-large", cardScalableClass += " card-focuscontent-large")
|
||||
|
||||
cardScalableClass += ' card-focuscontent';
|
||||
|
||||
if (enableFocusTransfrom) {
|
||||
cardBoxCssClass += ' cardBox-focustransform cardBox-withfocuscontent';
|
||||
} else {
|
||||
cardBoxCssClass += ' cardBox-withfocuscontent-large';
|
||||
cardScalableClass += ' card-focuscontent-large';
|
||||
}
|
||||
}
|
||||
return '<button type="button" class="' + className + '"' + dataAttributes + '><div class="' + cardBoxCssClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainer + '</div><div class="innerCardFooter">' + nameHtml + "</div></div></div></button>"
|
||||
|
||||
var html = '<button type="button" class="' + className + '"' + dataAttributes + '><div class="' + cardBoxCssClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainer + '</div><div class="innerCardFooter">' + nameHtml + '</div></div></div></button>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function buildChapterCards(item, chapters, options) {
|
||||
|
||||
if (options.parentContainer) {
|
||||
if (!document.body.contains(options.parentContainer)) return;
|
||||
if (!chapters.length) return void options.parentContainer.classList.add("hide");
|
||||
options.parentContainer.classList.remove("hide")
|
||||
// Abort if the container has been disposed
|
||||
if (!document.body.contains(options.parentContainer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chapters.length) {
|
||||
options.parentContainer.classList.remove('hide');
|
||||
} else {
|
||||
options.parentContainer.classList.add('hide');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var html = buildChapterCardsHtml(item, chapters, options);
|
||||
options.itemsContainer.innerHTML = html, imageLoader.lazyChildren(options.itemsContainer)
|
||||
|
||||
options.itemsContainer.innerHTML = html;
|
||||
|
||||
imageLoader.lazyChildren(options.itemsContainer);
|
||||
}
|
||||
|
||||
return {
|
||||
buildChapterCards: buildChapterCards
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -1,18 +1,22 @@
|
||||
define(["cardBuilder"], function(cardBuilder) {
|
||||
"use strict";
|
||||
define(['cardBuilder'], function (cardBuilder) {
|
||||
'use strict';
|
||||
|
||||
function buildPeopleCards(items, options) {
|
||||
|
||||
options = Object.assign(options || {}, {
|
||||
cardLayout: !1,
|
||||
centerText: !0,
|
||||
showTitle: !0,
|
||||
cardFooterAside: "none",
|
||||
showPersonRoleOrType: !0,
|
||||
cardCssClass: "personCard",
|
||||
defaultCardImageIcon: ""
|
||||
}), cardBuilder.buildCards(items, options)
|
||||
cardLayout: false,
|
||||
centerText: true,
|
||||
showTitle: true,
|
||||
cardFooterAside: 'none',
|
||||
showPersonRoleOrType: true,
|
||||
cardCssClass: 'personCard',
|
||||
defaultCardImageIcon: ''
|
||||
});
|
||||
cardBuilder.buildCards(items, options);
|
||||
}
|
||||
|
||||
return {
|
||||
buildPeopleCards: buildPeopleCards
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -1,10 +1,7 @@
|
||||
.card-round:focus>.cardBox-focustransform {
|
||||
-webkit-transform: scale(1.26, 1.26);
|
||||
transform: scale(1.26, 1.26)
|
||||
.card-round:focus > .cardBox-focustransform {
|
||||
transform: scale(1.26, 1.26);
|
||||
}
|
||||
|
||||
.cardImage-round,
|
||||
.cardImageContainer-round {
|
||||
-webkit-border-radius: 1000px;
|
||||
border-radius: 1000px
|
||||
}
|
||||
.cardImageContainer-round, .cardImage-round {
|
||||
border-radius: 1000px;
|
||||
}
|
||||
|
||||
@@ -1,67 +1,228 @@
|
||||
define(["events"], function(events) {
|
||||
"use strict";
|
||||
define(['events'], function (events) {
|
||||
'use strict';
|
||||
|
||||
// LinkParser
|
||||
//
|
||||
// https://github.com/ravisorg/LinkParser
|
||||
//
|
||||
// Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and
|
||||
// IPv6, unrecognised TLDs, and more.
|
||||
//
|
||||
// This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
// http://creativecommons.org/licenses/by-sa/4.0/
|
||||
(function () {
|
||||
|
||||
// Original URL regex from the Android android.text.util.Linkify function, found here:
|
||||
// http://stackoverflow.com/a/19696443
|
||||
//
|
||||
// However there were problems with it, most probably related to the fact it was
|
||||
// written in 2007, and it's been highly modified.
|
||||
//
|
||||
// 1) I didn't like the fact that it was tied to specific TLDs, since new ones
|
||||
// are being added all the time it wouldn't be reasonable to expect developer to
|
||||
// be continually updating their regular expressions.
|
||||
//
|
||||
// 2) It didn't allow unicode characters in the domains which are now allowed in
|
||||
// many languages, (including some IDN TLDs). Again these are constantly being
|
||||
// added to and it doesn't seem reasonable to hard-code them. Note this ended up
|
||||
// not being possible in standard JS due to the way it handles multibyte strings.
|
||||
// It is possible using XRegExp, however a big performance hit results. Disabled
|
||||
// for now.
|
||||
//
|
||||
// 3) It didn't allow for IPv6 hostnames
|
||||
// IPv6 regex from http://stackoverflow.com/a/17871737
|
||||
//
|
||||
// 4) It was very poorly commented
|
||||
//
|
||||
// 5) It wasn't as smart as it could have been about what should be part of a
|
||||
// URL and what should be part of human language.
|
||||
|
||||
var protocols = "(?:(?:http|https|rtsp|ftp):\\/\\/)";
|
||||
var credentials = "(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}" // username (1-64 normal or url escaped characters)
|
||||
+ "(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?" // followed by optional password (: + 1-25 normal or url escaped characters)
|
||||
+ "\\@)";
|
||||
|
||||
// IPv6 Regex http://forums.intermapper.com/viewtopic.php?t=452
|
||||
// by Dartware, LLC is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License
|
||||
// http://intermapper.com/
|
||||
var ipv6 = "("
|
||||
+ "(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))"
|
||||
+ "|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))"
|
||||
+ "|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))"
|
||||
+ "|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
|
||||
+ "|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
|
||||
+ "|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
|
||||
+ "|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
|
||||
+ "|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
|
||||
+ ")(%.+)?";
|
||||
|
||||
var ipv4 = "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\."
|
||||
+ "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\."
|
||||
+ "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\."
|
||||
+ "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])";
|
||||
|
||||
// This would have been a lot cleaner if JS RegExp supported conditionals...
|
||||
var linkRegExpString =
|
||||
|
||||
// begin match for protocol / username / password / host
|
||||
"(?:"
|
||||
|
||||
// ============================
|
||||
// If we have a recognized protocol at the beginning of the URL, we're
|
||||
// more relaxed about what we accept, because we assume the user wants
|
||||
// this to be a URL, and we're not accidentally matching human language
|
||||
+ protocols + "?"
|
||||
|
||||
// optional username:password@
|
||||
+ credentials + "?"
|
||||
|
||||
// IP address (both v4 and v6)
|
||||
+ "(?:"
|
||||
|
||||
// IPv6
|
||||
+ ipv6
|
||||
|
||||
// IPv4
|
||||
+ "|" + ipv4
|
||||
|
||||
+ ")"
|
||||
|
||||
// end match for protocol / username / password / host
|
||||
+ ")"
|
||||
|
||||
// optional port number
|
||||
+ "(?:\\:\\d{1,5})?"
|
||||
|
||||
// plus optional path and query params (no unicode allowed here?)
|
||||
+ "(?:"
|
||||
+ "\\/(?:"
|
||||
// some characters we'll accept because it's unlikely human language
|
||||
// would use them after a URL unless they were part of the url
|
||||
+ "(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])"
|
||||
+ "|(?:\\%[a-f0-9]{2})"
|
||||
// some characters are much more likely to be used AFTER a url and
|
||||
// were not intended to be included in the url itself. Mostly end
|
||||
// of sentence type things. It's also likely that the URL would
|
||||
// still work if any of these characters were missing from the end
|
||||
// because we parsed it incorrectly. For these characters to be accepted
|
||||
// they must be followed by another character that we're reasonably
|
||||
// sure is part of the url
|
||||
+ "|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})))"
|
||||
+ ")*"
|
||||
+ "|\\b|\$"
|
||||
+ ")";
|
||||
|
||||
// regex = XRegExp(regex,'gi');
|
||||
var linkRegExp = RegExp(linkRegExpString, 'gi');
|
||||
|
||||
var protocolRegExp = RegExp('^' + protocols, 'i');
|
||||
|
||||
// if url doesn't begin with a known protocol, add http by default
|
||||
function ensureProtocol(url) {
|
||||
if (!url.match(protocolRegExp)) {
|
||||
url = "http://" + url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
// look for links in the text
|
||||
var LinkParser = {
|
||||
parse: function (text) {
|
||||
var links = [];
|
||||
var match;
|
||||
|
||||
while (match = linkRegExp.exec(text)) {
|
||||
// console.log(matches);
|
||||
var txt = match[0];
|
||||
var pos = match.index;
|
||||
var len = txt.length;
|
||||
var url = ensureProtocol(text);
|
||||
links.push({ 'pos': pos, 'text': txt, 'len': len, 'url': url });
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
window.LinkParser = LinkParser;
|
||||
})();
|
||||
|
||||
var cache = {};
|
||||
|
||||
function isValidIpAddress(address) {
|
||||
return 1 == LinkParser.parse(address).length
|
||||
|
||||
var links = LinkParser.parse(address);
|
||||
|
||||
return links.length == 1;
|
||||
}
|
||||
|
||||
function isLocalIpAddress(address) {
|
||||
return address = address.toLowerCase(), -1 !== address.indexOf("127.0.0.1") || -1 !== address.indexOf("localhost")
|
||||
|
||||
address = address.toLowerCase();
|
||||
|
||||
if (address.indexOf('127.0.0.1') !== -1) {
|
||||
return true;
|
||||
}
|
||||
if (address.indexOf('localhost') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getServerAddress(apiClient) {
|
||||
|
||||
var serverAddress = apiClient.serverAddress();
|
||||
if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) return Promise.resolve(serverAddress);
|
||||
|
||||
if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) {
|
||||
return Promise.resolve(serverAddress);
|
||||
}
|
||||
|
||||
var cachedValue = getCachedValue(serverAddress);
|
||||
return cachedValue ? Promise.resolve(cachedValue) : apiClient.getEndpointInfo().then(function(endpoint) {
|
||||
return endpoint.IsInNetwork ? apiClient.getPublicSystemInfo().then(function(info) {
|
||||
return addToCache(serverAddress, info.LocalAddress), info.LocalAddress
|
||||
}) : (addToCache(serverAddress, serverAddress), serverAddress)
|
||||
})
|
||||
if (cachedValue) {
|
||||
return Promise.resolve(cachedValue);
|
||||
}
|
||||
|
||||
return apiClient.getEndpointInfo().then(function (endpoint) {
|
||||
if (endpoint.IsInNetwork) {
|
||||
return apiClient.getPublicSystemInfo().then(function (info) {
|
||||
addToCache(serverAddress, info.LocalAddress);
|
||||
return info.LocalAddress;
|
||||
});
|
||||
} else {
|
||||
addToCache(serverAddress, serverAddress);
|
||||
return serverAddress;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearCache() {
|
||||
cache = {}
|
||||
cache = {};
|
||||
}
|
||||
|
||||
function addToCache(key, value) {
|
||||
cache[key] = {
|
||||
value: value,
|
||||
time: (new Date).getTime()
|
||||
}
|
||||
time: new Date().getTime()
|
||||
};
|
||||
}
|
||||
|
||||
function getCachedValue(key) {
|
||||
|
||||
var obj = cache[key];
|
||||
return obj && (new Date).getTime() - obj.time < 18e4 ? obj.value : null
|
||||
}! function() {
|
||||
function ensureProtocol(url) {
|
||||
return url.match(protocolRegExp) || (url = "http://" + url), url
|
||||
|
||||
if (obj && (new Date().getTime() - obj.time) < 180000) {
|
||||
return obj.value;
|
||||
}
|
||||
var protocols = "(?:(?:http|https|rtsp|ftp):\\/\\/)",
|
||||
linkRegExp = RegExp("(?:(?:(?:http|https|rtsp|ftp):\\/\\/)?(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?\\@)?(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?|(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\\:\\d{1,5})?(?:\\/(?:(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2}))))*|\\b|$)", "gi"),
|
||||
protocolRegExp = RegExp("^" + protocols, "i"),
|
||||
LinkParser = {
|
||||
parse: function(text) {
|
||||
for (var match, links = []; match = linkRegExp.exec(text);) {
|
||||
var txt = match[0],
|
||||
pos = match.index,
|
||||
len = txt.length,
|
||||
url = ensureProtocol(text);
|
||||
links.push({
|
||||
pos: pos,
|
||||
text: txt,
|
||||
len: len,
|
||||
url: url
|
||||
})
|
||||
}
|
||||
return links
|
||||
}
|
||||
};
|
||||
window.LinkParser = LinkParser
|
||||
}();
|
||||
var cache = {};
|
||||
return events.on(ConnectionManager, "localusersignedin", clearCache), events.on(ConnectionManager, "localusersignedout", clearCache), {
|
||||
getServerAddress: getServerAddress
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
events.on(ConnectionManager, 'localusersignedin', clearCache);
|
||||
events.on(ConnectionManager, 'localusersignedout', clearCache);
|
||||
|
||||
return {
|
||||
getServerAddress: getServerAddress
|
||||
};
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
||||
.clearButton {
|
||||
background: 0 0;
|
||||
background: transparent;
|
||||
border: 0 !important;
|
||||
padding: 0 !important;
|
||||
cursor: pointer;
|
||||
outline: 0 !important;
|
||||
outline: none !important;
|
||||
color: inherit;
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
font-family: inherit;
|
||||
font-size: inherit
|
||||
font-size: inherit;
|
||||
}
|
||||
@@ -1,119 +1,287 @@
|
||||
define(["dialogHelper", "loading", "apphost", "layoutManager", "connectionManager", "appRouter", "globalize", "emby-checkbox", "emby-input", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button", "emby-linkbutton", "flexStyles"], function(dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) {
|
||||
"use strict";
|
||||
define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) {
|
||||
'use strict';
|
||||
|
||||
var currentServerId;
|
||||
|
||||
function parentWithClass(elem, className) {
|
||||
for (; !elem.classList || !elem.classList.contains(className);)
|
||||
if (!(elem = elem.parentNode)) return null;
|
||||
return elem
|
||||
|
||||
while (!elem.classList || !elem.classList.contains(className)) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
loading.show();
|
||||
var panel = parentWithClass(this, "dialog"),
|
||||
collectionId = panel.querySelector("#selectCollectionToAddTo").value,
|
||||
apiClient = connectionManager.getApiClient(currentServerId);
|
||||
return collectionId ? addToCollection(apiClient, panel, collectionId) : createCollection(apiClient, panel), e.preventDefault(), !1
|
||||
|
||||
var panel = parentWithClass(this, 'dialog');
|
||||
|
||||
var collectionId = panel.querySelector('#selectCollectionToAddTo').value;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
|
||||
if (collectionId) {
|
||||
addToCollection(apiClient, panel, collectionId);
|
||||
} else {
|
||||
createCollection(apiClient, panel);
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function createCollection(apiClient, dlg) {
|
||||
|
||||
var url = apiClient.getUrl("Collections", {
|
||||
Name: dlg.querySelector("#txtNewCollectionName").value,
|
||||
IsLocked: !dlg.querySelector("#chkEnableInternetMetadata").checked,
|
||||
Ids: dlg.querySelector(".fldSelectedItemIds").value || ""
|
||||
|
||||
Name: dlg.querySelector('#txtNewCollectionName').value,
|
||||
IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked,
|
||||
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
|
||||
});
|
||||
|
||||
apiClient.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
dataType: "json"
|
||||
}).then(function(result) {
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
loading.hide();
|
||||
|
||||
var id = result.Id;
|
||||
dlg.submitted = !0, dialogHelper.close(dlg), redirectToCollection(apiClient, id)
|
||||
})
|
||||
|
||||
dlg.submitted = true;
|
||||
dialogHelper.close(dlg);
|
||||
redirectToCollection(apiClient, id);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function redirectToCollection(apiClient, id) {
|
||||
appRouter.showItem(id, apiClient.serverId())
|
||||
|
||||
appRouter.showItem(id, apiClient.serverId());
|
||||
}
|
||||
|
||||
function addToCollection(apiClient, dlg, id) {
|
||||
|
||||
var url = apiClient.getUrl("Collections/" + id + "/Items", {
|
||||
Ids: dlg.querySelector(".fldSelectedItemIds").value || ""
|
||||
|
||||
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
|
||||
});
|
||||
|
||||
apiClient.ajax({
|
||||
type: "POST",
|
||||
url: url
|
||||
}).then(function() {
|
||||
loading.hide(), dlg.submitted = !0, dialogHelper.close(dlg), require(["toast"], function(toast) {
|
||||
toast(globalize.translate("sharedcomponents#MessageItemsAdded"))
|
||||
})
|
||||
})
|
||||
|
||||
}).then(function () {
|
||||
|
||||
loading.hide();
|
||||
|
||||
dlg.submitted = true;
|
||||
dialogHelper.close(dlg);
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('sharedcomponents#MessageItemsAdded'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function triggerChange(select) {
|
||||
select.dispatchEvent(new CustomEvent("change", {}))
|
||||
select.dispatchEvent(new CustomEvent('change', {}));
|
||||
}
|
||||
|
||||
function populateCollections(panel) {
|
||||
|
||||
loading.show();
|
||||
var select = panel.querySelector("#selectCollectionToAddTo");
|
||||
panel.querySelector(".newCollectionInfo").classList.add("hide");
|
||||
|
||||
var select = panel.querySelector('#selectCollectionToAddTo');
|
||||
|
||||
panel.querySelector('.newCollectionInfo').classList.add('hide');
|
||||
|
||||
var options = {
|
||||
Recursive: !0,
|
||||
IncludeItemTypes: "BoxSet",
|
||||
SortBy: "SortName",
|
||||
EnableTotalRecordCount: !1
|
||||
},
|
||||
apiClient = connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function(result) {
|
||||
var html = "";
|
||||
html += '<option value="">' + globalize.translate("sharedcomponents#OptionNew") + "</option>", html += result.Items.map(function(i) {
|
||||
return '<option value="' + i.Id + '">' + i.Name + "</option>"
|
||||
}), select.innerHTML = html, select.value = "", triggerChange(select), loading.hide()
|
||||
})
|
||||
|
||||
Recursive: true,
|
||||
IncludeItemTypes: "BoxSet",
|
||||
SortBy: "SortName",
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) {
|
||||
|
||||
var html = '';
|
||||
|
||||
html += '<option value="">' + globalize.translate('sharedcomponents#OptionNew') + '</option>';
|
||||
|
||||
html += result.Items.map(function (i) {
|
||||
|
||||
return '<option value="' + i.Id + '">' + i.Name + '</option>';
|
||||
});
|
||||
|
||||
select.innerHTML = html;
|
||||
select.value = '';
|
||||
triggerChange(select);
|
||||
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function getEditorHtml() {
|
||||
var html = "";
|
||||
return html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">', html += '<div class="dialogContentInner dialog-content-centered">', html += '<form class="newCollectionForm" style="margin:auto;">', html += "<div>", html += globalize.translate("sharedcomponents#NewCollectionHelp"), html += "</div>", html += '<div class="fldSelectCollection">', html += "<br/>", html += "<br/>", html += '<div class="selectContainer">', html += '<select is="emby-select" label="' + globalize.translate("sharedcomponents#LabelCollection") + '" id="selectCollectionToAddTo" autofocus></select>', html += "</div>", html += "</div>", html += '<div class="newCollectionInfo">', html += '<div class="inputContainer">', html += '<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="' + globalize.translate("sharedcomponents#LabelName") + '" />', html += '<div class="fieldDescription">' + globalize.translate("sharedcomponents#NewCollectionNameExample") + "</div>", html += "</div>", html += '<label class="checkboxContainer">', html += '<input is="emby-checkbox" type="checkbox" id="chkEnableInternetMetadata" />', html += "<span>" + globalize.translate("sharedcomponents#SearchForCollectionInternetMetadata") + "</span>", html += "</label>", html += "</div>", html += '<div class="formDialogFooter">', html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate("sharedcomponents#ButtonOk") + "</button>", html += "</div>", html += '<input type="hidden" class="fldSelectedItemIds" />', html += "</form>", html += "</div>", html += "</div>"
|
||||
|
||||
var html = '';
|
||||
|
||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
html += '<form class="newCollectionForm" style="margin:auto;">';
|
||||
|
||||
html += '<div>';
|
||||
html += globalize.translate('sharedcomponents#NewCollectionHelp');
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="fldSelectCollection">';
|
||||
html += '<br/>';
|
||||
html += '<br/>';
|
||||
html += '<div class="selectContainer">';
|
||||
html += '<select is="emby-select" label="' + globalize.translate('sharedcomponents#LabelCollection') + '" id="selectCollectionToAddTo" autofocus></select>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="newCollectionInfo">';
|
||||
|
||||
html += '<div class="inputContainer">';
|
||||
html += '<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="' + globalize.translate('sharedcomponents#LabelName') + '" />';
|
||||
html += '<div class="fieldDescription">' + globalize.translate('sharedcomponents#NewCollectionNameExample') + '</div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<label class="checkboxContainer">';
|
||||
html += '<input is="emby-checkbox" type="checkbox" id="chkEnableInternetMetadata" />';
|
||||
html += '<span>' + globalize.translate('sharedcomponents#SearchForCollectionInternetMetadata') + '</span>';
|
||||
html += '</label>';
|
||||
|
||||
// newCollectionInfo
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="formDialogFooter">';
|
||||
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('sharedcomponents#ButtonOk') + '</button>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<input type="hidden" class="fldSelectedItemIds" />';
|
||||
|
||||
html += '</form>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function initEditor(content, items) {
|
||||
if (content.querySelector("#selectCollectionToAddTo").addEventListener("change", function() {
|
||||
this.value ? (content.querySelector(".newCollectionInfo").classList.add("hide"), content.querySelector("#txtNewCollectionName").removeAttribute("required")) : (content.querySelector(".newCollectionInfo").classList.remove("hide"), content.querySelector("#txtNewCollectionName").setAttribute("required", "required"))
|
||||
}), content.querySelector("form").addEventListener("submit", onSubmit), content.querySelector(".fldSelectedItemIds", content).value = items.join(","), items.length) content.querySelector(".fldSelectCollection").classList.remove("hide"), populateCollections(content);
|
||||
else {
|
||||
content.querySelector(".fldSelectCollection").classList.add("hide");
|
||||
var selectCollectionToAddTo = content.querySelector("#selectCollectionToAddTo");
|
||||
selectCollectionToAddTo.innerHTML = "", selectCollectionToAddTo.value = "", triggerChange(selectCollectionToAddTo)
|
||||
|
||||
content.querySelector('#selectCollectionToAddTo').addEventListener('change', function () {
|
||||
if (this.value) {
|
||||
content.querySelector('.newCollectionInfo').classList.add('hide');
|
||||
content.querySelector('#txtNewCollectionName').removeAttribute('required');
|
||||
} else {
|
||||
content.querySelector('.newCollectionInfo').classList.remove('hide');
|
||||
content.querySelector('#txtNewCollectionName').setAttribute('required', 'required');
|
||||
}
|
||||
});
|
||||
|
||||
content.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
content.querySelector('.fldSelectedItemIds', content).value = items.join(',');
|
||||
|
||||
if (items.length) {
|
||||
content.querySelector('.fldSelectCollection').classList.remove('hide');
|
||||
populateCollections(content);
|
||||
} else {
|
||||
content.querySelector('.fldSelectCollection').classList.add('hide');
|
||||
|
||||
var selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo');
|
||||
selectCollectionToAddTo.innerHTML = '';
|
||||
selectCollectionToAddTo.value = '';
|
||||
triggerChange(selectCollectionToAddTo);
|
||||
}
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(["scrollHelper"], function(scrollHelper) {
|
||||
var fn = on ? "on" : "off";
|
||||
scrollHelper.centerFocus[fn](elem, horiz)
|
||||
})
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function CollectionEditor() {}
|
||||
var currentServerId;
|
||||
return CollectionEditor.prototype.show = function(options) {
|
||||
function CollectionEditor() {
|
||||
|
||||
}
|
||||
|
||||
CollectionEditor.prototype.show = function (options) {
|
||||
|
||||
var items = options.items || {};
|
||||
currentServerId = options.serverId;
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: !0,
|
||||
scrollY: !1
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small";
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add("formDialog");
|
||||
var html = "",
|
||||
title = items.length ? globalize.translate("sharedcomponents#HeaderAddToCollection") : globalize.translate("sharedcomponents#NewCollection");
|
||||
return html += '<div class="formDialogHeader">', html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>', html += '<h3 class="formDialogHeaderTitle">', html += title, html += "</h3>", appHost.supports("externallinks") && (html += '<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="' + globalize.translate("sharedcomponents#Help") + '"><i class="md-icon"></i><span style="margin-left:.25em;">' + globalize.translate("sharedcomponents#Help") + "</span></a>"), html += "</div>", html += getEditorHtml(), dlg.innerHTML = html, initEditor(dlg, items), dlg.querySelector(".btnCancel").addEventListener("click", function() {
|
||||
dialogHelper.close(dlg)
|
||||
}), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dialogHelper.open(dlg).then(function() {
|
||||
return layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), dlg.submitted ? Promise.resolve() : Promise.reject()
|
||||
})
|
||||
}, CollectionEditor
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
var title = items.length ? globalize.translate('sharedcomponents#HeaderAddToCollection') : globalize.translate('sharedcomponents#NewCollection');
|
||||
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
html += title;
|
||||
html += '</h3>';
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += '<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="' + globalize.translate('sharedcomponents#Help') + '"><i class="md-icon"></i><span style="margin-left:.25em;">' + globalize.translate('sharedcomponents#Help') + '</span></a>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += getEditorHtml();
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
initEditor(dlg, items);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
||||
}
|
||||
|
||||
return dialogHelper.open(dlg).then(function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
|
||||
if (dlg.submitted) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
};
|
||||
|
||||
return CollectionEditor;
|
||||
});
|
||||
@@ -1,22 +1,40 @@
|
||||
define(["dialog", "globalize"], function(dialog, globalize) {
|
||||
"use strict";
|
||||
return function(text, title) {
|
||||
define(['dialog', 'globalize'], function (dialog, globalize) {
|
||||
'use strict';
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
options = "string" == typeof text ? {
|
||||
title: title,
|
||||
text: text
|
||||
} : text;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
text: text
|
||||
};
|
||||
} else {
|
||||
options = text;
|
||||
}
|
||||
|
||||
var items = [];
|
||||
return items.push({
|
||||
name: options.cancelText || globalize.translate("sharedcomponents#ButtonCancel"),
|
||||
id: "cancel",
|
||||
type: "cancel" === options.primary ? "submit" : "cancel"
|
||||
}), items.push({
|
||||
name: options.confirmText || globalize.translate("sharedcomponents#ButtonOk"),
|
||||
id: "ok",
|
||||
type: "cancel" === options.primary ? "cancel" : "submit"
|
||||
}), options.buttons = items, dialog(options).then(function(result) {
|
||||
return "ok" === result ? Promise.resolve() : Promise.reject()
|
||||
})
|
||||
}
|
||||
|
||||
items.push({
|
||||
name: options.cancelText || globalize.translate('sharedcomponents#ButtonCancel'),
|
||||
id: 'cancel',
|
||||
type: options.primary === 'cancel' ? 'submit' : 'cancel'
|
||||
});
|
||||
|
||||
items.push({
|
||||
name: options.confirmText || globalize.translate('sharedcomponents#ButtonOk'),
|
||||
id: 'ok',
|
||||
type: options.primary === 'cancel' ? 'cancel' : 'submit'
|
||||
});
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
return dialog(options).then(function (result) {
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -1,15 +1,27 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.split(find).join(replace)
|
||||
}
|
||||
return function(options) {
|
||||
"string" == typeof options && (options = {
|
||||
title: "",
|
||||
text: options
|
||||
});
|
||||
var text = replaceAll(options.text || "", "<br/>", "\n");
|
||||
return confirm(text) ? Promise.resolve() : Promise.reject()
|
||||
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
|
||||
return function (options) {
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
title: '',
|
||||
text: options
|
||||
};
|
||||
}
|
||||
|
||||
var text = replaceAll(options.text || '', '<br/>', '\n');
|
||||
var result = confirm(text);
|
||||
|
||||
if (result) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
};
|
||||
});
|
||||
305
src/bower_components/emby-webcomponents/datetime.js
vendored
305
src/bower_components/emby-webcomponents/datetime.js
vendored
@@ -1,113 +1,272 @@
|
||||
define(["globalize"], function(globalize) {
|
||||
"use strict";
|
||||
define(['globalize'], function (globalize) {
|
||||
'use strict';
|
||||
|
||||
function parseISO8601Date(s, toLocal) {
|
||||
var re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/,
|
||||
d = s.match(re);
|
||||
if (!d) throw "Couldn't parse ISO 8601 date string '" + s + "'";
|
||||
|
||||
// parenthese matches:
|
||||
// year month day hours minutes seconds
|
||||
// dotmilliseconds
|
||||
// tzstring plusminus hours minutes
|
||||
var re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/;
|
||||
|
||||
var d = s.match(re);
|
||||
|
||||
// "2010-12-07T11:00:00.000-09:00" parses to:
|
||||
// ["2010-12-07T11:00:00.000-09:00", "2010", "12", "07", "11",
|
||||
// "00", "00", ".000", "-09:00", "-", "09", "00"]
|
||||
// "2010-12-07T11:00:00.000Z" parses to:
|
||||
// ["2010-12-07T11:00:00.000Z", "2010", "12", "07", "11",
|
||||
// "00", "00", ".000", "Z", undefined, undefined, undefined]
|
||||
|
||||
if (!d) {
|
||||
|
||||
throw "Couldn't parse ISO 8601 date string '" + s + "'";
|
||||
}
|
||||
|
||||
// parse strings, leading zeros into proper ints
|
||||
var a = [1, 2, 3, 4, 5, 6, 10, 11];
|
||||
for (var i in a) d[a[i]] = parseInt(d[a[i]], 10);
|
||||
for (var i in a) {
|
||||
d[a[i]] = parseInt(d[a[i]], 10);
|
||||
}
|
||||
d[7] = parseFloat(d[7]);
|
||||
|
||||
// Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]])
|
||||
// note that month is 0-11, not 1-12
|
||||
// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC
|
||||
var ms = Date.UTC(d[1], d[2] - 1, d[3], d[4], d[5], d[6]);
|
||||
if (d[7] > 0 && (ms += Math.round(1e3 * d[7])), "Z" !== d[8] && d[10]) {
|
||||
var offset = 60 * d[10] * 60 * 1e3;
|
||||
d[11] && (offset += 60 * d[11] * 1e3), "-" === d[9] ? ms -= offset : ms += offset
|
||||
} else !1 === toLocal && (ms += 6e4 * (new Date).getTimezoneOffset());
|
||||
return new Date(ms)
|
||||
|
||||
// if there are milliseconds, add them
|
||||
if (d[7] > 0) {
|
||||
ms += Math.round(d[7] * 1000);
|
||||
}
|
||||
|
||||
// if there's a timezone, calculate it
|
||||
if (d[8] !== "Z" && d[10]) {
|
||||
var offset = d[10] * 60 * 60 * 1000;
|
||||
if (d[11]) {
|
||||
offset += d[11] * 60 * 1000;
|
||||
}
|
||||
if (d[9] === "-") {
|
||||
ms -= offset;
|
||||
} else {
|
||||
ms += offset;
|
||||
}
|
||||
} else if (toLocal === false) {
|
||||
ms += new Date().getTimezoneOffset() * 60000;
|
||||
}
|
||||
|
||||
return new Date(ms);
|
||||
}
|
||||
|
||||
function getDisplayRunningTime(ticks) {
|
||||
var parts = [],
|
||||
hours = ticks / 36e9;
|
||||
hours = Math.floor(hours), hours && parts.push(hours), ticks -= 36e9 * hours;
|
||||
var minutes = ticks / 6e8;
|
||||
minutes = Math.floor(minutes), ticks -= 6e8 * minutes, minutes < 10 && hours && (minutes = "0" + minutes), parts.push(minutes);
|
||||
var seconds = ticks / 1e7;
|
||||
return seconds = Math.floor(seconds), seconds < 10 && (seconds = "0" + seconds), parts.push(seconds), parts.join(":")
|
||||
var ticksPerHour = 36000000000;
|
||||
var ticksPerMinute = 600000000;
|
||||
var ticksPerSecond = 10000000;
|
||||
|
||||
var parts = [];
|
||||
|
||||
var hours = ticks / ticksPerHour;
|
||||
hours = Math.floor(hours);
|
||||
|
||||
if (hours) {
|
||||
parts.push(hours);
|
||||
}
|
||||
|
||||
ticks -= (hours * ticksPerHour);
|
||||
|
||||
var minutes = ticks / ticksPerMinute;
|
||||
minutes = Math.floor(minutes);
|
||||
|
||||
ticks -= (minutes * ticksPerMinute);
|
||||
|
||||
if (minutes < 10 && hours) {
|
||||
minutes = '0' + minutes;
|
||||
}
|
||||
parts.push(minutes);
|
||||
|
||||
var seconds = ticks / ticksPerSecond;
|
||||
seconds = Math.floor(seconds);
|
||||
|
||||
if (seconds < 10) {
|
||||
seconds = '0' + seconds;
|
||||
}
|
||||
parts.push(seconds);
|
||||
|
||||
return parts.join(':');
|
||||
}
|
||||
|
||||
var toLocaleTimeStringSupportsLocales = function () {
|
||||
try {
|
||||
new Date().toLocaleTimeString('i');
|
||||
} catch (e) {
|
||||
return e.name === 'RangeError';
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
function getOptionList(options) {
|
||||
|
||||
var list = [];
|
||||
for (var i in options) list.push({
|
||||
name: i,
|
||||
value: options[i]
|
||||
});
|
||||
return list
|
||||
|
||||
for (var i in options) {
|
||||
list.push({
|
||||
name: i,
|
||||
value: options[i]
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function toLocaleString(date, options) {
|
||||
if (!date) throw new Error("date cannot be null");
|
||||
if (options = options || {}, toLocaleTimeStringSupportsLocales) {
|
||||
var currentLocale = globalize.getCurrentDateTimeLocale();
|
||||
if (currentLocale) return date.toLocaleString(currentLocale, options)
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
return date.toLocaleString()
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (toLocaleTimeStringSupportsLocales) {
|
||||
|
||||
var currentLocale = globalize.getCurrentDateTimeLocale();
|
||||
|
||||
if (currentLocale) {
|
||||
return date.toLocaleString(currentLocale, options);
|
||||
}
|
||||
}
|
||||
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
function toLocaleDateString(date, options) {
|
||||
if (!date) throw new Error("date cannot be null");
|
||||
if (options = options || {}, toLocaleTimeStringSupportsLocales) {
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (toLocaleTimeStringSupportsLocales) {
|
||||
|
||||
var currentLocale = globalize.getCurrentDateTimeLocale();
|
||||
if (currentLocale) return date.toLocaleDateString(currentLocale, options)
|
||||
|
||||
if (currentLocale) {
|
||||
return date.toLocaleDateString(currentLocale, options);
|
||||
}
|
||||
}
|
||||
|
||||
// This is essentially a hard-coded polyfill
|
||||
var optionList = getOptionList(options);
|
||||
if (1 === optionList.length && "weekday" === optionList[0].name) {
|
||||
if (optionList.length === 1 && optionList[0].name === 'weekday') {
|
||||
var weekday = [];
|
||||
return weekday[0] = "Sun", weekday[1] = "Mon", weekday[2] = "Tue", weekday[3] = "Wed", weekday[4] = "Thu", weekday[5] = "Fri", weekday[6] = "Sat", weekday[date.getDay()]
|
||||
weekday[0] = "Sun";
|
||||
weekday[1] = "Mon";
|
||||
weekday[2] = "Tue";
|
||||
weekday[3] = "Wed";
|
||||
weekday[4] = "Thu";
|
||||
weekday[5] = "Fri";
|
||||
weekday[6] = "Sat";
|
||||
return weekday[date.getDay()];
|
||||
}
|
||||
return date.toLocaleDateString()
|
||||
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
|
||||
function toLocaleTimeString(date, options) {
|
||||
if (!date) throw new Error("date cannot be null");
|
||||
if (options = options || {}, toLocaleTimeStringSupportsLocales) {
|
||||
var currentLocale = globalize.getCurrentDateTimeLocale();
|
||||
if (currentLocale) return date.toLocaleTimeString(currentLocale, options)
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
return date.toLocaleTimeString()
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (toLocaleTimeStringSupportsLocales) {
|
||||
|
||||
var currentLocale = globalize.getCurrentDateTimeLocale();
|
||||
|
||||
if (currentLocale) {
|
||||
return date.toLocaleTimeString(currentLocale, options);
|
||||
}
|
||||
}
|
||||
|
||||
return date.toLocaleTimeString();
|
||||
}
|
||||
|
||||
function getDisplayTime(date) {
|
||||
if (!date) throw new Error("date cannot be null");
|
||||
if ("string" === (typeof date).toString().toLowerCase()) try {
|
||||
date = parseISO8601Date(date, !0)
|
||||
} catch (err) {
|
||||
return date
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
if (toLocaleTimeStringSupportsLocales) return toLocaleTimeString(date, {
|
||||
hour: "numeric",
|
||||
minute: "2-digit"
|
||||
});
|
||||
var time = toLocaleTimeString(date),
|
||||
timeLower = time.toLowerCase();
|
||||
if (-1 !== timeLower.indexOf("am") || -1 !== timeLower.indexOf("pm")) {
|
||||
|
||||
if ((typeof date).toString().toLowerCase() === 'string') {
|
||||
try {
|
||||
|
||||
date = parseISO8601Date(date, true);
|
||||
|
||||
} catch (err) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
if (toLocaleTimeStringSupportsLocales) {
|
||||
return toLocaleTimeString(date, {
|
||||
|
||||
hour: 'numeric',
|
||||
minute: '2-digit'
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
var time = toLocaleTimeString(date);
|
||||
|
||||
var timeLower = time.toLowerCase();
|
||||
|
||||
if (timeLower.indexOf('am') !== -1 || timeLower.indexOf('pm') !== -1) {
|
||||
|
||||
time = timeLower;
|
||||
var hour = date.getHours() % 12,
|
||||
suffix = date.getHours() > 11 ? "pm" : "am";
|
||||
hour || (hour = 12);
|
||||
var hour = date.getHours() % 12;
|
||||
var suffix = date.getHours() > 11 ? 'pm' : 'am';
|
||||
if (!hour) {
|
||||
hour = 12;
|
||||
}
|
||||
var minutes = date.getMinutes();
|
||||
minutes < 10 && (minutes = "0" + minutes), minutes = ":" + minutes, time = hour + minutes + suffix
|
||||
|
||||
if (minutes < 10) {
|
||||
minutes = '0' + minutes;
|
||||
}
|
||||
|
||||
minutes = ':' + minutes;
|
||||
time = hour + minutes + suffix;
|
||||
} else {
|
||||
var timeParts = time.split(":");
|
||||
timeParts.length > 2 && (timeParts.length = 2, time = timeParts.join(":"))
|
||||
|
||||
var timeParts = time.split(':');
|
||||
|
||||
// Trim off seconds
|
||||
if (timeParts.length > 2) {
|
||||
|
||||
// setting to 2 also handles '21:00:28 GMT+9:30'
|
||||
timeParts.length = 2;
|
||||
time = timeParts.join(':');
|
||||
}
|
||||
}
|
||||
return time
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
function isRelativeDay(date, offsetInDays) {
|
||||
if (!date) throw new Error("date cannot be null");
|
||||
var yesterday = new Date,
|
||||
day = yesterday.getDate() + offsetInDays;
|
||||
return yesterday.setDate(day), date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day
|
||||
}
|
||||
var toLocaleTimeStringSupportsLocales = function() {
|
||||
try {
|
||||
(new Date).toLocaleTimeString("i")
|
||||
} catch (e) {
|
||||
return "RangeError" === e.name
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
return !1
|
||||
}();
|
||||
|
||||
var yesterday = new Date();
|
||||
var day = yesterday.getDate() + offsetInDays;
|
||||
|
||||
yesterday.setDate(day); // automatically adjusts month/year appropriately
|
||||
|
||||
return date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day;
|
||||
}
|
||||
|
||||
return {
|
||||
parseISO8601Date: parseISO8601Date,
|
||||
getDisplayRunningTime: getDisplayRunningTime,
|
||||
@@ -116,8 +275,8 @@ define(["globalize"], function(globalize) {
|
||||
getDisplayTime: getDisplayTime,
|
||||
isRelativeDay: isRelativeDay,
|
||||
toLocaleTimeString: toLocaleTimeString,
|
||||
supportsLocalization: function() {
|
||||
return toLocaleTimeStringSupportsLocales
|
||||
supportsLocalization: function () {
|
||||
return toLocaleTimeStringSupportsLocales;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,39 +1,57 @@
|
||||
define(["connectionManager", "confirm", "appRouter", "globalize"], function(connectionManager, confirm, appRouter, globalize) {
|
||||
"use strict";
|
||||
define(['connectionManager', 'confirm', 'appRouter', 'globalize'], function (connectionManager, confirm, appRouter, globalize) {
|
||||
'use strict';
|
||||
|
||||
function alertText(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
require(["alert"], function(alert) {
|
||||
alert(options).then(resolve, resolve)
|
||||
})
|
||||
})
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
alert(options).then(resolve, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteItem(options) {
|
||||
var item = options.item,
|
||||
itemId = item.Id,
|
||||
parentId = item.SeasonId || item.SeriesId || item.ParentId,
|
||||
serverId = item.ServerId,
|
||||
msg = globalize.translate("sharedcomponents#ConfirmDeleteItem"),
|
||||
title = globalize.translate("sharedcomponents#HeaderDeleteItem"),
|
||||
apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
var item = options.item;
|
||||
var itemId = item.Id;
|
||||
var parentId = item.SeasonId || item.SeriesId || item.ParentId;
|
||||
var serverId = item.ServerId;
|
||||
|
||||
var msg = globalize.translate('sharedcomponents#ConfirmDeleteItem');
|
||||
var title = globalize.translate('sharedcomponents#HeaderDeleteItem');
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
return confirm({
|
||||
|
||||
title: title,
|
||||
text: msg,
|
||||
confirmText: globalize.translate("sharedcomponents#Delete"),
|
||||
primary: "cancel"
|
||||
}).then(function() {
|
||||
return apiClient.deleteItem(itemId).then(function() {
|
||||
options.navigate && (parentId ? appRouter.showItem(parentId, serverId) : appRouter.goHome())
|
||||
}, function(err) {
|
||||
var result = function() {
|
||||
return Promise.reject(err)
|
||||
confirmText: globalize.translate('sharedcomponents#Delete'),
|
||||
primary: 'cancel'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
return apiClient.deleteItem(itemId).then(function () {
|
||||
|
||||
if (options.navigate) {
|
||||
if (parentId) {
|
||||
appRouter.showItem(parentId, serverId);
|
||||
} else {
|
||||
appRouter.goHome();
|
||||
}
|
||||
}
|
||||
}, function (err) {
|
||||
|
||||
var result = function () {
|
||||
return Promise.reject(err);
|
||||
};
|
||||
return alertText(globalize.translate("sharedcomponents#ErrorDeletingItem")).then(result, result)
|
||||
})
|
||||
})
|
||||
|
||||
return alertText(globalize.translate('sharedcomponents#ErrorDeletingItem')).then(result, result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
deleteItem: deleteItem
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,46 +1,133 @@
|
||||
define(["dialogHelper", "dom", "layoutManager", "scrollHelper", "globalize", "require", "material-icons", "emby-button", "paper-icon-button-light", "emby-input", "formDialogStyle", "flexStyles"], function(dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
|
||||
"use strict";
|
||||
define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
|
||||
'use strict';
|
||||
|
||||
function showDialog(options, template) {
|
||||
function onButtonClick() {
|
||||
dialogResult = this.getAttribute("data-id"), dialogHelper.close(dlg)
|
||||
}
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: !0,
|
||||
scrollY: !1
|
||||
},
|
||||
enableTvLayout = layoutManager.tv;
|
||||
enableTvLayout && (dialogOptions.size = "fullscreen");
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateHtml(template, "sharedcomponents"), dlg.classList.add("align-items-center"), dlg.classList.add("justify-content-center");
|
||||
var formDialogContent = dlg.querySelector(".formDialogContent");
|
||||
formDialogContent.classList.add("no-grow"), enableTvLayout ? (formDialogContent.style["max-width"] = "50%", formDialogContent.style["max-height"] = "60%", scrollHelper.centerFocus.on(formDialogContent, !1)) : (formDialogContent.style.maxWidth = Math.min(150 * options.buttons.length + 200, dom.getWindowSize().innerWidth - 50) + "px", dlg.classList.add("dialog-fullscreen-lowres")), options.title ? dlg.querySelector(".formDialogHeaderTitle").innerHTML = options.title || "" : dlg.querySelector(".formDialogHeaderTitle").classList.add("hide");
|
||||
var displayText = options.html || options.text || "";
|
||||
dlg.querySelector(".text").innerHTML = displayText, displayText || dlg.querySelector(".dialogContentInner").classList.add("hide");
|
||||
var i, length, html = "",
|
||||
hasDescriptions = !1;
|
||||
for (i = 0, length = options.buttons.length; i < length; i++) {
|
||||
var item = options.buttons[i],
|
||||
autoFocus = 0 === i ? " autofocus" : "",
|
||||
buttonClass = "btnOption raised formDialogFooterItem formDialogFooterItem-autosize";
|
||||
item.type && (buttonClass += " button-" + item.type), item.description && (hasDescriptions = !0), hasDescriptions && (buttonClass += " formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom"), html += '<button is="emby-button" type="button" class="' + buttonClass + '" data-id="' + item.id + '"' + autoFocus + ">" + item.name + "</button>", item.description && (html += '<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">' + item.description + "</div>")
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
var enableTvLayout = layoutManager.tv;
|
||||
|
||||
if (enableTvLayout) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
}
|
||||
dlg.querySelector(".formDialogFooter").innerHTML = html, hasDescriptions && dlg.querySelector(".formDialogFooter").classList.add("formDialogFooter-vertical");
|
||||
var dialogResult, buttons = dlg.querySelectorAll(".btnOption");
|
||||
for (i = 0, length = buttons.length; i < length; i++) buttons[i].addEventListener("click", onButtonClick);
|
||||
return dialogHelper.open(dlg).then(function() {
|
||||
return enableTvLayout && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), dialogResult || Promise.reject()
|
||||
})
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
dlg.innerHTML = globalize.translateHtml(template, 'sharedcomponents');
|
||||
|
||||
dlg.classList.add('align-items-center');
|
||||
dlg.classList.add('justify-content-center');
|
||||
var formDialogContent = dlg.querySelector('.formDialogContent');
|
||||
formDialogContent.classList.add('no-grow');
|
||||
|
||||
if (enableTvLayout) {
|
||||
formDialogContent.style['max-width'] = '50%';
|
||||
formDialogContent.style['max-height'] = '60%';
|
||||
scrollHelper.centerFocus.on(formDialogContent, false);
|
||||
} else {
|
||||
formDialogContent.style.maxWidth = (Math.min((options.buttons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)) + 'px';
|
||||
dlg.classList.add('dialog-fullscreen-lowres');
|
||||
}
|
||||
|
||||
//dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
// dialogHelper.close(dlg);
|
||||
//});
|
||||
|
||||
if (options.title) {
|
||||
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || '';
|
||||
} else {
|
||||
dlg.querySelector('.formDialogHeaderTitle').classList.add('hide');
|
||||
}
|
||||
|
||||
var displayText = options.html || options.text || '';
|
||||
dlg.querySelector('.text').innerHTML = displayText;
|
||||
|
||||
if (!displayText) {
|
||||
dlg.querySelector('.dialogContentInner').classList.add('hide');
|
||||
}
|
||||
|
||||
var i, length;
|
||||
var html = '';
|
||||
var hasDescriptions = false;
|
||||
|
||||
for (i = 0, length = options.buttons.length; i < length; i++) {
|
||||
|
||||
var item = options.buttons[i];
|
||||
var autoFocus = i === 0 ? ' autofocus' : '';
|
||||
|
||||
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
|
||||
|
||||
if (item.type) {
|
||||
buttonClass += ' button-' + item.type;
|
||||
}
|
||||
|
||||
if (item.description) {
|
||||
hasDescriptions = true;
|
||||
}
|
||||
|
||||
if (hasDescriptions) {
|
||||
buttonClass += ' formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom';
|
||||
}
|
||||
|
||||
html += '<button is="emby-button" type="button" class="' + buttonClass + '" data-id="' + item.id + '"' + autoFocus + '>' + item.name + '</button>';
|
||||
|
||||
if (item.description) {
|
||||
html += '<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">' + item.description + '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
dlg.querySelector('.formDialogFooter').innerHTML = html;
|
||||
|
||||
if (hasDescriptions) {
|
||||
dlg.querySelector('.formDialogFooter').classList.add('formDialogFooter-vertical');
|
||||
}
|
||||
|
||||
var dialogResult;
|
||||
function onButtonClick() {
|
||||
dialogResult = this.getAttribute('data-id');
|
||||
dialogHelper.close(dlg);
|
||||
}
|
||||
|
||||
var buttons = dlg.querySelectorAll('.btnOption');
|
||||
for (i = 0, length = buttons.length; i < length; i++) {
|
||||
buttons[i].addEventListener('click', onButtonClick);
|
||||
}
|
||||
|
||||
return dialogHelper.open(dlg).then(function () {
|
||||
|
||||
if (enableTvLayout) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
if (dialogResult) {
|
||||
return dialogResult;
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
return function(text, title) {
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
return options = "string" == typeof text ? {
|
||||
title: title,
|
||||
text: text
|
||||
} : text, new Promise(function(resolve, reject) {
|
||||
require(["text!./dialog.template.html"], function(template) {
|
||||
showDialog(options, template).then(resolve, reject)
|
||||
})
|
||||
})
|
||||
}
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
text: text
|
||||
};
|
||||
} else {
|
||||
options = text;
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['text!./dialog.template.html'], function (template) {
|
||||
showDialog(options, template).then(resolve, reject);
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -1,12 +1,6 @@
|
||||
.dialogContainer {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@@ -16,234 +10,148 @@
|
||||
z-index: 999999 !important;
|
||||
contain: strict;
|
||||
overflow: hidden;
|
||||
overscroll-behavior: contain
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
margin: 0;
|
||||
-webkit-border-radius: .2em;
|
||||
border-radius: .2em;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
will-change: transform, opacity;
|
||||
/* Strict does not work well with actionsheet */
|
||||
contain: style paint;
|
||||
-webkit-box-shadow: 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12), 0 8px 10px -5px rgba(0, 0, 0, .4);
|
||||
box-shadow: 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12), 0 8px 10px -5px rgba(0, 0, 0, .4)
|
||||
box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.dialog-fixedSize {
|
||||
-webkit-border-radius: 0;
|
||||
border-radius: 0;
|
||||
max-height: none;
|
||||
max-width: none;
|
||||
contain: layout style paint
|
||||
contain: layout style paint;
|
||||
}
|
||||
|
||||
.dialog-fullscreen {
|
||||
/* Needed due to formDialog style */
|
||||
position: fixed !important;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none
|
||||
}
|
||||
|
||||
@-webkit-keyframes scaledown {
|
||||
from {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(.5);
|
||||
transform: scale(.5)
|
||||
}
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@keyframes scaledown {
|
||||
from {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none
|
||||
transform: none;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(.5);
|
||||
transform: scale(.5)
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes scaleup {
|
||||
from {
|
||||
-webkit-transform: scale(.5);
|
||||
transform: scale(.5);
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scaleup {
|
||||
from {
|
||||
-webkit-transform: scale(.5);
|
||||
transform: scale(.5);
|
||||
opacity: 0
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadein {
|
||||
from {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeout {
|
||||
from {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
from {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes slideup {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, 30%, 0);
|
||||
transform: translate3d(0, 30%, 0)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideup {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, 30%, 0);
|
||||
transform: translate3d(0, 30%, 0)
|
||||
transform: translate3d(0, 30%, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes slidedown {
|
||||
from {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, 20%, 0);
|
||||
transform: translate3d(0, 20%, 0)
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slidedown {
|
||||
|
||||
from {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none
|
||||
transform: none;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, 20%, 0);
|
||||
transform: translate3d(0, 20%, 0)
|
||||
transform: translate3d(0, 20%, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width:80em),
|
||||
all and (max-height:45em) {
|
||||
@media all and (max-width: 80em), all and (max-height: 45em) {
|
||||
|
||||
.dialog-fixedSize,
|
||||
.dialog-fullscreen-lowres {
|
||||
.dialog-fixedSize, .dialog-fullscreen-lowres {
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
bottom: 0 !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
margin: 0 !important;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width:80em) and (min-height:45em) {
|
||||
@media all and (min-width: 80em) and (min-height: 45em) {
|
||||
|
||||
.dialog-medium {
|
||||
width: 80%;
|
||||
height: 80%
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
.dialog-medium-tall {
|
||||
width: 80%;
|
||||
height: 90%
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.dialog-small {
|
||||
width: 60%;
|
||||
height: 80%
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
.dialog-fullscreen-border {
|
||||
width: 90%;
|
||||
height: 90%
|
||||
height: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.noScroll {
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: hidden !important
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
.dialogBackdrop {
|
||||
@@ -256,12 +164,10 @@ all and (max-height:45em) {
|
||||
right: 0 !important;
|
||||
margin: 0 !important;
|
||||
z-index: 999999 !important;
|
||||
-webkit-transition: opacity ease-out .2s;
|
||||
-o-transition: opacity ease-out .2s;
|
||||
transition: opacity ease-out .2s;
|
||||
will-change: opacity
|
||||
transition: opacity ease-out 0.2s;
|
||||
will-change: opacity;
|
||||
}
|
||||
|
||||
.dialogBackdropOpened {
|
||||
opacity: .5
|
||||
}
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
@@ -1,225 +1,486 @@
|
||||
define(["appRouter", "focusManager", "browser", "layoutManager", "inputManager", "dom", "css!./dialoghelper.css", "scrollStyles"], function(appRouter, focusManager, browser, layoutManager, inputManager, dom) {
|
||||
"use strict";
|
||||
define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', 'dom', 'css!./dialoghelper.css', 'scrollStyles'], function (appRouter, focusManager, browser, layoutManager, inputManager, dom) {
|
||||
'use strict';
|
||||
|
||||
var globalOnOpenCallback;
|
||||
|
||||
function enableAnimation() {
|
||||
return !browser.tv && browser.supportsCssAnimation()
|
||||
|
||||
// too slow
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return browser.supportsCssAnimation();
|
||||
}
|
||||
|
||||
function removeCenterFocus(dlg) {
|
||||
layoutManager.tv && (dlg.classList.contains("scrollX") ? centerFocus(dlg, !0, !1) : dlg.classList.contains("smoothScrollY") && centerFocus(dlg, !1, !1))
|
||||
|
||||
if (layoutManager.tv) {
|
||||
if (dlg.classList.contains('scrollX')) {
|
||||
centerFocus(dlg, true, false);
|
||||
}
|
||||
else if (dlg.classList.contains('smoothScrollY')) {
|
||||
centerFocus(dlg, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryRemoveElement(elem) {
|
||||
var parentNode = elem.parentNode;
|
||||
if (parentNode) try {
|
||||
parentNode.removeChild(elem)
|
||||
} catch (err) {
|
||||
console.log("Error removing dialog element: " + err)
|
||||
if (parentNode) {
|
||||
|
||||
// Seeing crashes in edge webview
|
||||
try {
|
||||
parentNode.removeChild(elem);
|
||||
} catch (err) {
|
||||
console.log('Error removing dialog element: ' + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function DialogHashHandler(dlg, hash, resolve) {
|
||||
|
||||
var self = this;
|
||||
self.originalUrl = window.location.href;
|
||||
var activeElement = document.activeElement;
|
||||
var removeScrollLockOnClose = false;
|
||||
|
||||
function onHashChange(e) {
|
||||
|
||||
var isBack = self.originalUrl === window.location.href;
|
||||
!isBack && isOpened(dlg) || window.removeEventListener("popstate", onHashChange), isBack && (self.closedByBack = !0, closeDialog(dlg))
|
||||
|
||||
if (isBack || !isOpened(dlg)) {
|
||||
window.removeEventListener('popstate', onHashChange);
|
||||
}
|
||||
|
||||
if (isBack) {
|
||||
self.closedByBack = true;
|
||||
closeDialog(dlg);
|
||||
}
|
||||
}
|
||||
|
||||
function onBackCommand(e) {
|
||||
"back" === e.detail.command && (self.closedByBack = !0, e.preventDefault(), e.stopPropagation(), closeDialog(dlg))
|
||||
|
||||
if (e.detail.command === 'back') {
|
||||
self.closedByBack = true;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
closeDialog(dlg);
|
||||
}
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
if (isHistoryEnabled(dlg) || inputManager.off(dlg, onBackCommand), window.removeEventListener("popstate", onHashChange), removeBackdrop(dlg), dlg.classList.remove("opened"), removeScrollLockOnClose && document.body.classList.remove("noScroll"), !self.closedByBack && isHistoryEnabled(dlg)) {
|
||||
(history.state || {}).dialogId === hash && history.back()
|
||||
|
||||
if (!isHistoryEnabled(dlg)) {
|
||||
inputManager.off(dlg, onBackCommand);
|
||||
}
|
||||
if (layoutManager.tv && focusManager.focus(activeElement), "false" !== dlg.getAttribute("data-removeonclose")) {
|
||||
|
||||
window.removeEventListener('popstate', onHashChange);
|
||||
|
||||
removeBackdrop(dlg);
|
||||
dlg.classList.remove('opened');
|
||||
|
||||
if (removeScrollLockOnClose) {
|
||||
document.body.classList.remove('noScroll');
|
||||
}
|
||||
|
||||
if (!self.closedByBack && isHistoryEnabled(dlg)) {
|
||||
var state = history.state || {};
|
||||
if (state.dialogId === hash) {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
focusManager.focus(activeElement);
|
||||
}
|
||||
|
||||
if (dlg.getAttribute('data-removeonclose') !== 'false') {
|
||||
removeCenterFocus(dlg);
|
||||
|
||||
var dialogContainer = dlg.dialogContainer;
|
||||
dialogContainer ? (tryRemoveElement(dialogContainer), dlg.dialogContainer = null) : tryRemoveElement(dlg)
|
||||
if (dialogContainer) {
|
||||
tryRemoveElement(dialogContainer);
|
||||
dlg.dialogContainer = null;
|
||||
} else {
|
||||
tryRemoveElement(dlg);
|
||||
}
|
||||
}
|
||||
setTimeout(function() {
|
||||
|
||||
//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)
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
|
||||
var center = !dlg.classList.contains('dialog-fixedSize');
|
||||
if (center) {
|
||||
dlg.classList.add('centeredDialog');
|
||||
}
|
||||
|
||||
dlg.classList.remove('hide');
|
||||
|
||||
addBackdropOverlay(dlg);
|
||||
|
||||
dlg.classList.add('opened');
|
||||
dlg.dispatchEvent(new CustomEvent('open', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
|
||||
if (dlg.getAttribute('data-lockscroll') === 'true' && !document.body.classList.contains('noScroll')) {
|
||||
document.body.classList.add('noScroll');
|
||||
removeScrollLockOnClose = true;
|
||||
}
|
||||
|
||||
animateDialogOpen(dlg);
|
||||
|
||||
if (isHistoryEnabled(dlg)) {
|
||||
appRouter.pushState({ dialogId: hash }, "Dialog", '#' + hash);
|
||||
|
||||
window.addEventListener('popstate', onHashChange);
|
||||
} else {
|
||||
inputManager.on(dlg, onBackCommand);
|
||||
}
|
||||
var self = this;
|
||||
self.originalUrl = window.location.href;
|
||||
var activeElement = document.activeElement,
|
||||
removeScrollLockOnClose = !1;
|
||||
dlg.addEventListener("close", onDialogClosed), !dlg.classList.contains("dialog-fixedSize") && dlg.classList.add("centeredDialog"), dlg.classList.remove("hide"), addBackdropOverlay(dlg), dlg.classList.add("opened"), dlg.dispatchEvent(new CustomEvent("open", {
|
||||
bubbles: !1,
|
||||
cancelable: !1
|
||||
})), "true" !== dlg.getAttribute("data-lockscroll") || document.body.classList.contains("noScroll") || (document.body.classList.add("noScroll"), removeScrollLockOnClose = !0), animateDialogOpen(dlg), isHistoryEnabled(dlg) ? (appRouter.pushState({
|
||||
dialogId: hash
|
||||
}, "Dialog", "#" + hash), window.addEventListener("popstate", onHashChange)) : inputManager.on(dlg, onBackCommand)
|
||||
}
|
||||
|
||||
function addBackdropOverlay(dlg) {
|
||||
var backdrop = document.createElement("div");
|
||||
backdrop.classList.add("dialogBackdrop");
|
||||
|
||||
var backdrop = document.createElement('div');
|
||||
backdrop.classList.add('dialogBackdrop');
|
||||
|
||||
var backdropParent = dlg.dialogContainer || dlg;
|
||||
backdropParent.parentNode.insertBefore(backdrop, backdropParent), dlg.backdrop = backdrop, backdrop.offsetWidth, backdrop.classList.add("dialogBackdropOpened"), dom.addEventListener(dlg.dialogContainer || backdrop, "click", function(e) {
|
||||
e.target === dlg.dialogContainer && close(dlg)
|
||||
backdropParent.parentNode.insertBefore(backdrop, backdropParent);
|
||||
dlg.backdrop = backdrop;
|
||||
|
||||
// trigger reflow or the backdrop will not animate
|
||||
void backdrop.offsetWidth;
|
||||
backdrop.classList.add('dialogBackdropOpened');
|
||||
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', function (e) {
|
||||
if (e.target === dlg.dialogContainer) {
|
||||
close(dlg);
|
||||
}
|
||||
}, {
|
||||
passive: !0
|
||||
})
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
function isHistoryEnabled(dlg) {
|
||||
return "true" === dlg.getAttribute("data-history")
|
||||
return dlg.getAttribute('data-history') === 'true';
|
||||
}
|
||||
|
||||
function open(dlg) {
|
||||
globalOnOpenCallback && globalOnOpenCallback(dlg);
|
||||
|
||||
if (globalOnOpenCallback) {
|
||||
globalOnOpenCallback(dlg);
|
||||
}
|
||||
|
||||
var parent = dlg.parentNode;
|
||||
parent && parent.removeChild(dlg);
|
||||
var dialogContainer = document.createElement("div");
|
||||
return dialogContainer.classList.add("dialogContainer"), dialogContainer.appendChild(dlg), dlg.dialogContainer = dialogContainer, document.body.appendChild(dialogContainer), new Promise(function(resolve, reject) {
|
||||
new DialogHashHandler(dlg, "dlg" + (new Date).getTime(), resolve)
|
||||
})
|
||||
if (parent) {
|
||||
parent.removeChild(dlg);
|
||||
}
|
||||
|
||||
var dialogContainer = document.createElement('div');
|
||||
dialogContainer.classList.add('dialogContainer');
|
||||
dialogContainer.appendChild(dlg);
|
||||
dlg.dialogContainer = dialogContainer;
|
||||
document.body.appendChild(dialogContainer);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
new DialogHashHandler(dlg, 'dlg' + new Date().getTime(), resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function isOpened(dlg) {
|
||||
return !dlg.classList.contains("hide")
|
||||
|
||||
//return dlg.opened;
|
||||
return !dlg.classList.contains('hide');
|
||||
}
|
||||
|
||||
function close(dlg) {
|
||||
isOpened(dlg) && (isHistoryEnabled(dlg) ? history.back() : closeDialog(dlg))
|
||||
|
||||
if (isOpened(dlg)) {
|
||||
if (isHistoryEnabled(dlg)) {
|
||||
history.back();
|
||||
} else {
|
||||
closeDialog(dlg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeDialog(dlg) {
|
||||
if (!dlg.classList.contains("hide")) {
|
||||
dlg.dispatchEvent(new CustomEvent("closing", {
|
||||
bubbles: !1,
|
||||
cancelable: !1
|
||||
|
||||
if (!dlg.classList.contains('hide')) {
|
||||
|
||||
dlg.dispatchEvent(new CustomEvent('closing', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
animateDialogClose(dlg, function() {
|
||||
focusManager.popScope(dlg), dlg.classList.add("hide"), dlg.dispatchEvent(new CustomEvent("close", {
|
||||
bubbles: !1,
|
||||
cancelable: !1
|
||||
}))
|
||||
})
|
||||
|
||||
var onAnimationFinish = function () {
|
||||
focusManager.popScope(dlg);
|
||||
|
||||
dlg.classList.add('hide');
|
||||
dlg.dispatchEvent(new CustomEvent('close', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
};
|
||||
|
||||
animateDialogClose(dlg, onAnimationFinish);
|
||||
}
|
||||
}
|
||||
|
||||
function animateDialogOpen(dlg) {
|
||||
var onAnimationFinish = function() {
|
||||
focusManager.pushScope(dlg), "true" === dlg.getAttribute("data-autofocus") && focusManager.autoFocus(dlg)
|
||||
|
||||
var onAnimationFinish = function () {
|
||||
focusManager.pushScope(dlg);
|
||||
if (dlg.getAttribute('data-autofocus') === 'true') {
|
||||
focusManager.autoFocus(dlg);
|
||||
}
|
||||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
var onFinish = function() {
|
||||
|
||||
var onFinish = function () {
|
||||
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: !0
|
||||
}), onAnimationFinish()
|
||||
once: true
|
||||
});
|
||||
onAnimationFinish();
|
||||
};
|
||||
return void dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: !0
|
||||
})
|
||||
dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
onAnimationFinish()
|
||||
|
||||
onAnimationFinish();
|
||||
}
|
||||
|
||||
function animateDialogClose(dlg, onAnimationFinish) {
|
||||
|
||||
if (enableAnimation()) {
|
||||
var animated = !0;
|
||||
|
||||
var animated = true;
|
||||
|
||||
switch (dlg.animationConfig.exit.name) {
|
||||
case "fadeout":
|
||||
dlg.style.animation = "fadeout " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
|
||||
|
||||
case 'fadeout':
|
||||
dlg.style.animation = 'fadeout ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
|
||||
break;
|
||||
case "scaledown":
|
||||
dlg.style.animation = "scaledown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
|
||||
case 'scaledown':
|
||||
dlg.style.animation = 'scaledown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
|
||||
break;
|
||||
case "slidedown":
|
||||
dlg.style.animation = "slidedown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
|
||||
case 'slidedown':
|
||||
dlg.style.animation = 'slidedown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
|
||||
break;
|
||||
default:
|
||||
animated = !1
|
||||
animated = false;
|
||||
break;
|
||||
}
|
||||
var onFinish = function() {
|
||||
var onFinish = function () {
|
||||
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: !0
|
||||
}), onAnimationFinish()
|
||||
once: true
|
||||
});
|
||||
onAnimationFinish();
|
||||
};
|
||||
if (dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: !0
|
||||
}), animated) return
|
||||
dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
});
|
||||
|
||||
if (animated) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
onAnimationFinish()
|
||||
|
||||
onAnimationFinish();
|
||||
}
|
||||
|
||||
var supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
|
||||
|
||||
function shouldLockDocumentScroll(options) {
|
||||
return !(supportsOverscrollBehavior && (options.size || !browser.touch)) && (null != options.lockScroll ? options.lockScroll : "fullscreen" === options.size || (!!options.size || browser.touch))
|
||||
|
||||
if (supportsOverscrollBehavior && (options.size || !browser.touch)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.lockScroll != null) {
|
||||
return options.lockScroll;
|
||||
}
|
||||
|
||||
if (options.size === 'fullscreen') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (options.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return browser.touch;
|
||||
}
|
||||
|
||||
function removeBackdrop(dlg) {
|
||||
|
||||
var backdrop = dlg.backdrop;
|
||||
if (backdrop) {
|
||||
dlg.backdrop = null;
|
||||
var onAnimationFinish = function() {
|
||||
tryRemoveElement(backdrop)
|
||||
};
|
||||
if (enableAnimation()) return backdrop.classList.remove("dialogBackdropOpened"), void setTimeout(onAnimationFinish, 300);
|
||||
onAnimationFinish()
|
||||
|
||||
if (!backdrop) {
|
||||
return;
|
||||
}
|
||||
|
||||
dlg.backdrop = null;
|
||||
|
||||
var onAnimationFinish = function () {
|
||||
tryRemoveElement(backdrop);
|
||||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
backdrop.classList.remove('dialogBackdropOpened');
|
||||
|
||||
// this is not firing animatonend
|
||||
setTimeout(onAnimationFinish, 300);
|
||||
return;
|
||||
}
|
||||
|
||||
onAnimationFinish();
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(["scrollHelper"], function(scrollHelper) {
|
||||
var fn = on ? "on" : "off";
|
||||
scrollHelper.centerFocus[fn](elem, horiz)
|
||||
})
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function createDialog(options) {
|
||||
|
||||
options = options || {};
|
||||
var dlg = document.createElement("div");
|
||||
dlg.classList.add("focuscontainer"), dlg.classList.add("hide"), shouldLockDocumentScroll(options) && dlg.setAttribute("data-lockscroll", "true"), !1 !== options.enableHistory && appRouter.enableNativeHistory() && dlg.setAttribute("data-history", "true"), !1 !== options.modal && dlg.setAttribute("modal", "modal"), !1 !== options.autoFocus && dlg.setAttribute("data-autofocus", "true");
|
||||
var defaultEntryAnimation, defaultExitAnimation;
|
||||
defaultEntryAnimation = "scaleup", defaultExitAnimation = "scaledown";
|
||||
var entryAnimation = options.entryAnimation || defaultEntryAnimation,
|
||||
exitAnimation = options.exitAnimation || defaultExitAnimation,
|
||||
entryAnimationDuration = options.entryAnimationDuration || ("fullscreen" !== options.size ? 180 : 280),
|
||||
exitAnimationDuration = options.exitAnimationDuration || ("fullscreen" !== options.size ? 120 : 220);
|
||||
if (dlg.animationConfig = {
|
||||
entry: {
|
||||
name: entryAnimation,
|
||||
timing: {
|
||||
duration: entryAnimationDuration,
|
||||
easing: "ease-out"
|
||||
}
|
||||
},
|
||||
exit: {
|
||||
name: exitAnimation,
|
||||
timing: {
|
||||
duration: exitAnimationDuration,
|
||||
easing: "ease-out",
|
||||
fill: "both"
|
||||
}
|
||||
}
|
||||
}, dlg.classList.add("dialog"), options.scrollX ? (dlg.classList.add("scrollX"), dlg.classList.add("smoothScrollX"), layoutManager.tv && centerFocus(dlg, !0, !0)) : !1 !== options.scrollY && (dlg.classList.add("smoothScrollY"), layoutManager.tv && centerFocus(dlg, !1, !0)), options.removeOnClose && dlg.setAttribute("data-removeonclose", "true"), options.size && (dlg.classList.add("dialog-fixedSize"), dlg.classList.add("dialog-" + options.size)), enableAnimation()) switch (dlg.animationConfig.entry.name) {
|
||||
case "fadein":
|
||||
dlg.style.animation = "fadein " + entryAnimationDuration + "ms ease-out normal";
|
||||
break;
|
||||
case "scaleup":
|
||||
dlg.style.animation = "scaleup " + entryAnimationDuration + "ms ease-out normal both";
|
||||
break;
|
||||
case "slideup":
|
||||
dlg.style.animation = "slideup " + entryAnimationDuration + "ms ease-out normal";
|
||||
break;
|
||||
case "slidedown":
|
||||
dlg.style.animation = "slidedown " + entryAnimationDuration + "ms ease-out normal"
|
||||
|
||||
// If there's no native dialog support, use a plain div
|
||||
// Also not working well in samsung tizen browser, content inside not clickable
|
||||
// Just go ahead and always use a plain div because we're seeing issues overlaying absoltutely positioned content over a modal dialog
|
||||
var dlg = document.createElement('div');
|
||||
|
||||
dlg.classList.add('focuscontainer');
|
||||
dlg.classList.add('hide');
|
||||
|
||||
if (shouldLockDocumentScroll(options)) {
|
||||
dlg.setAttribute('data-lockscroll', 'true');
|
||||
}
|
||||
return dlg
|
||||
|
||||
if (options.enableHistory !== false && appRouter.enableNativeHistory()) {
|
||||
dlg.setAttribute('data-history', 'true');
|
||||
}
|
||||
|
||||
// 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 (options.modal !== false) {
|
||||
dlg.setAttribute('modal', 'modal');
|
||||
}
|
||||
|
||||
if (options.autoFocus !== false) {
|
||||
dlg.setAttribute('data-autofocus', 'true');
|
||||
}
|
||||
|
||||
var defaultEntryAnimation;
|
||||
var defaultExitAnimation;
|
||||
|
||||
defaultEntryAnimation = 'scaleup';
|
||||
defaultExitAnimation = 'scaledown';
|
||||
var entryAnimation = options.entryAnimation || defaultEntryAnimation;
|
||||
var exitAnimation = options.exitAnimation || defaultExitAnimation;
|
||||
|
||||
// If it's not fullscreen then lower the default animation speed to make it open really fast
|
||||
var entryAnimationDuration = options.entryAnimationDuration || (options.size !== 'fullscreen' ? 180 : 280);
|
||||
var exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220);
|
||||
|
||||
dlg.animationConfig = {
|
||||
// scale up
|
||||
'entry': {
|
||||
name: entryAnimation,
|
||||
timing: {
|
||||
duration: entryAnimationDuration,
|
||||
easing: 'ease-out'
|
||||
}
|
||||
},
|
||||
// fade out
|
||||
'exit': {
|
||||
name: exitAnimation,
|
||||
timing: {
|
||||
duration: exitAnimationDuration,
|
||||
easing: 'ease-out',
|
||||
fill: 'both'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
dlg.classList.add('dialog');
|
||||
|
||||
if (options.scrollX) {
|
||||
dlg.classList.add('scrollX');
|
||||
dlg.classList.add('smoothScrollX');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg, true, true);
|
||||
}
|
||||
}
|
||||
else if (options.scrollY !== false) {
|
||||
dlg.classList.add('smoothScrollY');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.removeOnClose) {
|
||||
dlg.setAttribute('data-removeonclose', 'true');
|
||||
}
|
||||
|
||||
if (options.size) {
|
||||
dlg.classList.add('dialog-fixedSize');
|
||||
dlg.classList.add('dialog-' + options.size);
|
||||
}
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
switch (dlg.animationConfig.entry.name) {
|
||||
|
||||
case 'fadein':
|
||||
dlg.style.animation = 'fadein ' + entryAnimationDuration + 'ms ease-out normal';
|
||||
break;
|
||||
case 'scaleup':
|
||||
dlg.style.animation = 'scaleup ' + entryAnimationDuration + 'ms ease-out normal both';
|
||||
break;
|
||||
case 'slideup':
|
||||
dlg.style.animation = 'slideup ' + entryAnimationDuration + 'ms ease-out normal';
|
||||
break;
|
||||
case 'slidedown':
|
||||
dlg.style.animation = 'slidedown ' + entryAnimationDuration + 'ms ease-out normal';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return dlg;
|
||||
}
|
||||
var globalOnOpenCallback, supportsOverscrollBehavior = "overscroll-behavior-y" in document.body.style;
|
||||
|
||||
return {
|
||||
open: open,
|
||||
close: close,
|
||||
createDialog: createDialog,
|
||||
setOnOpen: function(val) {
|
||||
globalOnOpenCallback = val
|
||||
setOnOpen: function (val) {
|
||||
globalOnOpenCallback = val;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,122 +1,343 @@
|
||||
define(["require", "browser", "layoutManager", "appSettings", "pluginManager", "apphost", "focusManager", "datetime", "globalize", "loading", "connectionManager", "skinManager", "dom", "events", "emby-select", "emby-checkbox", "emby-linkbutton"], function(require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) {
|
||||
define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-linkbutton'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) {
|
||||
"use strict";
|
||||
|
||||
function fillThemes(select, isDashboard) {
|
||||
select.innerHTML = skinManager.getThemes().map(function(t) {
|
||||
|
||||
select.innerHTML = skinManager.getThemes().map(function (t) {
|
||||
|
||||
var value = t.id;
|
||||
return t.isDefault && !isDashboard ? value = "" : t.isDefaultServerDashboard && isDashboard && (value = ""), '<option value="' + value + '">' + t.name + "</option>"
|
||||
}).join("")
|
||||
|
||||
if (t.isDefault && !isDashboard) {
|
||||
value = '';
|
||||
}
|
||||
else if (t.isDefaultServerDashboard && isDashboard) {
|
||||
value = '';
|
||||
}
|
||||
|
||||
return '<option value="' + value + '">' + t.name + '</option>';
|
||||
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function loadScreensavers(context, userSettings) {
|
||||
var selectScreensaver = context.querySelector(".selectScreensaver"),
|
||||
options = pluginManager.ofType("screensaver").map(function(plugin) {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
}
|
||||
});
|
||||
|
||||
var selectScreensaver = context.querySelector('.selectScreensaver');
|
||||
var options = pluginManager.ofType('screensaver').map(function (plugin) {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
options.unshift({
|
||||
name: globalize.translate("sharedcomponents#None"),
|
||||
value: "none"
|
||||
}), selectScreensaver.innerHTML = options.map(function(o) {
|
||||
return '<option value="' + o.value + '">' + o.name + "</option>"
|
||||
}).join(""), selectScreensaver.value = userSettings.screensaver(), selectScreensaver.value || (selectScreensaver.value = "none")
|
||||
name: globalize.translate('sharedcomponents#None'),
|
||||
value: 'none'
|
||||
});
|
||||
|
||||
selectScreensaver.innerHTML = options.map(function (o) {
|
||||
return '<option value="' + o.value + '">' + o.name + '</option>';
|
||||
}).join('');
|
||||
selectScreensaver.value = userSettings.screensaver();
|
||||
|
||||
if (!selectScreensaver.value) {
|
||||
// TODO: set the default instead of none
|
||||
selectScreensaver.value = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function loadSoundEffects(context, userSettings) {
|
||||
var selectSoundEffects = context.querySelector(".selectSoundEffects"),
|
||||
options = pluginManager.ofType("soundeffects").map(function(plugin) {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
}
|
||||
});
|
||||
|
||||
var selectSoundEffects = context.querySelector('.selectSoundEffects');
|
||||
var options = pluginManager.ofType('soundeffects').map(function (plugin) {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
options.unshift({
|
||||
name: globalize.translate("sharedcomponents#None"),
|
||||
value: "none"
|
||||
}), selectSoundEffects.innerHTML = options.map(function(o) {
|
||||
return '<option value="' + o.value + '">' + o.name + "</option>"
|
||||
}).join(""), selectSoundEffects.value = userSettings.soundEffects(), selectSoundEffects.value || (selectSoundEffects.value = "none")
|
||||
name: globalize.translate('sharedcomponents#None'),
|
||||
value: 'none'
|
||||
});
|
||||
|
||||
selectSoundEffects.innerHTML = options.map(function (o) {
|
||||
return '<option value="' + o.value + '">' + o.name + '</option>';
|
||||
}).join('');
|
||||
selectSoundEffects.value = userSettings.soundEffects();
|
||||
|
||||
if (!selectSoundEffects.value) {
|
||||
// TODO: set the default instead of none
|
||||
selectSoundEffects.value = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function loadSkins(context, userSettings) {
|
||||
var selectSkin = context.querySelector(".selectSkin"),
|
||||
options = pluginManager.ofType("skin").map(function(plugin) {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
}
|
||||
});
|
||||
selectSkin.innerHTML = options.map(function(o) {
|
||||
return '<option value="' + o.value + '">' + o.name + "</option>"
|
||||
}).join(""), selectSkin.value = userSettings.skin(), !selectSkin.value && options.length && (selectSkin.value = options[0].value), options.length > 1 && appHost.supports("skins") ? context.querySelector(".selectSkinContainer").classList.remove("hide") : context.querySelector(".selectSkinContainer").classList.add("hide")
|
||||
|
||||
var selectSkin = context.querySelector('.selectSkin');
|
||||
|
||||
var options = pluginManager.ofType('skin').map(function (plugin) {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
selectSkin.innerHTML = options.map(function (o) {
|
||||
return '<option value="' + o.value + '">' + o.name + '</option>';
|
||||
}).join('');
|
||||
selectSkin.value = userSettings.skin();
|
||||
|
||||
if (!selectSkin.value && options.length) {
|
||||
selectSkin.value = options[0].value;
|
||||
}
|
||||
|
||||
if (options.length > 1 && appHost.supports('skins')) {
|
||||
context.querySelector('.selectSkinContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectSkinContainer').classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function showOrHideMissingEpisodesField(context, user, apiClient) {
|
||||
if (browser.tizen || browser.web0s) return void context.querySelector(".fldDisplayMissingEpisodes").classList.add("hide");
|
||||
context.querySelector(".fldDisplayMissingEpisodes").classList.remove("hide")
|
||||
|
||||
if (browser.tizen || browser.web0s) {
|
||||
context.querySelector('.fldDisplayMissingEpisodes').classList.add('hide');
|
||||
return;
|
||||
}
|
||||
|
||||
context.querySelector('.fldDisplayMissingEpisodes').classList.remove('hide');
|
||||
}
|
||||
|
||||
function loadForm(context, user, userSettings, apiClient) {
|
||||
apiClient.getCurrentUserId(), user.Id;
|
||||
user.Policy.IsAdministrator ? context.querySelector(".selectDashboardThemeContainer").classList.remove("hide") : context.querySelector(".selectDashboardThemeContainer").classList.add("hide"), appHost.supports("displaylanguage") ? context.querySelector(".languageSection").classList.remove("hide") : context.querySelector(".languageSection").classList.add("hide"), appHost.supports("displaymode") ? context.querySelector(".fldDisplayMode").classList.remove("hide") : context.querySelector(".fldDisplayMode").classList.add("hide"), appHost.supports("externallinks") ? context.querySelector(".learnHowToContributeContainer").classList.remove("hide") : context.querySelector(".learnHowToContributeContainer").classList.add("hide"), appHost.supports("runatstartup") ? context.querySelector(".fldAutorun").classList.remove("hide") : context.querySelector(".fldAutorun").classList.add("hide"), appHost.supports("soundeffects") ? context.querySelector(".fldSoundEffects").classList.remove("hide") : context.querySelector(".fldSoundEffects").classList.add("hide"), appHost.supports("screensaver") ? context.querySelector(".selectScreensaverContainer").classList.remove("hide") : context.querySelector(".selectScreensaverContainer").classList.add("hide"), datetime.supportsLocalization() ? context.querySelector(".fldDateTimeLocale").classList.remove("hide") : context.querySelector(".fldDateTimeLocale").classList.add("hide"), browser.tizen || browser.web0s ? (context.querySelector(".fldSeasonalThemes").classList.add("hide"), context.querySelector(".fldBackdrops").classList.add("hide"), context.querySelector(".fldThemeSong").classList.add("hide"), context.querySelector(".fldThemeVideo").classList.add("hide")) : (context.querySelector(".fldSeasonalThemes").classList.remove("hide"), context.querySelector(".fldBackdrops").classList.remove("hide"), context.querySelector(".fldThemeSong").classList.remove("hide"), context.querySelector(".fldThemeVideo").classList.remove("hide")), context.querySelector(".chkRunAtStartup").checked = appSettings.runAtStartup();
|
||||
var selectTheme = context.querySelector("#selectTheme"),
|
||||
selectDashboardTheme = context.querySelector("#selectDashboardTheme");
|
||||
fillThemes(selectTheme), fillThemes(selectDashboardTheme, !0), loadScreensavers(context, userSettings), loadSoundEffects(context, userSettings), loadSkins(context, userSettings), context.querySelector(".chkDisplayMissingEpisodes").checked = user.Configuration.DisplayMissingEpisodes || !1, context.querySelector("#chkThemeSong").checked = userSettings.enableThemeSongs(), context.querySelector("#chkThemeVideo").checked = userSettings.enableThemeVideos(), context.querySelector("#chkBackdrops").checked = userSettings.enableBackdrops(), context.querySelector("#chkSeasonalThemes").checked = userSettings.enableSeasonalThemes(), context.querySelector("#selectLanguage").value = userSettings.language() || "", context.querySelector(".selectDateTimeLocale").value = userSettings.dateTimeLocale() || "", selectDashboardTheme.value = userSettings.dashboardTheme() || "", selectTheme.value = userSettings.theme() || "", context.querySelector(".selectLayout").value = layoutManager.getSavedLayout() || "", showOrHideMissingEpisodesField(context, user, apiClient), loading.hide()
|
||||
|
||||
var loggedInUserId = apiClient.getCurrentUserId();
|
||||
var userId = user.Id;
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
context.querySelector('.selectDashboardThemeContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectDashboardThemeContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('displaylanguage')) {
|
||||
context.querySelector('.languageSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.languageSection').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('displaymode')) {
|
||||
context.querySelector('.fldDisplayMode').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldDisplayMode').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
context.querySelector('.learnHowToContributeContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.learnHowToContributeContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('runatstartup')) {
|
||||
context.querySelector('.fldAutorun').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldAutorun').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('soundeffects')) {
|
||||
context.querySelector('.fldSoundEffects').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldSoundEffects').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('screensaver')) {
|
||||
context.querySelector('.selectScreensaverContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectScreensaverContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (datetime.supportsLocalization()) {
|
||||
context.querySelector('.fldDateTimeLocale').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldDateTimeLocale').classList.add('hide');
|
||||
}
|
||||
|
||||
if (!browser.tizen && !browser.web0s) {
|
||||
context.querySelector('.fldSeasonalThemes').classList.remove('hide');
|
||||
context.querySelector('.fldBackdrops').classList.remove('hide');
|
||||
context.querySelector('.fldThemeSong').classList.remove('hide');
|
||||
context.querySelector('.fldThemeVideo').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldSeasonalThemes').classList.add('hide');
|
||||
context.querySelector('.fldBackdrops').classList.add('hide');
|
||||
context.querySelector('.fldThemeSong').classList.add('hide');
|
||||
context.querySelector('.fldThemeVideo').classList.add('hide');
|
||||
}
|
||||
|
||||
context.querySelector('.chkRunAtStartup').checked = appSettings.runAtStartup();
|
||||
|
||||
var selectTheme = context.querySelector('#selectTheme');
|
||||
var selectDashboardTheme = context.querySelector('#selectDashboardTheme');
|
||||
|
||||
fillThemes(selectTheme);
|
||||
fillThemes(selectDashboardTheme, true);
|
||||
loadScreensavers(context, userSettings);
|
||||
loadSoundEffects(context, userSettings);
|
||||
loadSkins(context, userSettings);
|
||||
|
||||
context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false;
|
||||
|
||||
context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs();
|
||||
context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos();
|
||||
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
|
||||
context.querySelector('#chkSeasonalThemes').checked = userSettings.enableSeasonalThemes();
|
||||
|
||||
context.querySelector('#selectLanguage').value = userSettings.language() || '';
|
||||
context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || '';
|
||||
|
||||
selectDashboardTheme.value = userSettings.dashboardTheme() || '';
|
||||
selectTheme.value = userSettings.theme() || '';
|
||||
|
||||
context.querySelector('.selectLayout').value = layoutManager.getSavedLayout() || '';
|
||||
|
||||
showOrHideMissingEpisodesField(context, user, apiClient);
|
||||
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
return appSettings.runAtStartup(context.querySelector(".chkRunAtStartup").checked), user.Configuration.DisplayMissingEpisodes = context.querySelector(".chkDisplayMissingEpisodes").checked, appHost.supports("displaylanguage") && userSettingsInstance.language(context.querySelector("#selectLanguage").value), userSettingsInstance.dateTimeLocale(context.querySelector(".selectDateTimeLocale").value), userSettingsInstance.enableThemeSongs(context.querySelector("#chkThemeSong").checked), userSettingsInstance.enableThemeVideos(context.querySelector("#chkThemeVideo").checked), userSettingsInstance.dashboardTheme(context.querySelector("#selectDashboardTheme").value), userSettingsInstance.theme(context.querySelector("#selectTheme").value), userSettingsInstance.soundEffects(context.querySelector(".selectSoundEffects").value), userSettingsInstance.screensaver(context.querySelector(".selectScreensaver").value), userSettingsInstance.skin(context.querySelector(".selectSkin").value), userSettingsInstance.enableBackdrops(context.querySelector("#chkBackdrops").checked), userSettingsInstance.enableSeasonalThemes(context.querySelector("#chkSeasonalThemes").checked), user.Id === apiClient.getCurrentUserId() && skinManager.setTheme(userSettingsInstance.theme()), layoutManager.setLayout(context.querySelector(".selectLayout").value), apiClient.updateUserConfiguration(user.Id, user.Configuration)
|
||||
|
||||
appSettings.runAtStartup(context.querySelector('.chkRunAtStartup').checked);
|
||||
|
||||
user.Configuration.DisplayMissingEpisodes = context.querySelector('.chkDisplayMissingEpisodes').checked;
|
||||
|
||||
if (appHost.supports('displaylanguage')) {
|
||||
userSettingsInstance.language(context.querySelector('#selectLanguage').value);
|
||||
}
|
||||
|
||||
userSettingsInstance.dateTimeLocale(context.querySelector('.selectDateTimeLocale').value);
|
||||
|
||||
userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked);
|
||||
userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked);
|
||||
userSettingsInstance.dashboardTheme(context.querySelector('#selectDashboardTheme').value);
|
||||
userSettingsInstance.theme(context.querySelector('#selectTheme').value);
|
||||
userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value);
|
||||
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
|
||||
|
||||
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
|
||||
|
||||
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
||||
userSettingsInstance.enableSeasonalThemes(context.querySelector('#chkSeasonalThemes').checked);
|
||||
|
||||
if (user.Id === apiClient.getCurrentUserId()) {
|
||||
|
||||
skinManager.setTheme(userSettingsInstance.theme());
|
||||
}
|
||||
|
||||
layoutManager.setLayout(context.querySelector('.selectLayout').value);
|
||||
|
||||
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
|
||||
}
|
||||
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
loading.show(), apiClient.getUser(userId).then(function(user) {
|
||||
saveUser(context, user, userSettings, apiClient).then(function() {
|
||||
loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) {
|
||||
toast(globalize.translate("sharedcomponents#SettingsSaved"))
|
||||
}), events.trigger(instance, "saved")
|
||||
}, function() {
|
||||
loading.hide()
|
||||
})
|
||||
})
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(function (user) {
|
||||
|
||||
saveUser(context, user, userSettings, apiClient).then(function () {
|
||||
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('sharedcomponents#SettingsSaved'));
|
||||
});
|
||||
}
|
||||
|
||||
events.trigger(instance, 'saved');
|
||||
|
||||
}, function () {
|
||||
loading.hide();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
var self = this,
|
||||
apiClient = connectionManager.getApiClient(self.options.serverId),
|
||||
userId = self.options.userId,
|
||||
userSettings = self.options.userSettings;
|
||||
return userSettings.setUserInfo(userId, apiClient).then(function() {
|
||||
|
||||
var self = this;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userId = self.options.userId;
|
||||
var userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
|
||||
var enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation)
|
||||
}), e && e.preventDefault(), !1
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
|
||||
// Disable default form submission
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function embed(options, self) {
|
||||
require(["text!./displaysettings.template.html"], function(template) {
|
||||
options.element.innerHTML = globalize.translateDocument(template, "sharedcomponents"), options.element.querySelector("form").addEventListener("submit", onSubmit.bind(self)), options.enableSaveButton && options.element.querySelector(".btnSave").classList.remove("hide"), self.loadData(options.autoFocus)
|
||||
})
|
||||
|
||||
require(['text!./displaysettings.template.html'], function (template) {
|
||||
|
||||
options.element.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||
|
||||
if (options.enableSaveButton) {
|
||||
options.element.querySelector('.btnSave').classList.remove('hide');
|
||||
}
|
||||
|
||||
self.loadData(options.autoFocus);
|
||||
});
|
||||
}
|
||||
|
||||
function DisplaySettings(options) {
|
||||
this.options = options, embed(options, this)
|
||||
|
||||
this.options = options;
|
||||
|
||||
embed(options, this);
|
||||
}
|
||||
return DisplaySettings.prototype.loadData = function(autoFocus) {
|
||||
var self = this,
|
||||
context = self.options.element;
|
||||
|
||||
DisplaySettings.prototype.loadData = function (autoFocus) {
|
||||
|
||||
var self = this;
|
||||
var context = self.options.element;
|
||||
|
||||
loading.show();
|
||||
var userId = self.options.userId,
|
||||
apiClient = connectionManager.getApiClient(self.options.serverId),
|
||||
userSettings = self.options.userSettings;
|
||||
return apiClient.getUser(userId).then(function(user) {
|
||||
return userSettings.setUserInfo(userId, apiClient).then(function() {
|
||||
self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient), autoFocus && focusManager.autoFocus(context)
|
||||
})
|
||||
})
|
||||
}, DisplaySettings.prototype.submit = function() {
|
||||
onSubmit.call(this)
|
||||
}, DisplaySettings.prototype.destroy = function() {
|
||||
this.options = null
|
||||
}, DisplaySettings
|
||||
|
||||
var userId = self.options.userId;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userSettings = self.options.userSettings;
|
||||
|
||||
return apiClient.getUser(userId).then(function (user) {
|
||||
|
||||
return userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
|
||||
if (autoFocus) {
|
||||
focusManager.autoFocus(context);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
DisplaySettings.prototype.submit = function () {
|
||||
onSubmit.call(this);
|
||||
};
|
||||
|
||||
DisplaySettings.prototype.destroy = function () {
|
||||
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return DisplaySettings;
|
||||
});
|
||||
@@ -55,7 +55,7 @@
|
||||
<div class="fieldDescription">
|
||||
<div>${LabelDisplayLanguageHelp}</div>
|
||||
<div class="learnHowToContributeContainer hide" style="margin-top: .25em;">
|
||||
<a is="emby-linkbutton" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">${LearnHowYouCanContribute}</a>
|
||||
<a is="emby-linkbutton" class="button-link" href="http://emby.media/community/index.php?/topic/5727-join-our-translation-team" target="_blank">${LearnHowYouCanContribute}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,6 +127,7 @@
|
||||
|
||||
<div class="selectContainer">
|
||||
<select id="selectTheme" is="emby-select" label="${LabelTheme}"></select>
|
||||
<div class="fieldDescription">${FeatureRequiresEmbyPremiere}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldSeasonalThemes hide">
|
||||
@@ -139,6 +140,7 @@
|
||||
|
||||
<div class="selectContainer selectDashboardThemeContainer hide">
|
||||
<select id="selectDashboardTheme" is="emby-select" label="${LabelDashboardTheme}"></select>
|
||||
<div class="fieldDescription">${FeatureRequiresEmbyPremiere}</div>
|
||||
</div>
|
||||
<div class="selectContainer hide selectScreensaverContainer">
|
||||
<select is="emby-select" class="selectScreensaver" label="${LabelScreensaver}"></select>
|
||||
@@ -188,4 +190,4 @@
|
||||
<button is="emby-button" type="submit" class="raised button-submit block btnSave hide">
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
</form>
|
||||
</form>
|
||||
192
src/bower_components/emby-webcomponents/dom.js
vendored
192
src/bower_components/emby-webcomponents/dom.js
vendored
@@ -1,96 +1,170 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function parentWithAttribute(elem, name, value) {
|
||||
for (; value ? elem.getAttribute(name) !== value : !elem.getAttribute(name);)
|
||||
if (!(elem = elem.parentNode) || !elem.getAttribute) return null;
|
||||
return elem
|
||||
|
||||
while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem || !elem.getAttribute) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function parentWithTag(elem, tagNames) {
|
||||
for (Array.isArray(tagNames) || (tagNames = [tagNames]); - 1 === tagNames.indexOf(elem.tagName || "");)
|
||||
if (!(elem = elem.parentNode)) return null;
|
||||
return elem
|
||||
|
||||
// accept both string and array passed in
|
||||
if (!Array.isArray(tagNames)) {
|
||||
tagNames = [tagNames];
|
||||
}
|
||||
|
||||
while (tagNames.indexOf(elem.tagName || '') === -1) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function containsAnyClass(classList, classNames) {
|
||||
for (var i = 0, length = classNames.length; i < length; i++)
|
||||
if (classList.contains(classNames[i])) return !0;
|
||||
return !1
|
||||
|
||||
for (var i = 0, length = classNames.length; i < length; i++) {
|
||||
if (classList.contains(classNames[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function parentWithClass(elem, classNames) {
|
||||
for (Array.isArray(classNames) || (classNames = [classNames]); !elem.classList || !containsAnyClass(elem.classList, classNames);)
|
||||
if (!(elem = elem.parentNode)) return null;
|
||||
return elem
|
||||
|
||||
// accept both string and array passed in
|
||||
if (!Array.isArray(classNames)) {
|
||||
classNames = [classNames];
|
||||
}
|
||||
|
||||
while (!elem.classList || !containsAnyClass(elem.classList, classNames)) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
var supportsCaptureOption = false;
|
||||
try {
|
||||
var opts = Object.defineProperty({}, 'capture', {
|
||||
get: function () {
|
||||
supportsCaptureOption = true;
|
||||
}
|
||||
});
|
||||
window.addEventListener("test", null, opts);
|
||||
} catch (e) { }
|
||||
|
||||
function addEventListenerWithOptions(target, type, handler, options) {
|
||||
var optionsOrCapture = options;
|
||||
supportsCaptureOption || (optionsOrCapture = options.capture), target.addEventListener(type, handler, optionsOrCapture)
|
||||
if (!supportsCaptureOption) {
|
||||
optionsOrCapture = options.capture;
|
||||
}
|
||||
target.addEventListener(type, handler, optionsOrCapture);
|
||||
}
|
||||
|
||||
function removeEventListenerWithOptions(target, type, handler, options) {
|
||||
var optionsOrCapture = options;
|
||||
supportsCaptureOption || (optionsOrCapture = options.capture), target.removeEventListener(type, handler, optionsOrCapture)
|
||||
if (!supportsCaptureOption) {
|
||||
optionsOrCapture = options.capture;
|
||||
}
|
||||
target.removeEventListener(type, handler, optionsOrCapture);
|
||||
}
|
||||
|
||||
var windowSize;
|
||||
var windowSizeEventsBound;
|
||||
function clearWindowSize() {
|
||||
windowSize = null
|
||||
windowSize = null;
|
||||
}
|
||||
|
||||
function getWindowSize() {
|
||||
return windowSize || (windowSize = {
|
||||
innerHeight: window.innerHeight,
|
||||
innerWidth: window.innerWidth
|
||||
}, windowSizeEventsBound || (windowSizeEventsBound = !0, addEventListenerWithOptions(window, "orientationchange", clearWindowSize, {
|
||||
passive: !0
|
||||
}), addEventListenerWithOptions(window, "resize", clearWindowSize, {
|
||||
passive: !0
|
||||
}))), windowSize
|
||||
if (!windowSize) {
|
||||
windowSize = {
|
||||
innerHeight: window.innerHeight,
|
||||
innerWidth: window.innerWidth
|
||||
};
|
||||
|
||||
if (!windowSizeEventsBound) {
|
||||
windowSizeEventsBound = true;
|
||||
addEventListenerWithOptions(window, "orientationchange", clearWindowSize, { passive: true });
|
||||
addEventListenerWithOptions(window, 'resize', clearWindowSize, { passive: true });
|
||||
}
|
||||
}
|
||||
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
var _animationEvent;
|
||||
function whichAnimationEvent() {
|
||||
if (_animationEvent) return _animationEvent;
|
||||
var t, el = document.createElement("div"),
|
||||
animations = {
|
||||
animation: "animationend",
|
||||
OAnimation: "oAnimationEnd",
|
||||
MozAnimation: "animationend",
|
||||
WebkitAnimation: "webkitAnimationEnd"
|
||||
};
|
||||
for (t in animations)
|
||||
if (void 0 !== el.style[t]) return _animationEvent = animations[t], animations[t];
|
||||
return _animationEvent = "animationend"
|
||||
|
||||
if (_animationEvent) {
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
var t,
|
||||
el = document.createElement("div");
|
||||
var animations = {
|
||||
"animation": "animationend",
|
||||
"OAnimation": "oAnimationEnd",
|
||||
"MozAnimation": "animationend",
|
||||
"WebkitAnimation": "webkitAnimationEnd"
|
||||
};
|
||||
for (t in animations) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_animationEvent = animations[t];
|
||||
return animations[t];
|
||||
}
|
||||
}
|
||||
|
||||
_animationEvent = 'animationend';
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
function whichAnimationCancelEvent() {
|
||||
return whichAnimationEvent().replace("animationend", "animationcancel").replace("AnimationEnd", "AnimationCancel")
|
||||
|
||||
return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel');
|
||||
}
|
||||
|
||||
var _transitionEvent;
|
||||
function whichTransitionEvent() {
|
||||
if (_transitionEvent) return _transitionEvent;
|
||||
var t, el = document.createElement("div"),
|
||||
transitions = {
|
||||
transition: "transitionend",
|
||||
OTransition: "oTransitionEnd",
|
||||
MozTransition: "transitionend",
|
||||
WebkitTransition: "webkitTransitionEnd"
|
||||
};
|
||||
for (t in transitions)
|
||||
if (void 0 !== el.style[t]) return _transitionEvent = transitions[t], transitions[t];
|
||||
return _transitionEvent = "transitionend"
|
||||
}
|
||||
var supportsCaptureOption = !1;
|
||||
try {
|
||||
var opts = Object.defineProperty({}, "capture", {
|
||||
get: function() {
|
||||
supportsCaptureOption = !0
|
||||
if (_transitionEvent) {
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
var t,
|
||||
el = document.createElement("div");
|
||||
var transitions = {
|
||||
"transition": "transitionend",
|
||||
"OTransition": "oTransitionEnd",
|
||||
"MozTransition": "transitionend",
|
||||
"WebkitTransition": "webkitTransitionEnd"
|
||||
};
|
||||
for (t in transitions) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_transitionEvent = transitions[t];
|
||||
return transitions[t];
|
||||
}
|
||||
});
|
||||
window.addEventListener("test", null, opts)
|
||||
} catch (e) {}
|
||||
var windowSize, windowSizeEventsBound, _animationEvent, _transitionEvent;
|
||||
}
|
||||
|
||||
_transitionEvent = 'transitionend';
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
return {
|
||||
parentWithAttribute: parentWithAttribute,
|
||||
parentWithClass: parentWithClass,
|
||||
@@ -101,5 +175,5 @@ define([], function() {
|
||||
whichTransitionEvent: whichTransitionEvent,
|
||||
whichAnimationEvent: whichAnimationEvent,
|
||||
whichAnimationCancelEvent: whichAnimationCancelEvent
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,33 +1,14 @@
|
||||
.emby-button,
|
||||
.fab {
|
||||
-webkit-box-sizing: border-box;
|
||||
-webkit-box-align: center
|
||||
}
|
||||
|
||||
.button-flat,
|
||||
.button-link {
|
||||
background: 0 0
|
||||
}
|
||||
|
||||
.emby-button,
|
||||
.paper-icon-button-light {
|
||||
text-align: center;
|
||||
font-family: inherit;
|
||||
color: inherit;
|
||||
outline: 0 !important;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
position: relative
|
||||
}
|
||||
|
||||
.emby-button {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
margin: 0 .29em;
|
||||
text-align: center;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
color: inherit;
|
||||
outline-width: 0;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
@@ -35,99 +16,98 @@
|
||||
cursor: pointer;
|
||||
z-index: 0;
|
||||
padding: .86em 1em;
|
||||
vertical-align: middle;
|
||||
border: 0;
|
||||
vertical-align: middle;
|
||||
-webkit-border-radius: .2em;
|
||||
border-radius: .2em;
|
||||
/* These are getting an outline in opera tv browsers, which run chrome 30 */
|
||||
outline: none !important;
|
||||
position: relative;
|
||||
font-weight: 600;
|
||||
/* Disable webkit tap highlighting */
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
text-decoration: none;
|
||||
line-height: 1.35
|
||||
|
||||
/* Not crazy about this but it normalizes heights between anchors and buttons */
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.emby-button::-moz-focus-inner {
|
||||
border: 0
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.button-flat:hover {
|
||||
opacity: .5
|
||||
.button-flat {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.button-flat:hover {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.button-link {
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
vertical-align: initial
|
||||
vertical-align: initial;
|
||||
}
|
||||
|
||||
.button-link-inline {
|
||||
display: inline
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.button-link:hover {
|
||||
text-decoration: underline
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.emby-button-focusscale {
|
||||
-webkit-transition: -webkit-transform 180ms ease-out !important;
|
||||
-o-transition: transform 180ms ease-out !important;
|
||||
transition: transform 180ms ease-out !important;
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.emby-button-focusscale:focus {
|
||||
-webkit-transform: scale(1.16);
|
||||
transform: scale(1.16);
|
||||
z-index: 1
|
||||
.emby-button-focusscale:focus {
|
||||
transform: scale(1.16);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.emby-button > i {
|
||||
/* For non-fab buttons that have icons */
|
||||
font-size: 1.36em;
|
||||
}
|
||||
|
||||
.emby-button>i {
|
||||
font-size: 1.36em
|
||||
}
|
||||
|
||||
.button-link>i {
|
||||
font-size: 1em
|
||||
.button-link > i {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.fab {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
padding: .6em;
|
||||
box-sizing: border-box;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
text-align: center
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.emby-button.block {
|
||||
display: block;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
margin: .25em 0;
|
||||
width: 100%
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.paper-icon-button-light {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin: 0 .29em;
|
||||
background: 0 0;
|
||||
background: transparent;
|
||||
text-align: center;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
color: inherit;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
@@ -139,84 +119,82 @@
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding: .556em;
|
||||
vertical-align: middle;
|
||||
border: 0;
|
||||
vertical-align: middle;
|
||||
/* These are getting an outline in opera tv browsers, which run chrome 30 */
|
||||
outline: none !important;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center
|
||||
/* Disable webkit tap highlighting */
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.paper-icon-button-light::-moz-focus-inner {
|
||||
border: 0
|
||||
}
|
||||
.paper-icon-button-light::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.paper-icon-button-light[disabled] {
|
||||
opacity: .3
|
||||
}
|
||||
.paper-icon-button-light[disabled] {
|
||||
opacity: .3;
|
||||
}
|
||||
|
||||
.paper-icon-button-light>i {
|
||||
font-size: 1.66956521739130434em;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle
|
||||
}
|
||||
.paper-icon-button-light > i {
|
||||
font-size: 1.66956521739130434em;
|
||||
/* Make sure its on top of the ripple */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.paper-icon-button-light>img {
|
||||
width: 1.72em;
|
||||
max-height: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle
|
||||
}
|
||||
.paper-icon-button-light > img {
|
||||
width: 1.72em;
|
||||
/* Can't use 100% height or it will stretch past the boundaries in safari */
|
||||
/*height: 100%;*/
|
||||
max-height: 100%;
|
||||
/* Make sure its on top of the ripple */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.emby-button-foreground {
|
||||
position: relative;
|
||||
z-index: 1
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.icon-button-focusscale {
|
||||
-webkit-transition: -webkit-transform 180ms ease-out !important;
|
||||
-o-transition: transform 180ms ease-out !important;
|
||||
transition: transform 180ms ease-out !important;
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.icon-button-focusscale:focus {
|
||||
-webkit-transform: scale(1.3);
|
||||
transform: scale(1.3);
|
||||
z-index: 1
|
||||
}
|
||||
.icon-button-focusscale:focus {
|
||||
transform: scale(1.3);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.btnFilterWithBubble {
|
||||
position: relative
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.filterButtonBubble {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
background: #444;
|
||||
top: 0;
|
||||
right: 0;
|
||||
/* padding: .5em; */
|
||||
width: 1.6em;
|
||||
height: 1.6em;
|
||||
z-index: 100000000;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
font-size: 82%;
|
||||
-webkit-border-radius: 100em;
|
||||
border-radius: 100em;
|
||||
-webkit-box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2);
|
||||
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2);
|
||||
box-shadow: 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12), 0px 2px 4px -1px rgba(0, 0, 0, 0.2);
|
||||
background: #03A9F4;
|
||||
font-weight: 700
|
||||
}
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,99 @@
|
||||
define(["browser", "dom", "layoutManager", "shell", "appRouter", "apphost", "css!./emby-button", "registerElement"], function(browser, dom, layoutManager, shell, appRouter, appHost) {
|
||||
"use strict";
|
||||
define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css!./emby-button', 'registerElement'], function (browser, dom, layoutManager, shell, appRouter, appHost) {
|
||||
'use strict';
|
||||
|
||||
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
|
||||
var EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype);
|
||||
|
||||
function openPremiumInfo() {
|
||||
require(["registrationServices"], function(registrationServices) {
|
||||
registrationServices.showPremiereInfo()
|
||||
})
|
||||
|
||||
require(['registrationServices'], function (registrationServices) {
|
||||
registrationServices.showPremiereInfo();
|
||||
});
|
||||
}
|
||||
|
||||
function onAnchorClick(e) {
|
||||
var href = this.getAttribute("href") || "";
|
||||
"#" !== href ? this.getAttribute("target") ? -1 === href.indexOf("emby.media/premiere") || appHost.supports("externalpremium") ? appHost.supports("targetblank") || (e.preventDefault(), shell.openUrl(href)) : (e.preventDefault(), openPremiumInfo()) : appRouter.handleAnchorClick(e) : e.preventDefault()
|
||||
|
||||
var href = this.getAttribute('href') || '';
|
||||
|
||||
if (href !== '#') {
|
||||
|
||||
if (this.getAttribute('target')) {
|
||||
if (href.indexOf('emby.media/premiere') !== -1 && !appHost.supports('externalpremium')) {
|
||||
e.preventDefault();
|
||||
openPremiumInfo();
|
||||
}
|
||||
else if (!appHost.supports('targetblank')) {
|
||||
e.preventDefault();
|
||||
shell.openUrl(href);
|
||||
}
|
||||
} else {
|
||||
appRouter.handleAnchorClick(e);
|
||||
}
|
||||
} else {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype),
|
||||
EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype);
|
||||
return EmbyButtonPrototype.createdCallback = function() {
|
||||
this.classList.contains("emby-button") || (this.classList.add("emby-button"), browser.firefox && this.classList.add("button-link-inline"), layoutManager.tv && ("false" !== this.getAttribute("data-focusscale") && this.classList.add("emby-button-focusscale"), this.classList.add("emby-button-tv")))
|
||||
}, EmbyButtonPrototype.attachedCallback = function() {
|
||||
"A" === this.tagName && (dom.removeEventListener(this, "click", onAnchorClick, {}), dom.addEventListener(this, "click", onAnchorClick, {}), "true" === this.getAttribute("data-autohide") && (appHost.supports("externallinks") ? this.classList.remove("hide") : this.classList.add("hide")))
|
||||
}, EmbyButtonPrototype.detachedCallback = function() {
|
||||
dom.removeEventListener(this, "click", onAnchorClick, {})
|
||||
}, EmbyLinkButtonPrototype.createdCallback = EmbyButtonPrototype.createdCallback, EmbyLinkButtonPrototype.attachedCallback = EmbyButtonPrototype.attachedCallback, document.registerElement("emby-button", {
|
||||
|
||||
EmbyButtonPrototype.createdCallback = function () {
|
||||
|
||||
if (this.classList.contains('emby-button')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classList.add('emby-button');
|
||||
|
||||
if (browser.firefox) {
|
||||
// a ff hack is needed for vertical alignment
|
||||
this.classList.add('button-link-inline');
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
if (this.getAttribute('data-focusscale') !== 'false') {
|
||||
this.classList.add('emby-button-focusscale');
|
||||
}
|
||||
this.classList.add('emby-button-tv');
|
||||
}
|
||||
};
|
||||
|
||||
EmbyButtonPrototype.attachedCallback = function () {
|
||||
|
||||
if (this.tagName === 'A') {
|
||||
|
||||
dom.removeEventListener(this, 'click', onAnchorClick, {
|
||||
});
|
||||
|
||||
dom.addEventListener(this, 'click', onAnchorClick, {
|
||||
});
|
||||
|
||||
if (this.getAttribute('data-autohide') === 'true') {
|
||||
if (appHost.supports('externallinks')) {
|
||||
this.classList.remove('hide');
|
||||
} else {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EmbyButtonPrototype.detachedCallback = function () {
|
||||
|
||||
dom.removeEventListener(this, 'click', onAnchorClick, {
|
||||
});
|
||||
};
|
||||
|
||||
EmbyLinkButtonPrototype.createdCallback = EmbyButtonPrototype.createdCallback;
|
||||
EmbyLinkButtonPrototype.attachedCallback = EmbyButtonPrototype.attachedCallback;
|
||||
|
||||
document.registerElement('emby-button', {
|
||||
prototype: EmbyButtonPrototype,
|
||||
extends: "button"
|
||||
}), document.registerElement("emby-linkbutton", {
|
||||
extends: 'button'
|
||||
});
|
||||
|
||||
document.registerElement('emby-linkbutton', {
|
||||
prototype: EmbyLinkButtonPrototype,
|
||||
extends: "a"
|
||||
}), EmbyButtonPrototype
|
||||
extends: 'a'
|
||||
});
|
||||
|
||||
// For extension purposes
|
||||
return EmbyButtonPrototype;
|
||||
});
|
||||
@@ -1,10 +1,19 @@
|
||||
define(["layoutManager", "css!./emby-button", "registerElement"], function(layoutManager) {
|
||||
"use strict";
|
||||
define(['layoutManager', 'css!./emby-button', 'registerElement'], function (layoutManager) {
|
||||
'use strict';
|
||||
|
||||
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
|
||||
EmbyButtonPrototype.createdCallback = function() {
|
||||
this.classList.add("paper-icon-button-light"), layoutManager.tv && this.classList.add("icon-button-focusscale")
|
||||
}, document.registerElement("paper-icon-button-light", {
|
||||
|
||||
EmbyButtonPrototype.createdCallback = function () {
|
||||
|
||||
this.classList.add('paper-icon-button-light');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('icon-button-focusscale');
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('paper-icon-button-light', {
|
||||
prototype: EmbyButtonPrototype,
|
||||
extends: "button"
|
||||
})
|
||||
extends: 'button'
|
||||
});
|
||||
});
|
||||
@@ -2,45 +2,37 @@
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0 0 0 2.4em;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
padding: 0;
|
||||
padding-left: 2.4em;
|
||||
align-items: center;
|
||||
height: 2.35em;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.checkboxContainer,
|
||||
.checkboxListContainer {
|
||||
margin-bottom: 1.8em
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkboxFieldDescription {
|
||||
padding-left: 2.4em
|
||||
padding-left: 2.4em;
|
||||
}
|
||||
|
||||
.checkboxContainer {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex
|
||||
margin-bottom: 1.8em;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.checkboxListContainer {
|
||||
margin-bottom: 1.8em;
|
||||
}
|
||||
|
||||
.checkboxContainer-withDescription {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.emby-checkbox {
|
||||
position: absolute;
|
||||
/* This is for focusing purposes, so the focusManager doesn't skip over it */
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: 0;
|
||||
@@ -50,112 +42,109 @@
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
border: none
|
||||
border: none;
|
||||
}
|
||||
|
||||
.checkboxOutline {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
width: 1.83em;
|
||||
height: 1.83em;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
border: 2px solid currentcolor;
|
||||
-webkit-border-radius: .14em;
|
||||
border-radius: .14em;
|
||||
z-index: 2;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Commenting this out - set by theme */
|
||||
/*.emby-checkbox:checked + span + span + .checkboxOutline {
|
||||
border-color: #52B54B;
|
||||
}*/
|
||||
|
||||
.emby-checkbox-focushelper {
|
||||
position: absolute;
|
||||
top: -.915em;
|
||||
left: -.915em;
|
||||
top: -0.915em;
|
||||
left: -0.915em;
|
||||
width: 3.66em;
|
||||
height: 3.66em;
|
||||
display: inline-block;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin: 3px 0 0;
|
||||
-webkit-border-radius: 50%;
|
||||
margin: 3px 0 0 0;
|
||||
border-radius: 50%;
|
||||
background-color: transparent
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Commenting this out - set by theme */
|
||||
/*.emby-checkbox:focus + span + .emby-checkbox-focushelper {
|
||||
background-color: rgba(82, 181, 75, 0.26);
|
||||
}*/
|
||||
|
||||
.checkboxIcon {
|
||||
font-size: 1.6em;
|
||||
color: #fff
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.checkboxIcon-checked {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
.emby-checkbox:checked+span+span+.checkboxOutline>.checkboxIcon-checked {
|
||||
display: -webkit-box !important;
|
||||
display: -webkit-flex !important;
|
||||
display: flex !important
|
||||
.emby-checkbox:checked + span + span + .checkboxOutline > .checkboxIcon-checked {
|
||||
/* background-color set by theme */
|
||||
/*background-color: #52B54B;*/
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.emby-checkbox:checked+span+span+.checkboxOutline>.checkboxIcon-unchecked {
|
||||
display: none !important
|
||||
.emby-checkbox:checked + span + span + .checkboxOutline > .checkboxIcon-unchecked {
|
||||
/* background-color set by theme */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.emby-checkbox:checked[disabled]+span+span+.checkboxOutline>.checkboxIcon {
|
||||
background-color: rgba(0, 0, 0, .26)
|
||||
.emby-checkbox:checked[disabled] + span + span + .checkboxOutline > .checkboxIcon {
|
||||
background-color: rgba(0, 0, 0, 0.26);
|
||||
}
|
||||
|
||||
.checkboxLabel {
|
||||
position: relative;
|
||||
margin: 0
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.checkboxList>.emby-checkbox-label {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
.checkboxList > .emby-checkbox-label {
|
||||
display: flex;
|
||||
margin: .5em 0
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
.checkboxList-verticalwrap {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.checkboxList-verticalwrap>.emby-checkbox-label {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex;
|
||||
margin: .3em 0;
|
||||
width: 12em
|
||||
}
|
||||
.checkboxList-verticalwrap > .emby-checkbox-label {
|
||||
display: inline-flex;
|
||||
margin: .3em 0 .3em 0;
|
||||
width: 12em;
|
||||
}
|
||||
|
||||
.checkboxList-paperList {
|
||||
padding: 1em !important
|
||||
padding: 1em !important;
|
||||
}
|
||||
|
||||
.checkboxListLabel {
|
||||
margin-bottom: .25em
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
@-webkit-keyframes repaintChrome {
|
||||
|
||||
from,
|
||||
to {
|
||||
padding: 0
|
||||
from {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
to {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,110 @@
|
||||
define(["browser", "dom", "css!./emby-checkbox", "registerElement"], function(browser, dom) {
|
||||
"use strict";
|
||||
define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (browser, dom) {
|
||||
'use strict';
|
||||
|
||||
var EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (13 === e.keyCode) return e.preventDefault(), this.checked = !this.checked, this.dispatchEvent(new CustomEvent("change", {
|
||||
bubbles: !0
|
||||
})), !1
|
||||
|
||||
// Don't submit form on enter
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
|
||||
this.checked = !this.checked;
|
||||
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s ? true : false;
|
||||
|
||||
function forceRefresh(loading) {
|
||||
|
||||
var elem = this.parentNode;
|
||||
elem.style.webkitAnimationName = "repaintChrome", elem.style.webkitAnimationDelay = !0 === loading ? "500ms" : "", elem.style.webkitAnimationDuration = "10ms", elem.style.webkitAnimationIterationCount = "1", setTimeout(function() {
|
||||
elem.style.webkitAnimationName = ""
|
||||
}, !0 === loading ? 520 : 20)
|
||||
|
||||
elem.style.webkitAnimationName = 'repaintChrome';
|
||||
elem.style.webkitAnimationDelay = (loading === true ? '500ms' : '');
|
||||
elem.style.webkitAnimationDuration = '10ms';
|
||||
elem.style.webkitAnimationIterationCount = '1';
|
||||
|
||||
setTimeout(function () {
|
||||
elem.style.webkitAnimationName = '';
|
||||
}, (loading === true ? 520 : 20));
|
||||
}
|
||||
var EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype),
|
||||
enableRefreshHack = !!(browser.tizen || browser.orsay || browser.operaTv || browser.web0s);
|
||||
EmbyCheckboxPrototype.attachedCallback = function() {
|
||||
if ("true" !== this.getAttribute("data-embycheckbox")) {
|
||||
this.setAttribute("data-embycheckbox", "true"), this.classList.add("emby-checkbox");
|
||||
var labelElement = this.parentNode;
|
||||
labelElement.classList.add("emby-checkbox-label");
|
||||
var labelTextElement = labelElement.querySelector("span"),
|
||||
outlineClass = "checkboxOutline",
|
||||
customClass = this.getAttribute("data-outlineclass");
|
||||
customClass && (outlineClass += " " + customClass);
|
||||
var checkedIcon = this.getAttribute("data-checkedicon") || "",
|
||||
uncheckedIcon = this.getAttribute("data-uncheckedicon") || "",
|
||||
checkHtml = '<i class="md-icon checkboxIcon checkboxIcon-checked">' + checkedIcon + "</i>",
|
||||
uncheckedHtml = '<i class="md-icon checkboxIcon checkboxIcon-unchecked">' + uncheckedIcon + "</i>";
|
||||
labelElement.insertAdjacentHTML("beforeend", '<span class="emby-checkbox-focushelper"></span><span class="' + outlineClass + '">' + checkHtml + uncheckedHtml + "</span>"), labelTextElement.classList.add("checkboxLabel"), this.addEventListener("keydown", onKeyDown), enableRefreshHack && (forceRefresh.call(this, !0), dom.addEventListener(this, "click", forceRefresh, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "blur", forceRefresh, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "focus", forceRefresh, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "change", forceRefresh, {
|
||||
passive: !0
|
||||
}))
|
||||
|
||||
EmbyCheckboxPrototype.attachedCallback = function () {
|
||||
|
||||
if (this.getAttribute('data-embycheckbox') === 'true') {
|
||||
return;
|
||||
}
|
||||
}, EmbyCheckboxPrototype.detachedCallback = function() {
|
||||
this.removeEventListener("keydown", onKeyDown), dom.removeEventListener(this, "click", forceRefresh, {
|
||||
passive: !0
|
||||
}), dom.removeEventListener(this, "blur", forceRefresh, {
|
||||
passive: !0
|
||||
}), dom.removeEventListener(this, "focus", forceRefresh, {
|
||||
passive: !0
|
||||
}), dom.removeEventListener(this, "change", forceRefresh, {
|
||||
passive: !0
|
||||
})
|
||||
}, document.registerElement("emby-checkbox", {
|
||||
|
||||
this.setAttribute('data-embycheckbox', 'true');
|
||||
|
||||
this.classList.add('emby-checkbox');
|
||||
|
||||
var labelElement = this.parentNode;
|
||||
labelElement.classList.add('emby-checkbox-label');
|
||||
|
||||
var labelTextElement = labelElement.querySelector('span');
|
||||
|
||||
var outlineClass = 'checkboxOutline';
|
||||
|
||||
var customClass = this.getAttribute('data-outlineclass');
|
||||
if (customClass) {
|
||||
outlineClass += ' ' + customClass;
|
||||
}
|
||||
|
||||
var checkedIcon = this.getAttribute('data-checkedicon') || '';
|
||||
var uncheckedIcon = this.getAttribute('data-uncheckedicon') || '';
|
||||
var checkHtml = '<i class="md-icon checkboxIcon checkboxIcon-checked">' + checkedIcon + '</i>';
|
||||
var uncheckedHtml = '<i class="md-icon checkboxIcon checkboxIcon-unchecked">' + uncheckedIcon + '</i>';
|
||||
labelElement.insertAdjacentHTML('beforeend', '<span class="emby-checkbox-focushelper"></span><span class="' + outlineClass + '">' + checkHtml + uncheckedHtml + '</span>');
|
||||
|
||||
labelTextElement.classList.add('checkboxLabel');
|
||||
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
|
||||
if (enableRefreshHack) {
|
||||
|
||||
forceRefresh.call(this, true);
|
||||
dom.addEventListener(this, 'click', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'blur', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'focus', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'change', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
EmbyCheckboxPrototype.detachedCallback = function () {
|
||||
|
||||
this.removeEventListener('keydown', onKeyDown);
|
||||
|
||||
dom.removeEventListener(this, 'click', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'blur', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'focus', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'change', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
|
||||
document.registerElement('emby-checkbox', {
|
||||
prototype: EmbyCheckboxPrototype,
|
||||
extends: "input"
|
||||
})
|
||||
});
|
||||
extends: 'input'
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,56 +1,44 @@
|
||||
.emby-collapse {
|
||||
margin: .5em 0
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
.collapseContent {
|
||||
border-width: 0;
|
||||
padding: 1.25em;
|
||||
padding: 1.25em 1.25em;
|
||||
height: 0;
|
||||
-webkit-transition-property: height;
|
||||
-o-transition-property: height;
|
||||
transition-property: height;
|
||||
-webkit-transition-duration: .3s;
|
||||
-o-transition-duration: .3s;
|
||||
transition-duration: .3s;
|
||||
overflow: hidden
|
||||
transition-duration: 300ms;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.emby-collapsible-button {
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
text-transform: none;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
text-transform: none;
|
||||
border-width: 0 0 .1em;
|
||||
border-width: 0 0 .1em 0;
|
||||
border-style: solid;
|
||||
padding-left: .1em;
|
||||
background: 0 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.emby-collapse-expandIcon {
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
-webkit-transition: -webkit-transform 180ms ease-out;
|
||||
-o-transition: transform 180ms ease-out;
|
||||
transition: transform 180ms ease-out;
|
||||
position: absolute;
|
||||
right: .5em;
|
||||
font-size: 1.5em
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.emby-collapse-expandIconExpanded {
|
||||
-webkit-transform: rotate(180deg);
|
||||
transform: rotate(180deg)
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.emby-collapsible-title {
|
||||
margin: 0;
|
||||
padding: 0
|
||||
}
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -1,43 +1,100 @@
|
||||
define(["browser", "css!./emby-collapse", "registerElement", "emby-button"], function(browser) {
|
||||
"use strict";
|
||||
define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], function (browser) {
|
||||
'use strict';
|
||||
|
||||
var EmbyButtonPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
function slideDownToShow(button, elem) {
|
||||
elem.classList.remove("hide"), elem.classList.add("expanded"), elem.style.height = "auto";
|
||||
var height = elem.offsetHeight + "px";
|
||||
elem.style.height = "0";
|
||||
elem.offsetHeight;
|
||||
elem.style.height = height, setTimeout(function() {
|
||||
elem.classList.contains("expanded") ? elem.classList.remove("hide") : elem.classList.add("hide"), elem.style.height = "auto"
|
||||
}, 300), button.querySelector("i").classList.add("emby-collapse-expandIconExpanded")
|
||||
|
||||
elem.classList.remove('hide');
|
||||
elem.classList.add('expanded');
|
||||
elem.style.height = 'auto';
|
||||
var height = elem.offsetHeight + 'px';
|
||||
elem.style.height = '0';
|
||||
|
||||
// trigger reflow
|
||||
var newHeight = elem.offsetHeight;
|
||||
elem.style.height = height;
|
||||
|
||||
setTimeout(function () {
|
||||
if (elem.classList.contains('expanded')) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
elem.style.height = 'auto';
|
||||
}, 300);
|
||||
|
||||
var icon = button.querySelector('i');
|
||||
//icon.innerHTML = 'expand_less';
|
||||
icon.classList.add('emby-collapse-expandIconExpanded');
|
||||
}
|
||||
|
||||
function slideUpToHide(button, elem) {
|
||||
elem.style.height = elem.offsetHeight + "px";
|
||||
elem.offsetHeight;
|
||||
elem.classList.remove("expanded"), elem.style.height = "0", setTimeout(function() {
|
||||
elem.classList.contains("expanded") ? elem.classList.remove("hide") : elem.classList.add("hide")
|
||||
}, 300), button.querySelector("i").classList.remove("emby-collapse-expandIconExpanded")
|
||||
|
||||
elem.style.height = elem.offsetHeight + 'px';
|
||||
// trigger reflow
|
||||
var newHeight = elem.offsetHeight;
|
||||
|
||||
elem.classList.remove('expanded');
|
||||
elem.style.height = '0';
|
||||
|
||||
setTimeout(function () {
|
||||
if (elem.classList.contains('expanded')) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
}, 300);
|
||||
|
||||
var icon = button.querySelector('i');
|
||||
//icon.innerHTML = 'expand_more';
|
||||
icon.classList.remove('emby-collapse-expandIconExpanded');
|
||||
}
|
||||
|
||||
function onButtonClick(e) {
|
||||
var button = this,
|
||||
collapseContent = button.parentNode.querySelector(".collapseContent");
|
||||
collapseContent.expanded ? (collapseContent.expanded = !1, slideUpToHide(button, collapseContent)) : (collapseContent.expanded = !0, slideDownToShow(button, collapseContent))
|
||||
}
|
||||
var EmbyButtonPrototype = Object.create(HTMLDivElement.prototype);
|
||||
EmbyButtonPrototype.attachedCallback = function() {
|
||||
if (!this.classList.contains("emby-collapse")) {
|
||||
this.classList.add("emby-collapse");
|
||||
var collapseContent = this.querySelector(".collapseContent");
|
||||
collapseContent && collapseContent.classList.add("hide");
|
||||
var title = this.getAttribute("title"),
|
||||
html = '<button is="emby-button" type="button" on-click="toggleExpand" id="expandButton" class="emby-collapsible-button iconRight"><h3 class="emby-collapsible-title" title="' + title + '">' + title + '</h3><i class="md-icon emby-collapse-expandIcon">expand_more</i></button>';
|
||||
this.insertAdjacentHTML("afterbegin", html);
|
||||
var button = this.querySelector(".emby-collapsible-button");
|
||||
button.addEventListener("click", onButtonClick), "true" === this.getAttribute("data-expanded") && onButtonClick.call(button)
|
||||
|
||||
var button = this;
|
||||
var collapseContent = button.parentNode.querySelector('.collapseContent');
|
||||
|
||||
if (collapseContent.expanded) {
|
||||
collapseContent.expanded = false;
|
||||
slideUpToHide(button, collapseContent);
|
||||
} else {
|
||||
collapseContent.expanded = true;
|
||||
slideDownToShow(button, collapseContent);
|
||||
}
|
||||
}, document.registerElement("emby-collapse", {
|
||||
}
|
||||
|
||||
EmbyButtonPrototype.attachedCallback = function () {
|
||||
|
||||
if (this.classList.contains('emby-collapse')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classList.add('emby-collapse');
|
||||
|
||||
var collapseContent = this.querySelector('.collapseContent');
|
||||
if (collapseContent) {
|
||||
collapseContent.classList.add('hide');
|
||||
}
|
||||
|
||||
var title = this.getAttribute('title');
|
||||
|
||||
var html = '<button is="emby-button" type="button" on-click="toggleExpand" id="expandButton" class="emby-collapsible-button iconRight"><h3 class="emby-collapsible-title" title="' + title + '">' + title + '</h3><i class="md-icon emby-collapse-expandIcon">expand_more</i></button>';
|
||||
|
||||
this.insertAdjacentHTML('afterbegin', html);
|
||||
|
||||
var button = this.querySelector('.emby-collapsible-button');
|
||||
|
||||
button.addEventListener('click', onButtonClick);
|
||||
|
||||
if (this.getAttribute('data-expanded') === 'true') {
|
||||
onButtonClick.call(button);
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-collapse', {
|
||||
prototype: EmbyButtonPrototype,
|
||||
extends: "div"
|
||||
})
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
||||
@@ -1,106 +1,219 @@
|
||||
define(["globalize", "apphost", "loading", "alert", "emby-linkbutton"], function(globalize, appHost, loading, alert) {
|
||||
"use strict";
|
||||
define(['globalize', 'apphost', 'loading', 'alert', 'emby-linkbutton'], function (globalize, appHost, loading, alert) {
|
||||
'use strict';
|
||||
|
||||
function resolvePromise() {
|
||||
return Promise.resolve()
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function rejectPromise() {
|
||||
return Promise.reject()
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
function showNewUserInviteMessage(result) {
|
||||
if (!result.IsNewUserInvitation && !result.IsPending) return Promise.resolve();
|
||||
var message = result.IsNewUserInvitation ? globalize.translate("sharedcomponents#MessageInvitationSentToNewUser", result.GuestDisplayName) : globalize.translate("sharedcomponents#MessageInvitationSentToUser", result.GuestDisplayName);
|
||||
|
||||
if (!result.IsNewUserInvitation && !result.IsPending) {
|
||||
|
||||
// It was immediately approved
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var message = result.IsNewUserInvitation ?
|
||||
globalize.translate('sharedcomponents#MessageInvitationSentToNewUser', result.GuestDisplayName) :
|
||||
globalize.translate('sharedcomponents#MessageInvitationSentToUser', result.GuestDisplayName);
|
||||
|
||||
return alert({
|
||||
|
||||
text: message,
|
||||
title: globalize.translate("sharedcomponents#HeaderInvitationSent")
|
||||
}).then(resolvePromise, resolvePromise)
|
||||
title: globalize.translate('sharedcomponents#HeaderInvitationSent')
|
||||
|
||||
}).then(resolvePromise, resolvePromise);
|
||||
}
|
||||
|
||||
function inviteGuest(options) {
|
||||
|
||||
var apiClient = options.apiClient;
|
||||
return loading.show(), apiClient.ajax({
|
||||
|
||||
loading.show();
|
||||
|
||||
// Add/Update connect info
|
||||
return apiClient.ajax({
|
||||
|
||||
type: "POST",
|
||||
url: apiClient.getUrl("Connect/Invite"),
|
||||
dataType: "json",
|
||||
url: apiClient.getUrl('Connect/Invite'),
|
||||
dataType: 'json',
|
||||
data: options.guestOptions || {}
|
||||
}).then(function(result) {
|
||||
return loading.hide(), showNewUserInviteMessage(result)
|
||||
}, function(response) {
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
loading.hide();
|
||||
return showNewUserInviteMessage(result);
|
||||
|
||||
}, function (response) {
|
||||
|
||||
loading.hide();
|
||||
|
||||
var statusCode = response ? response.status : 0;
|
||||
return 502 === statusCode ? showConnectServerUnreachableErrorMessage().then(rejectPromise, rejectPromise) : 404 === statusCode ? alert({
|
||||
text: globalize.translate("sharedcomponents#GuestUserNotFound")
|
||||
}).then(rejectPromise, rejectPromise) : (statusCode || 0) >= 500 ? alert({
|
||||
text: globalize.translate("sharedcomponents#ErrorReachingEmbyConnect")
|
||||
}).then(rejectPromise, rejectPromise) : showGuestGeneralErrorMessage().then(rejectPromise, rejectPromise)
|
||||
})
|
||||
|
||||
if (statusCode === 502) {
|
||||
return showConnectServerUnreachableErrorMessage().then(rejectPromise, rejectPromise);
|
||||
}
|
||||
else if (statusCode === 404) {
|
||||
// User doesn't exist
|
||||
return alert({
|
||||
text: globalize.translate('sharedcomponents#GuestUserNotFound')
|
||||
}).then(rejectPromise, rejectPromise);
|
||||
|
||||
} else if ((statusCode || 0) >= 500) {
|
||||
|
||||
// Unable to reach connect server ?
|
||||
return alert({
|
||||
text: globalize.translate('sharedcomponents#ErrorReachingEmbyConnect')
|
||||
}).then(rejectPromise, rejectPromise);
|
||||
|
||||
} else {
|
||||
|
||||
// status 400 = account not activated
|
||||
|
||||
// General error
|
||||
return showGuestGeneralErrorMessage().then(rejectPromise, rejectPromise);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showGuestGeneralErrorMessage() {
|
||||
|
||||
var html;
|
||||
appHost.supports("externallinks") && (html = globalize.translate("sharedcomponents#ErrorAddingGuestAccount1", '<a is="emby-linkbutton" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">https://github.com/jellyfin/jellyfin</a>'), html += "<br/><br/>" + globalize.translate("sharedcomponents#ErrorAddingGuestAccount2", "apps@emby.media"));
|
||||
var text = globalize.translate("sharedcomponents#ErrorAddingGuestAccount1", "https://github.com/jellyfin/jellyfin");
|
||||
return text += "\n\n" + globalize.translate("sharedcomponents#ErrorAddingGuestAccount2", "apps@emby.media"), alert({
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html = globalize.translate('sharedcomponents#ErrorAddingGuestAccount1', '<a is="emby-linkbutton" class="button-link" href="https://emby.media/connect" target="_blank">https://emby.media/connect</a>');
|
||||
html += '<br/><br/>' + globalize.translate('sharedcomponents#ErrorAddingGuestAccount2', 'apps@emby.media');
|
||||
}
|
||||
|
||||
var text = globalize.translate('sharedcomponents#ErrorAddingGuestAccount1', 'https://emby.media/connect');
|
||||
text += '\n\n' + globalize.translate('sharedcomponents#ErrorAddingGuestAccount2', 'apps@emby.media');
|
||||
|
||||
return alert({
|
||||
text: text,
|
||||
html: html
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function showConnectServerUnreachableErrorMessage() {
|
||||
var text = globalize.translate("sharedcomponents#ErrorConnectServerUnreachable", "https://connect.emby.media");
|
||||
|
||||
var text = globalize.translate('sharedcomponents#ErrorConnectServerUnreachable', 'https://connect.emby.media');
|
||||
|
||||
return alert({
|
||||
text: text
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function showLinkUserErrorMessage(username, statusCode) {
|
||||
var html, text;
|
||||
return 502 === statusCode ? showConnectServerUnreachableErrorMessage() : (username ? (appHost.supports("externallinks") && (html = globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount1", '<a is="emby-linkbutton" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">https://github.com/jellyfin/jellyfin</a>'), html += "<br/><br/>" + globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount2", "apps@emby.media")), text = globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount1", "https://github.com/jellyfin/jellyfin"), text += "\n\n" + globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount2", "apps@emby.media")) : html = text = globalize.translate("sharedcomponents#DefaultErrorMessage"), alert({
|
||||
|
||||
var html;
|
||||
var text;
|
||||
|
||||
if (statusCode === 502) {
|
||||
return showConnectServerUnreachableErrorMessage();
|
||||
}
|
||||
else if (username) {
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html = globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount1', '<a is="emby-linkbutton" class="button-link" href="https://emby.media/connect" target="_blank">https://emby.media/connect</a>');
|
||||
html += '<br/><br/>' + globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount2', 'apps@emby.media');
|
||||
}
|
||||
|
||||
text = globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount1', 'https://emby.media/connect');
|
||||
text += '\n\n' + globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount2', 'apps@emby.media');
|
||||
|
||||
} else {
|
||||
html = text = globalize.translate('sharedcomponents#DefaultErrorMessage');
|
||||
}
|
||||
|
||||
return alert({
|
||||
text: text,
|
||||
html: html
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
function updateUserLink(apiClient, user, newConnectUsername) {
|
||||
var currentConnectUsername = user.ConnectUserName || "",
|
||||
enteredConnectUsername = newConnectUsername,
|
||||
linkUrl = apiClient.getUrl("Users/" + user.Id + "/Connect/Link");
|
||||
return currentConnectUsername && !enteredConnectUsername ? apiClient.ajax({
|
||||
type: "DELETE",
|
||||
url: linkUrl
|
||||
}).then(function() {
|
||||
return alert({
|
||||
text: globalize.translate("sharedcomponents#MessageEmbyAccontRemoved"),
|
||||
title: globalize.translate("sharedcomponents#HeaderEmbyAccountRemoved")
|
||||
}).catch(resolvePromise)
|
||||
}, function(response) {
|
||||
return 502 === (response ? response.status : 0) ? showConnectServerUnreachableErrorMessage().then(rejectPromise) : alert({
|
||||
text: globalize.translate("sharedcomponents#ErrorRemovingEmbyConnectAccount")
|
||||
}).then(rejectPromise)
|
||||
}) : currentConnectUsername !== enteredConnectUsername ? apiClient.ajax({
|
||||
type: "POST",
|
||||
url: linkUrl,
|
||||
data: {
|
||||
ConnectUsername: enteredConnectUsername
|
||||
},
|
||||
dataType: "json"
|
||||
}).then(function(result) {
|
||||
var msgKey = result.IsPending ? "sharedcomponents#MessagePendingEmbyAccountAdded" : "sharedcomponents#MessageEmbyAccountAdded";
|
||||
return alert({
|
||||
text: globalize.translate(msgKey),
|
||||
title: globalize.translate("sharedcomponents#HeaderEmbyAccountAdded")
|
||||
}).catch(resolvePromise)
|
||||
}, function(response) {
|
||||
var statusCode = response ? response.status : 0;
|
||||
return 502 === statusCode ? showConnectServerUnreachableErrorMessage().then(rejectPromise) : showLinkUserErrorMessage(".", statusCode).then(rejectPromise)
|
||||
}) : Promise.reject()
|
||||
var currentConnectUsername = user.ConnectUserName || '';
|
||||
var enteredConnectUsername = newConnectUsername;
|
||||
|
||||
var linkUrl = apiClient.getUrl('Users/' + user.Id + '/Connect/Link');
|
||||
|
||||
if (currentConnectUsername && !enteredConnectUsername) {
|
||||
|
||||
// Remove connect info
|
||||
// Add/Update connect info
|
||||
return apiClient.ajax({
|
||||
|
||||
type: "DELETE",
|
||||
url: linkUrl
|
||||
|
||||
}).then(function () {
|
||||
|
||||
return alert({
|
||||
text: globalize.translate('sharedcomponents#MessageEmbyAccontRemoved'),
|
||||
title: globalize.translate('sharedcomponents#HeaderEmbyAccountRemoved'),
|
||||
|
||||
}).catch(resolvePromise);
|
||||
|
||||
}, function (response) {
|
||||
|
||||
var statusCode = response ? response.status : 0;
|
||||
|
||||
if (statusCode === 502) {
|
||||
return showConnectServerUnreachableErrorMessage().then(rejectPromise);
|
||||
}
|
||||
|
||||
return alert({
|
||||
text: globalize.translate('sharedcomponents#ErrorRemovingEmbyConnectAccount')
|
||||
|
||||
}).then(rejectPromise);
|
||||
});
|
||||
|
||||
}
|
||||
else if (currentConnectUsername !== enteredConnectUsername) {
|
||||
|
||||
// Add/Update connect info
|
||||
return apiClient.ajax({
|
||||
type: "POST",
|
||||
url: linkUrl,
|
||||
data: {
|
||||
ConnectUsername: enteredConnectUsername
|
||||
},
|
||||
dataType: 'json'
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
var msgKey = result.IsPending ? 'sharedcomponents#MessagePendingEmbyAccountAdded' : 'sharedcomponents#MessageEmbyAccountAdded';
|
||||
|
||||
return alert({
|
||||
text: globalize.translate(msgKey),
|
||||
title: globalize.translate('sharedcomponents#HeaderEmbyAccountAdded'),
|
||||
|
||||
}).catch(resolvePromise);
|
||||
|
||||
}, function (response) {
|
||||
|
||||
var statusCode = response ? response.status : 0;
|
||||
|
||||
if (statusCode === 502) {
|
||||
return showConnectServerUnreachableErrorMessage().then(rejectPromise);
|
||||
}
|
||||
|
||||
return showLinkUserErrorMessage('.', statusCode).then(rejectPromise);
|
||||
});
|
||||
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
inviteGuest: inviteGuest,
|
||||
updateUserLink: updateUserLink,
|
||||
showLinkUserErrorMessage: showLinkUserErrorMessage,
|
||||
showConnectServerUnreachableErrorMessage: showConnectServerUnreachableErrorMessage
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -2,35 +2,39 @@
|
||||
display: block;
|
||||
margin: 0;
|
||||
margin-bottom: 0 !important;
|
||||
/* Remove select styling */
|
||||
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
|
||||
font-size: 110%;
|
||||
/* General select styles: change as needed */
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
padding: .4em .25em;
|
||||
/* Prevent padding from causing width overflow */
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
outline: 0 !important;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
width: 100%
|
||||
outline: none !important;
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.emby-input::-moz-focus-inner {
|
||||
border: 0
|
||||
}
|
||||
.emby-input::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.inputContainer {
|
||||
margin-bottom: 1.8em
|
||||
margin-bottom: 1.8em;
|
||||
}
|
||||
|
||||
.inputLabel {
|
||||
display: inline-block;
|
||||
margin-bottom: .25em
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
.emby-input+.fieldDescription {
|
||||
margin-top: .25em
|
||||
.emby-input + .fieldDescription {
|
||||
margin-top: .25em;
|
||||
}
|
||||
|
||||
.emby-input-iconbutton {
|
||||
-webkit-align-self: flex-end;
|
||||
align-self: flex-end
|
||||
}
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
@@ -1,56 +1,125 @@
|
||||
define(["layoutManager", "browser", "dom", "css!./emby-input", "registerElement"], function(layoutManager, browser, dom) {
|
||||
"use strict";
|
||||
define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'registerElement'], function (layoutManager, browser, dom) {
|
||||
'use strict';
|
||||
|
||||
var EmbyInputPrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
var inputId = 0;
|
||||
var supportsFloatingLabel = false;
|
||||
|
||||
function onChange() {
|
||||
var label = this.labelElement;
|
||||
if (this.value) label.classList.remove("inputLabel-float");
|
||||
else {
|
||||
supportsFloatingLabel && "date" !== this.type && "time" !== this.type && label.classList.add("inputLabel-float")
|
||||
}
|
||||
}
|
||||
var EmbyInputPrototype = Object.create(HTMLInputElement.prototype),
|
||||
inputId = 0,
|
||||
supportsFloatingLabel = !1;
|
||||
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
|
||||
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
|
||||
|
||||
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
|
||||
|
||||
// descriptor returning null in webos
|
||||
if (descriptor && descriptor.configurable) {
|
||||
var baseSetMethod = descriptor.set;
|
||||
descriptor.set = function(value) {
|
||||
baseSetMethod.call(this, value), this.dispatchEvent(new CustomEvent("valueset", {
|
||||
bubbles: !1,
|
||||
cancelable: !1
|
||||
}))
|
||||
}, Object.defineProperty(HTMLInputElement.prototype, "value", descriptor), supportsFloatingLabel = !0
|
||||
descriptor.set = function (value) {
|
||||
baseSetMethod.call(this, value);
|
||||
|
||||
this.dispatchEvent(new CustomEvent('valueset', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
};
|
||||
|
||||
Object.defineProperty(HTMLInputElement.prototype, 'value', descriptor);
|
||||
supportsFloatingLabel = true;
|
||||
}
|
||||
}
|
||||
EmbyInputPrototype.createdCallback = function() {
|
||||
if (this.id || (this.id = "embyinput" + inputId, inputId++), !this.classList.contains("emby-input")) {
|
||||
this.classList.add("emby-input");
|
||||
var parentNode = this.parentNode,
|
||||
document = this.ownerDocument,
|
||||
label = document.createElement("label");
|
||||
label.innerHTML = this.getAttribute("label") || "", label.classList.add("inputLabel"), label.classList.add("inputLabelUnfocused"), label.htmlFor = this.id, parentNode.insertBefore(label, this), this.labelElement = label, dom.addEventListener(this, "focus", function() {
|
||||
onChange.call(this), document.attachIME && document.attachIME(this), label.classList.add("inputLabelFocused"), label.classList.remove("inputLabelUnfocused")
|
||||
}, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "blur", function() {
|
||||
onChange.call(this), label.classList.remove("inputLabelFocused"), label.classList.add("inputLabelUnfocused")
|
||||
}, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "change", onChange, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "input", onChange, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "valueset", onChange, {
|
||||
passive: !0
|
||||
}), browser.orsay && this === document.activeElement && document.attachIME && document.attachIME(this)
|
||||
|
||||
EmbyInputPrototype.createdCallback = function () {
|
||||
|
||||
if (!this.id) {
|
||||
this.id = 'embyinput' + inputId;
|
||||
inputId++;
|
||||
} if (this.classList.contains('emby-input')) {
|
||||
return;
|
||||
}
|
||||
}, EmbyInputPrototype.attachedCallback = function() {
|
||||
this.labelElement.htmlFor = this.id, onChange.call(this)
|
||||
}, EmbyInputPrototype.label = function(text) {
|
||||
this.labelElement.innerHTML = text
|
||||
}, document.registerElement("emby-input", {
|
||||
|
||||
this.classList.add('emby-input');
|
||||
|
||||
var parentNode = this.parentNode;
|
||||
var document = this.ownerDocument;
|
||||
var label = document.createElement('label');
|
||||
label.innerHTML = this.getAttribute('label') || '';
|
||||
label.classList.add('inputLabel');
|
||||
label.classList.add('inputLabelUnfocused');
|
||||
|
||||
label.htmlFor = this.id;
|
||||
parentNode.insertBefore(label, this);
|
||||
this.labelElement = label;
|
||||
|
||||
dom.addEventListener(this, 'focus', function () {
|
||||
onChange.call(this);
|
||||
|
||||
// For Samsung orsay devices
|
||||
if (document.attachIME) {
|
||||
document.attachIME(this);
|
||||
}
|
||||
|
||||
label.classList.add('inputLabelFocused');
|
||||
label.classList.remove('inputLabelUnfocused');
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(this, 'blur', function () {
|
||||
onChange.call(this);
|
||||
label.classList.remove('inputLabelFocused');
|
||||
label.classList.add('inputLabelUnfocused');
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(this, 'change', onChange, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'input', onChange, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'valueset', onChange, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
if (browser.orsay) {
|
||||
if (this === document.activeElement) {
|
||||
//Make sure the IME pops up if this is the first/default element on the page
|
||||
if (document.attachIME) {
|
||||
document.attachIME(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function onChange() {
|
||||
|
||||
var label = this.labelElement;
|
||||
if (this.value) {
|
||||
label.classList.remove('inputLabel-float');
|
||||
} else {
|
||||
|
||||
var instanceSupportsFloat = supportsFloatingLabel && this.type !== 'date' && this.type !== 'time';
|
||||
|
||||
if (instanceSupportsFloat) {
|
||||
label.classList.add('inputLabel-float');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmbyInputPrototype.attachedCallback = function () {
|
||||
|
||||
this.labelElement.htmlFor = this.id;
|
||||
|
||||
onChange.call(this);
|
||||
};
|
||||
|
||||
EmbyInputPrototype.label = function (text) {
|
||||
this.labelElement.innerHTML = text;
|
||||
};
|
||||
|
||||
document.registerElement('emby-input', {
|
||||
prototype: EmbyInputPrototype,
|
||||
extends: "input"
|
||||
})
|
||||
extends: 'input'
|
||||
});
|
||||
});
|
||||
@@ -1,32 +1,77 @@
|
||||
define(["emby-progressring", "dom", "serverNotifications", "events", "registerElement"], function(EmbyProgressRing, dom, serverNotifications, events) {
|
||||
"use strict";
|
||||
define(['emby-progressring', 'dom', 'serverNotifications', 'events', 'registerElement'], function (EmbyProgressRing, dom, serverNotifications, events) {
|
||||
'use strict';
|
||||
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
|
||||
var localHandler = handler.bind(instance);
|
||||
events.on(serverNotifications, name, localHandler), instance[name] = localHandler
|
||||
events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name) {
|
||||
|
||||
var handler = instance[name];
|
||||
handler && (events.off(serverNotifications, name, handler), instance[name] = null)
|
||||
if (handler) {
|
||||
events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function onRefreshProgress(e, apiClient, info) {
|
||||
|
||||
var indicator = this;
|
||||
if (indicator.itemId || (indicator.itemId = dom.parentWithAttribute(indicator, "data-id").getAttribute("data-id")), info.ItemId === indicator.itemId) {
|
||||
|
||||
if (!indicator.itemId) {
|
||||
indicator.itemId = dom.parentWithAttribute(indicator, 'data-id').getAttribute('data-id');
|
||||
}
|
||||
|
||||
if (info.ItemId === indicator.itemId) {
|
||||
|
||||
var progress = parseFloat(info.Progress);
|
||||
progress && progress < 100 ? this.classList.remove("hide") : this.classList.add("hide"), this.setProgress(progress)
|
||||
|
||||
if (progress && progress < 100) {
|
||||
this.classList.remove('hide');
|
||||
} else {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
this.setProgress(progress);
|
||||
}
|
||||
}
|
||||
|
||||
var EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
|
||||
EmbyItemRefreshIndicatorPrototype.createdCallback = function() {
|
||||
EmbyProgressRing.createdCallback && EmbyProgressRing.createdCallback.call(this), addNotificationEvent(this, "RefreshProgress", onRefreshProgress)
|
||||
}, EmbyItemRefreshIndicatorPrototype.attachedCallback = function() {
|
||||
EmbyProgressRing.attachedCallback && EmbyProgressRing.attachedCallback.call(this)
|
||||
}, EmbyItemRefreshIndicatorPrototype.detachedCallback = function() {
|
||||
EmbyProgressRing.detachedCallback && EmbyProgressRing.detachedCallback.call(this), removeNotificationEvent(this, "RefreshProgress"), this.itemId = null
|
||||
}, document.registerElement("emby-itemrefreshindicator", {
|
||||
|
||||
EmbyItemRefreshIndicatorPrototype.createdCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyProgressRing.createdCallback) {
|
||||
EmbyProgressRing.createdCallback.call(this);
|
||||
}
|
||||
|
||||
addNotificationEvent(this, 'RefreshProgress', onRefreshProgress);
|
||||
};
|
||||
|
||||
EmbyItemRefreshIndicatorPrototype.attachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyProgressRing.attachedCallback) {
|
||||
EmbyProgressRing.attachedCallback.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyItemRefreshIndicatorPrototype.detachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyProgressRing.detachedCallback) {
|
||||
EmbyProgressRing.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
removeNotificationEvent(this, 'RefreshProgress');
|
||||
this.itemId = null;
|
||||
};
|
||||
|
||||
document.registerElement('emby-itemrefreshindicator', {
|
||||
prototype: EmbyItemRefreshIndicatorPrototype,
|
||||
extends: "div"
|
||||
})
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
||||
@@ -1,220 +1,548 @@
|
||||
define(["itemShortcuts", "inputManager", "connectionManager", "playbackManager", "imageLoader", "layoutManager", "browser", "dom", "loading", "focusManager", "serverNotifications", "events", "registerElement"], function(itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) {
|
||||
"use strict";
|
||||
define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', 'imageLoader', 'layoutManager', 'browser', 'dom', 'loading', 'focusManager', 'serverNotifications', 'events', 'registerElement'], function (itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) {
|
||||
'use strict';
|
||||
|
||||
var ItemsContainerProtoType = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
function onClick(e) {
|
||||
var itemsContainer = this,
|
||||
multiSelect = (e.target, itemsContainer.multiSelect);
|
||||
multiSelect && !1 === multiSelect.onContainerClick.call(itemsContainer, e) || itemShortcuts.onClick.call(itemsContainer, e)
|
||||
|
||||
var itemsContainer = this;
|
||||
var target = e.target;
|
||||
|
||||
var multiSelect = itemsContainer.multiSelect;
|
||||
|
||||
if (multiSelect) {
|
||||
if (multiSelect.onContainerClick.call(itemsContainer, e) === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
itemShortcuts.onClick.call(itemsContainer, e);
|
||||
}
|
||||
|
||||
function disableEvent(e) {
|
||||
return e.preventDefault(), e.stopPropagation(), !1
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
function onContextMenu(e) {
|
||||
var target = e.target,
|
||||
card = dom.parentWithAttribute(target, "data-id");
|
||||
if (card && card.getAttribute("data-serverid")) return inputManager.trigger("menu", {
|
||||
sourceElement: card
|
||||
}), e.preventDefault(), e.stopPropagation(), !1
|
||||
|
||||
var itemsContainer = this;
|
||||
|
||||
var target = e.target;
|
||||
var card = dom.parentWithAttribute(target, 'data-id');
|
||||
|
||||
// check for serverId, it won't be present on selectserver
|
||||
if (card && card.getAttribute('data-serverid')) {
|
||||
|
||||
inputManager.trigger('menu', {
|
||||
sourceElement: card
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getShortcutOptions() {
|
||||
return {
|
||||
click: !1
|
||||
}
|
||||
click: false
|
||||
};
|
||||
}
|
||||
|
||||
ItemsContainerProtoType.enableMultiSelect = function (enabled) {
|
||||
|
||||
var current = this.multiSelect;
|
||||
|
||||
if (!enabled) {
|
||||
if (current) {
|
||||
current.destroy();
|
||||
this.multiSelect = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (current) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
require(['multiSelect'], function (MultiSelect) {
|
||||
self.multiSelect = new MultiSelect({
|
||||
container: self,
|
||||
bindOnClick: false
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function onDrop(evt, itemsContainer) {
|
||||
var el = evt.item,
|
||||
newIndex = evt.newIndex,
|
||||
itemId = el.getAttribute("data-playlistitemid"),
|
||||
playlistId = el.getAttribute("data-playlistid");
|
||||
|
||||
var el = evt.item;
|
||||
|
||||
var newIndex = evt.newIndex;
|
||||
var itemId = el.getAttribute('data-playlistitemid');
|
||||
var playlistId = el.getAttribute('data-playlistid');
|
||||
|
||||
if (!playlistId) {
|
||||
|
||||
var oldIndex = evt.oldIndex;
|
||||
return void el.dispatchEvent(new CustomEvent("itemdrop", {
|
||||
|
||||
el.dispatchEvent(new CustomEvent('itemdrop', {
|
||||
detail: {
|
||||
oldIndex: oldIndex,
|
||||
newIndex: newIndex,
|
||||
playlistItemId: itemId
|
||||
},
|
||||
bubbles: !0,
|
||||
cancelable: !1
|
||||
}))
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
return;
|
||||
}
|
||||
var serverId = el.getAttribute("data-serverid"),
|
||||
apiClient = connectionManager.getApiClient(serverId);
|
||||
loading.show(), apiClient.ajax({
|
||||
url: apiClient.getUrl("Playlists/" + playlistId + "/Items/" + itemId + "/Move/" + newIndex),
|
||||
type: "POST"
|
||||
}).then(function() {
|
||||
loading.hide()
|
||||
}, function() {
|
||||
loading.hide(), itemsContainer.refreshItems()
|
||||
})
|
||||
|
||||
var serverId = el.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.ajax({
|
||||
|
||||
url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex),
|
||||
|
||||
type: 'POST'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
loading.hide();
|
||||
|
||||
}, function () {
|
||||
|
||||
loading.hide();
|
||||
|
||||
itemsContainer.refreshItems();
|
||||
});
|
||||
}
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
var itemsContainer = this;
|
||||
require(["cardBuilder"], function(cardBuilder) {
|
||||
cardBuilder.onUserDataChanged(userData, itemsContainer)
|
||||
ItemsContainerProtoType.enableDragReordering = function (enabled) {
|
||||
|
||||
var current = this.sortable;
|
||||
|
||||
if (!enabled) {
|
||||
if (current) {
|
||||
current.destroy();
|
||||
this.sortable = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (current) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
require(['sortable'], function (Sortable) {
|
||||
|
||||
self.sortable = new Sortable(self, {
|
||||
|
||||
draggable: ".listItem",
|
||||
handle: '.listViewDragHandle',
|
||||
|
||||
// dragging ended
|
||||
onEnd: function (/**Event*/evt) {
|
||||
|
||||
return onDrop(evt, self);
|
||||
}
|
||||
});
|
||||
});
|
||||
var eventsToMonitor = getEventsToMonitor(itemsContainer); - 1 !== eventsToMonitor.indexOf("markfavorite") ? itemsContainer.notifyRefreshNeeded() : -1 !== eventsToMonitor.indexOf("markplayed") && itemsContainer.notifyRefreshNeeded()
|
||||
};
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
|
||||
var itemsContainer = this;
|
||||
|
||||
require(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.onUserDataChanged(userData, itemsContainer);
|
||||
});
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function getEventsToMonitor(itemsContainer) {
|
||||
var monitor = itemsContainer.getAttribute("data-monitor");
|
||||
return monitor ? monitor.split(",") : []
|
||||
|
||||
var monitor = itemsContainer.getAttribute('data-monitor');
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
|
||||
var itemsContainer = this;
|
||||
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("timers")) return void itemsContainer.notifyRefreshNeeded();
|
||||
var programId = data.ProgramId,
|
||||
newTimerId = data.Id;
|
||||
require(["cardBuilder"], function(cardBuilder) {
|
||||
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer)
|
||||
})
|
||||
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
var programId = data.ProgramId;
|
||||
// This could be null, not supported by all tv providers
|
||||
var newTimerId = data.Id;
|
||||
|
||||
require(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onSeriesTimerCreated(e, apiClient, data) {
|
||||
|
||||
var itemsContainer = this;
|
||||
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("seriestimers")) return void itemsContainer.notifyRefreshNeeded()
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
var itemsContainer = this;
|
||||
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("timers")) return void itemsContainer.notifyRefreshNeeded();
|
||||
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
var id = data.Id;
|
||||
require(["cardBuilder"], function(cardBuilder) {
|
||||
cardBuilder.onTimerCancelled(id, itemsContainer)
|
||||
})
|
||||
|
||||
require(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.onTimerCancelled(id, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
|
||||
var itemsContainer = this;
|
||||
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("seriestimers")) return void itemsContainer.notifyRefreshNeeded();
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
var id = data.Id;
|
||||
require(["cardBuilder"], function(cardBuilder) {
|
||||
cardBuilder.onSeriesTimerCancelled(id, itemsContainer)
|
||||
})
|
||||
|
||||
require(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.onSeriesTimerCancelled(id, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
var itemsContainer = this,
|
||||
eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (-1 === eventsToMonitor.indexOf("seriestimers") && -1 === eventsToMonitor.indexOf("timers")) {
|
||||
var itemsAdded = data.ItemsAdded || [],
|
||||
itemsRemoved = data.ItemsRemoved || [];
|
||||
if (itemsAdded.length || itemsRemoved.length) {
|
||||
var parentId = itemsContainer.getAttribute("data-parentid");
|
||||
if (parentId) {
|
||||
var foldersAddedTo = data.FoldersAddedTo || [],
|
||||
foldersRemovedFrom = data.FoldersRemovedFrom || [],
|
||||
collectionFolders = data.CollectionFolders || [];
|
||||
if (-1 === foldersAddedTo.indexOf(parentId) && -1 === foldersRemovedFrom.indexOf(parentId) && -1 === collectionFolders.indexOf(parentId)) return
|
||||
}
|
||||
itemsContainer.notifyRefreshNeeded()
|
||||
|
||||
var itemsContainer = this;
|
||||
var eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
var itemsAdded = data.ItemsAdded || [];
|
||||
var itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parentId = itemsContainer.getAttribute('data-parentid');
|
||||
if (parentId) {
|
||||
var foldersAddedTo = data.FoldersAddedTo || [];
|
||||
var foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
var collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
|
||||
var itemsContainer = this;
|
||||
|
||||
var state = stopInfo.state;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
|
||||
itemsContainer.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
||||
|
||||
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
|
||||
itemsContainer.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
var itemsContainer = this,
|
||||
state = stopInfo.state,
|
||||
eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (state.NowPlayingItem && "Video" === state.NowPlayingItem.MediaType) {
|
||||
if (-1 !== eventsToMonitor.indexOf("videoplayback")) return void itemsContainer.notifyRefreshNeeded(!0)
|
||||
} else if (state.NowPlayingItem && "Audio" === state.NowPlayingItem.MediaType && -1 !== eventsToMonitor.indexOf("audioplayback")) return void itemsContainer.notifyRefreshNeeded(!0)
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
|
||||
var localHandler = handler.bind(instance);
|
||||
owner = owner || serverNotifications, events.on(owner, name, localHandler), instance["event_" + name] = localHandler
|
||||
owner = owner || serverNotifications;
|
||||
events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
var handler = instance["event_" + name];
|
||||
handler && (owner = owner || serverNotifications, events.off(owner, name, handler), instance["event_" + name] = null)
|
||||
|
||||
var handler = instance['event_' + name];
|
||||
if (handler) {
|
||||
owner = owner || serverNotifications;
|
||||
events.off(owner, name, handler);
|
||||
instance['event_' + name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
ItemsContainerProtoType.createdCallback = function () {
|
||||
|
||||
this.classList.add('itemsContainer');
|
||||
};
|
||||
|
||||
ItemsContainerProtoType.attachedCallback = function () {
|
||||
|
||||
this.addEventListener('click', onClick);
|
||||
|
||||
if (browser.touch) {
|
||||
this.addEventListener('contextmenu', disableEvent);
|
||||
} else {
|
||||
if (this.getAttribute('data-contextmenu') !== 'false') {
|
||||
this.addEventListener('contextmenu', onContextMenu);
|
||||
}
|
||||
}
|
||||
|
||||
if (layoutManager.desktop || layoutManager.mobile) {
|
||||
if (this.getAttribute('data-multiselect') !== 'false') {
|
||||
this.enableMultiSelect(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('itemsContainer-tv');
|
||||
}
|
||||
|
||||
itemShortcuts.on(this, getShortcutOptions());
|
||||
|
||||
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
|
||||
addNotificationEvent(this, 'TimerCreated', onTimerCreated);
|
||||
addNotificationEvent(this, 'SeriesTimerCreated', onSeriesTimerCreated);
|
||||
addNotificationEvent(this, 'TimerCancelled', onTimerCancelled);
|
||||
addNotificationEvent(this, 'SeriesTimerCancelled', onSeriesTimerCancelled);
|
||||
addNotificationEvent(this, 'LibraryChanged', onLibraryChanged);
|
||||
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
|
||||
|
||||
if (this.getAttribute('data-dragreorder') === 'true') {
|
||||
this.enableDragReordering(true);
|
||||
}
|
||||
};
|
||||
|
||||
ItemsContainerProtoType.detachedCallback = function () {
|
||||
|
||||
clearRefreshInterval(this);
|
||||
|
||||
this.enableMultiSelect(false);
|
||||
this.enableDragReordering(false);
|
||||
this.removeEventListener('click', onClick);
|
||||
this.removeEventListener('contextmenu', onContextMenu);
|
||||
this.removeEventListener('contextmenu', disableEvent);
|
||||
itemShortcuts.off(this, getShortcutOptions());
|
||||
|
||||
removeNotificationEvent(this, 'UserDataChanged');
|
||||
removeNotificationEvent(this, 'TimerCreated');
|
||||
removeNotificationEvent(this, 'SeriesTimerCreated');
|
||||
removeNotificationEvent(this, 'TimerCancelled');
|
||||
removeNotificationEvent(this, 'SeriesTimerCancelled');
|
||||
removeNotificationEvent(this, 'LibraryChanged');
|
||||
removeNotificationEvent(this, 'playbackstop', playbackManager);
|
||||
|
||||
this.fetchData = null;
|
||||
this.getItemsHtml = null;
|
||||
this.parentContainer = null;
|
||||
};
|
||||
|
||||
ItemsContainerProtoType.pause = function () {
|
||||
|
||||
clearRefreshInterval(this, true);
|
||||
|
||||
this.paused = true;
|
||||
};
|
||||
|
||||
ItemsContainerProtoType.resume = function (options) {
|
||||
|
||||
this.paused = false;
|
||||
|
||||
var refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
if (refreshIntervalEndTime) {
|
||||
|
||||
var remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
if (remainingMs > 0 && !this.needsRefresh) {
|
||||
|
||||
resetRefreshInterval(this, remainingMs);
|
||||
|
||||
} else {
|
||||
this.needsRefresh = true;
|
||||
this.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.needsRefresh || (options && options.refresh)) {
|
||||
return this.refreshItems();
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
ItemsContainerProtoType.refreshItems = function () {
|
||||
|
||||
if (!this.fetchData) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.needsRefresh = false;
|
||||
|
||||
return this.fetchData().then(onDataFetched.bind(this));
|
||||
};
|
||||
|
||||
ItemsContainerProtoType.notifyRefreshNeeded = function (isInForeground) {
|
||||
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var timeout = this.refreshTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
if (isInForeground === true) {
|
||||
this.refreshItems();
|
||||
} else {
|
||||
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
|
||||
}
|
||||
};
|
||||
|
||||
function clearRefreshInterval(itemsContainer, isPausing) {
|
||||
itemsContainer.refreshInterval && (clearInterval(itemsContainer.refreshInterval), itemsContainer.refreshInterval = null, isPausing || (itemsContainer.refreshIntervalEndTime = null))
|
||||
|
||||
if (itemsContainer.refreshInterval) {
|
||||
|
||||
clearInterval(itemsContainer.refreshInterval);
|
||||
itemsContainer.refreshInterval = null;
|
||||
|
||||
if (!isPausing) {
|
||||
itemsContainer.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(itemsContainer, intervalMs) {
|
||||
clearRefreshInterval(itemsContainer), intervalMs || (intervalMs = parseInt(itemsContainer.getAttribute("data-refreshinterval") || "0")), intervalMs && (itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs), itemsContainer.refreshIntervalEndTime = (new Date).getTime() + intervalMs)
|
||||
|
||||
clearRefreshInterval(itemsContainer);
|
||||
|
||||
if (!intervalMs) {
|
||||
intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0');
|
||||
}
|
||||
|
||||
if (intervalMs) {
|
||||
itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs);
|
||||
itemsContainer.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
var items = result.Items || result,
|
||||
parentContainer = this.parentContainer;
|
||||
parentContainer && (items.length ? parentContainer.classList.remove("hide") : parentContainer.classList.add("hide"));
|
||||
var focusId, hasActiveElement, activeElement = document.activeElement;
|
||||
this.contains(activeElement) && (hasActiveElement = !0, focusId = activeElement.getAttribute("data-id")), this.innerHTML = this.getItemsHtml(items), imageLoader.lazyChildren(this), hasActiveElement && setFocus(this, focusId), resetRefreshInterval(this), this.afterRefresh && this.afterRefresh(result)
|
||||
|
||||
var items = result.Items || result;
|
||||
|
||||
var parentContainer = this.parentContainer;
|
||||
if (parentContainer) {
|
||||
if (items.length) {
|
||||
parentContainer.classList.remove('hide');
|
||||
} else {
|
||||
parentContainer.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll back up so they can see the results from the beginning
|
||||
// TODO: Find scroller
|
||||
//window.scrollTo(0, 0);
|
||||
|
||||
var activeElement = document.activeElement;
|
||||
var focusId;
|
||||
var hasActiveElement;
|
||||
|
||||
if (this.contains(activeElement)) {
|
||||
hasActiveElement = true;
|
||||
focusId = activeElement.getAttribute('data-id');
|
||||
}
|
||||
|
||||
this.innerHTML = this.getItemsHtml(items);
|
||||
|
||||
imageLoader.lazyChildren(this);
|
||||
|
||||
if (hasActiveElement) {
|
||||
setFocus(this, focusId);
|
||||
}
|
||||
|
||||
resetRefreshInterval(this);
|
||||
|
||||
if (this.afterRefresh) {
|
||||
this.afterRefresh(result);
|
||||
}
|
||||
}
|
||||
|
||||
function setFocus(itemsContainer, focusId) {
|
||||
if (focusId) {
|
||||
var newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]');
|
||||
if (newElement) try {
|
||||
return void focusManager.focus(newElement)
|
||||
} catch (err) {}
|
||||
if (newElement) {
|
||||
|
||||
try {
|
||||
focusManager.focus(newElement);
|
||||
return;
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
}
|
||||
}
|
||||
focusManager.autoFocus(itemsContainer)
|
||||
|
||||
focusManager.autoFocus(itemsContainer);
|
||||
}
|
||||
var ItemsContainerProtoType = Object.create(HTMLDivElement.prototype);
|
||||
ItemsContainerProtoType.enableMultiSelect = function(enabled) {
|
||||
var current = this.multiSelect;
|
||||
if (!enabled) return void(current && (current.destroy(), this.multiSelect = null));
|
||||
if (!current) {
|
||||
var self = this;
|
||||
require(["multiSelect"], function(MultiSelect) {
|
||||
self.multiSelect = new MultiSelect({
|
||||
container: self,
|
||||
bindOnClick: !1
|
||||
})
|
||||
})
|
||||
}
|
||||
}, ItemsContainerProtoType.enableDragReordering = function(enabled) {
|
||||
var current = this.sortable;
|
||||
if (!enabled) return void(current && (current.destroy(), this.sortable = null));
|
||||
if (!current) {
|
||||
var self = this;
|
||||
require(["sortable"], function(Sortable) {
|
||||
self.sortable = new Sortable(self, {
|
||||
draggable: ".listItem",
|
||||
handle: ".listViewDragHandle",
|
||||
onEnd: function(evt) {
|
||||
return onDrop(evt, self)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}, ItemsContainerProtoType.createdCallback = function() {
|
||||
this.classList.add("itemsContainer")
|
||||
}, ItemsContainerProtoType.attachedCallback = function() {
|
||||
this.addEventListener("click", onClick), browser.touch ? this.addEventListener("contextmenu", disableEvent) : "false" !== this.getAttribute("data-contextmenu") && this.addEventListener("contextmenu", onContextMenu), (layoutManager.desktop || layoutManager.mobile) && "false" !== this.getAttribute("data-multiselect") && this.enableMultiSelect(!0), layoutManager.tv && this.classList.add("itemsContainer-tv"), itemShortcuts.on(this, getShortcutOptions()), addNotificationEvent(this, "UserDataChanged", onUserDataChanged), addNotificationEvent(this, "TimerCreated", onTimerCreated), addNotificationEvent(this, "SeriesTimerCreated", onSeriesTimerCreated), addNotificationEvent(this, "TimerCancelled", onTimerCancelled), addNotificationEvent(this, "SeriesTimerCancelled", onSeriesTimerCancelled), addNotificationEvent(this, "LibraryChanged", onLibraryChanged), addNotificationEvent(this, "playbackstop", onPlaybackStopped, playbackManager), "true" === this.getAttribute("data-dragreorder") && this.enableDragReordering(!0)
|
||||
}, ItemsContainerProtoType.detachedCallback = function() {
|
||||
clearRefreshInterval(this), this.enableMultiSelect(!1), this.enableDragReordering(!1), this.removeEventListener("click", onClick), this.removeEventListener("contextmenu", onContextMenu), this.removeEventListener("contextmenu", disableEvent), itemShortcuts.off(this, getShortcutOptions()), removeNotificationEvent(this, "UserDataChanged"), removeNotificationEvent(this, "TimerCreated"), removeNotificationEvent(this, "SeriesTimerCreated"), removeNotificationEvent(this, "TimerCancelled"), removeNotificationEvent(this, "SeriesTimerCancelled"), removeNotificationEvent(this, "LibraryChanged"), removeNotificationEvent(this, "playbackstop", playbackManager), this.fetchData = null, this.getItemsHtml = null, this.parentContainer = null
|
||||
}, ItemsContainerProtoType.pause = function() {
|
||||
clearRefreshInterval(this, !0), this.paused = !0
|
||||
}, ItemsContainerProtoType.resume = function(options) {
|
||||
this.paused = !1;
|
||||
var refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
if (refreshIntervalEndTime) {
|
||||
var remainingMs = refreshIntervalEndTime - (new Date).getTime();
|
||||
remainingMs > 0 && !this.needsRefresh ? resetRefreshInterval(this, remainingMs) : (this.needsRefresh = !0, this.refreshIntervalEndTime = null)
|
||||
}
|
||||
return this.needsRefresh || options && options.refresh ? this.refreshItems() : Promise.resolve()
|
||||
}, ItemsContainerProtoType.refreshItems = function() {
|
||||
return this.fetchData ? this.paused ? (this.needsRefresh = !0, Promise.resolve()) : (this.needsRefresh = !1, this.fetchData().then(onDataFetched.bind(this))) : Promise.resolve()
|
||||
}, ItemsContainerProtoType.notifyRefreshNeeded = function(isInForeground) {
|
||||
if (this.paused) return void(this.needsRefresh = !0);
|
||||
var timeout = this.refreshTimeout;
|
||||
timeout && clearTimeout(timeout), !0 === isInForeground ? this.refreshItems() : this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 1e4)
|
||||
}, document.registerElement("emby-itemscontainer", {
|
||||
|
||||
document.registerElement('emby-itemscontainer', {
|
||||
prototype: ItemsContainerProtoType,
|
||||
extends: "div"
|
||||
})
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
||||
@@ -1,157 +1,105 @@
|
||||
.progressring {
|
||||
.progressring {
|
||||
position: relative;
|
||||
width: 2.6em;
|
||||
height: 2.6em;
|
||||
float: left;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.progressring-bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
border: .25em solid rgba(0, 0, 0, 1);
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background: rgba(0, 0, 0, .9);
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center
|
||||
}
|
||||
|
||||
.spiner-holder-one,
|
||||
.spiner-holder-two {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
background: 0 0;
|
||||
-webkit-box-sizing: border-box
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.progressring-text {
|
||||
text-align: center;
|
||||
color: #ddd;
|
||||
font-size: 90%
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.spiner-holder-one {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
width: 51%;
|
||||
height: 51%;
|
||||
box-sizing: border-box
|
||||
background: transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.spiner-holder-two {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box
|
||||
background: transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.progressring-spiner {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
border-width: .25em;
|
||||
border-style: solid;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.animate-0-25-a {
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
transform-origin: 100% 100%;
|
||||
-webkit-transition: -webkit-transform 180ms ease-out;
|
||||
-o-transition: transform 180ms ease-out;
|
||||
transition: transform 180ms ease-out
|
||||
}
|
||||
|
||||
.animate-0-25-b,
|
||||
.animate-25-50-a {
|
||||
-webkit-transition: -webkit-transform 180ms ease-out;
|
||||
-o-transition: transform 180ms ease-out
|
||||
transition: transform 180ms ease-out;
|
||||
}
|
||||
|
||||
.animate-0-25-b {
|
||||
-webkit-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
transform-origin: 100% 100%;
|
||||
transition: transform 180ms ease-out
|
||||
transition: transform 180ms ease-out;
|
||||
}
|
||||
|
||||
.animate-25-50-a {
|
||||
-webkit-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
transform-origin: 100% 100%;
|
||||
transition: transform 180ms ease-out
|
||||
}
|
||||
|
||||
.animate-25-50-b,
|
||||
.animate-50-75-a {
|
||||
-webkit-transition: -webkit-transform 180ms ease-out;
|
||||
-o-transition: transform 180ms ease-out
|
||||
transition: transform 180ms ease-out;
|
||||
}
|
||||
|
||||
.animate-25-50-b {
|
||||
-webkit-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
transform-origin: 100% 100%;
|
||||
transition: transform 180ms ease-out
|
||||
transition: transform 180ms ease-out;
|
||||
}
|
||||
|
||||
.animate-50-75-a {
|
||||
-webkit-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
transform-origin: 100% 100%;
|
||||
transition: transform 180ms ease-out
|
||||
}
|
||||
|
||||
.animate-50-75-b,
|
||||
.animate-75-100-a {
|
||||
-webkit-transition: -webkit-transform 180ms ease-out;
|
||||
-o-transition: transform 180ms ease-out
|
||||
transition: transform 180ms ease-out;
|
||||
}
|
||||
|
||||
.animate-50-75-b {
|
||||
-webkit-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
transform-origin: 100% 100%;
|
||||
transition: transform 180ms ease-out
|
||||
transition: transform 180ms ease-out;
|
||||
}
|
||||
|
||||
.animate-75-100-a {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
transform: rotate(0deg);
|
||||
transform-origin: 100% 100%;
|
||||
transition: transform 180ms ease-out
|
||||
transition: transform 180ms ease-out;
|
||||
}
|
||||
|
||||
.animate-75-100-b {
|
||||
-webkit-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
transform-origin: 100% 100%;
|
||||
-webkit-transition: -webkit-transform 180ms ease-out;
|
||||
-o-transition: transform 180ms ease-out;
|
||||
transition: transform 180ms ease-out
|
||||
}
|
||||
transition: transform 180ms ease-out;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,105 @@
|
||||
define(["require", "css!./emby-progressring", "registerElement"], function(require) {
|
||||
"use strict";
|
||||
define(['require', 'css!./emby-progressring', 'registerElement'], function (require) {
|
||||
'use strict';
|
||||
|
||||
var EmbyProgressRing = Object.create(HTMLDivElement.prototype);
|
||||
return EmbyProgressRing.createdCallback = function() {
|
||||
this.classList.add("progressring");
|
||||
|
||||
EmbyProgressRing.createdCallback = function () {
|
||||
|
||||
this.classList.add('progressring');
|
||||
var instance = this;
|
||||
require(["text!./emby-progressring.template.html"], function(template) {
|
||||
instance.innerHTML = template, instance.setProgress(parseFloat(instance.getAttribute("data-progress") || "0"))
|
||||
})
|
||||
}, EmbyProgressRing.setProgress = function(progress) {
|
||||
|
||||
require(['text!./emby-progressring.template.html'], function (template) {
|
||||
instance.innerHTML = template;
|
||||
|
||||
//if (window.MutationObserver) {
|
||||
// // create an observer instance
|
||||
// var observer = new MutationObserver(function (mutations) {
|
||||
// mutations.forEach(function (mutation) {
|
||||
|
||||
// instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
|
||||
// });
|
||||
// });
|
||||
|
||||
// // configuration of the observer:
|
||||
// var config = { attributes: true, childList: false, characterData: false };
|
||||
|
||||
// // pass in the target node, as well as the observer options
|
||||
// observer.observe(instance, config);
|
||||
|
||||
// instance.observer = observer;
|
||||
//}
|
||||
|
||||
instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
|
||||
});
|
||||
};
|
||||
|
||||
EmbyProgressRing.setProgress = function (progress) {
|
||||
|
||||
progress = Math.floor(progress);
|
||||
|
||||
var angle;
|
||||
progress < 25 ? (angle = progress / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-25-50-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-50-75-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 25 && progress < 50 ? (angle = (progress - 25) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-50-75-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 50 && progress < 75 ? (angle = (progress - 50) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "none", this.querySelector(".animate-50-75-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 75 && progress <= 100 && (angle = (progress - 75) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "none", this.querySelector(".animate-50-75-b").style.transform = "none", this.querySelector(".animate-75-100-b").style.transform = "rotate(" + angle + "deg)"), this.querySelector(".progressring-text").innerHTML = progress + "%"
|
||||
}, EmbyProgressRing.attachedCallback = function() {}, EmbyProgressRing.detachedCallback = function() {
|
||||
|
||||
if (progress < 25) {
|
||||
angle = -90 + (progress / 100) * 360;
|
||||
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
}
|
||||
else if (progress >= 25 && progress < 50) {
|
||||
|
||||
angle = -90 + ((progress - 25) / 100) * 360;
|
||||
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
}
|
||||
else if (progress >= 50 && progress < 75) {
|
||||
angle = -90 + ((progress - 50) / 100) * 360;
|
||||
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'none';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
}
|
||||
else if (progress >= 75 && progress <= 100) {
|
||||
angle = -90 + ((progress - 75) / 100) * 360;
|
||||
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'none';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'none';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
}
|
||||
|
||||
this.querySelector('.progressring-text').innerHTML = progress + '%';
|
||||
};
|
||||
|
||||
EmbyProgressRing.attachedCallback = function () {
|
||||
|
||||
};
|
||||
|
||||
EmbyProgressRing.detachedCallback = function () {
|
||||
|
||||
|
||||
var observer = this.observer;
|
||||
observer && (observer.disconnect(), this.observer = null)
|
||||
}, document.registerElement("emby-progressring", {
|
||||
|
||||
if (observer) {
|
||||
// later, you can stop observing
|
||||
observer.disconnect();
|
||||
|
||||
this.observer = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-progressring', {
|
||||
prototype: EmbyProgressRing,
|
||||
extends: "div"
|
||||
}), EmbyProgressRing
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
return EmbyProgressRing;
|
||||
});
|
||||
@@ -2,26 +2,26 @@
|
||||
position: relative;
|
||||
line-height: 24px;
|
||||
display: inline-block;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding-left: 24px
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.radio-label-block {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
margin-top: .5em;
|
||||
margin-bottom: .5em
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
.mdl-radio {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.mdl-radio__button {
|
||||
line-height: 24px;
|
||||
position: absolute;
|
||||
/* 1px is for focusing purposes, so the focusManager doesn't skip over it */
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: 0;
|
||||
@@ -31,7 +31,7 @@
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
border: none
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mdl-radio__outer-circle {
|
||||
@@ -39,25 +39,23 @@
|
||||
top: 4px;
|
||||
left: 0;
|
||||
display: inline-block;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
border: 2px solid currentcolor;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
z-index: 2
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.mdl-radio__button:checked+.mdl-radio__label+.mdl-radio__outer-circle {
|
||||
border: 2px solid #00a4dc
|
||||
.mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle {
|
||||
border: 2px solid rgb(82, 181, 75);
|
||||
}
|
||||
|
||||
.mdl-radio__button:disabled+.mdl-radio__label+.mdl-radio__outer-circle {
|
||||
border: 2px solid rgba(0, 0, 0, .26);
|
||||
cursor: auto
|
||||
.mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle {
|
||||
border: 2px solid rgba(0,0,0, 0.26);
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.mdl-radio__inner-circle {
|
||||
@@ -66,52 +64,44 @@
|
||||
margin: 0;
|
||||
top: 8px;
|
||||
left: 4px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
cursor: pointer;
|
||||
-webkit-transition-duration: .28s;
|
||||
-o-transition-duration: .28s;
|
||||
transition-duration: .28s;
|
||||
-webkit-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
-o-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
-o-transition-property: transform;
|
||||
-webkit-transition-property: -webkit-transform, -webkit-transform;
|
||||
transition-duration: 0.28s;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-property: -webkit-transform;
|
||||
transition-property: transform;
|
||||
transition-property: transform, -webkit-transform;
|
||||
-webkit-transform: scale3d(0, 0, 0);
|
||||
transform: scale3d(0, 0, 0);
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
background: #00a4dc
|
||||
background: rgb(82, 181, 75);
|
||||
}
|
||||
|
||||
.mdl-radio__button:checked+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle {
|
||||
.mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1)
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
.mdl-radio__button:disabled+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle {
|
||||
background: rgba(0, 0, 0, .26);
|
||||
cursor: auto
|
||||
.mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
|
||||
background: rgba(0,0,0, 0.26);
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.mdl-radio__button:focus+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle {
|
||||
-webkit-box-shadow: 0 0 0 10px rgba(255, 255, 255, .76);
|
||||
box-shadow: 0 0 0 10px rgba(255, 255, 255, .76)
|
||||
.mdl-radio__button:focus + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
|
||||
box-shadow: 0 0 0px 10px rgba(255, 255, 255, 0.76);
|
||||
}
|
||||
|
||||
.mdl-radio__button:checked:focus+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle {
|
||||
-webkit-box-shadow: 0 0 0 10px rgba(0,164,220, .26);
|
||||
box-shadow: 0 0 0 10px rgba(0,164,220, .26)
|
||||
.mdl-radio__button:checked:focus + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
|
||||
box-shadow: 0 0 0px 10px rgba(82, 181, 75, 0.26);
|
||||
}
|
||||
|
||||
.mdl-radio__label {
|
||||
cursor: pointer
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mdl-radio__button:disabled+.mdl-radio__label {
|
||||
color: rgba(0, 0, 0, .26);
|
||||
cursor: auto
|
||||
}
|
||||
.mdl-radio__button:disabled + .mdl-radio__label {
|
||||
color: rgba(0,0,0, 0.26);
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,48 @@
|
||||
define(["css!./emby-radio", "registerElement"], function() {
|
||||
"use strict";
|
||||
define(['css!./emby-radio', 'registerElement'], function () {
|
||||
'use strict';
|
||||
|
||||
var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (13 === e.keyCode) return e.preventDefault(), this.checked = !0, !1
|
||||
}
|
||||
var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
|
||||
EmbyRadioPrototype.attachedCallback = function() {
|
||||
if ("true" !== this.getAttribute("data-radio")) {
|
||||
this.setAttribute("data-radio", "true"), this.classList.add("mdl-radio__button");
|
||||
var labelElement = this.parentNode;
|
||||
labelElement.classList.add("mdl-radio"), labelElement.classList.add("mdl-js-radio"), labelElement.classList.add("mdl-js-ripple-effect");
|
||||
var labelTextElement = labelElement.querySelector("span");
|
||||
labelTextElement.classList.add("radioButtonLabel"), labelTextElement.classList.add("mdl-radio__label"), labelElement.insertAdjacentHTML("beforeend", '<span class="mdl-radio__outer-circle"></span><span class="mdl-radio__inner-circle"></span>'), this.addEventListener("keydown", onKeyDown)
|
||||
|
||||
// Don't submit form on enter
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
|
||||
this.checked = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}, document.registerElement("emby-radio", {
|
||||
}
|
||||
|
||||
EmbyRadioPrototype.attachedCallback = function () {
|
||||
|
||||
if (this.getAttribute('data-radio') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setAttribute('data-radio', 'true');
|
||||
|
||||
this.classList.add('mdl-radio__button');
|
||||
|
||||
var labelElement = this.parentNode;
|
||||
//labelElement.classList.add('"mdl-radio mdl-js-radio mdl-js-ripple-effect');
|
||||
labelElement.classList.add('mdl-radio');
|
||||
labelElement.classList.add('mdl-js-radio');
|
||||
labelElement.classList.add('mdl-js-ripple-effect');
|
||||
|
||||
var labelTextElement = labelElement.querySelector('span');
|
||||
|
||||
labelTextElement.classList.add('radioButtonLabel');
|
||||
labelTextElement.classList.add('mdl-radio__label');
|
||||
|
||||
labelElement.insertAdjacentHTML('beforeend', '<span class="mdl-radio__outer-circle"></span><span class="mdl-radio__inner-circle"></span>');
|
||||
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
};
|
||||
|
||||
document.registerElement('emby-radio', {
|
||||
prototype: EmbyRadioPrototype,
|
||||
extends: "input"
|
||||
})
|
||||
extends: 'input'
|
||||
});
|
||||
});
|
||||
@@ -1,67 +1,60 @@
|
||||
.emby-scrollbuttons-scroller {
|
||||
position: relative
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.scrollbuttoncontainer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
font-size: 3em;
|
||||
color: #fff;
|
||||
display: none;
|
||||
overflow: hidden
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scrollbuttoncontainer-left {
|
||||
background: rgba(20, 20, 20, .5);
|
||||
background: -webkit-linear-gradient(left, #000 0, rgba(0, 0, 0, 0) 100%);
|
||||
background: -webkit-gradient(linear, left top, right top, from(#000), to(rgba(0, 0, 0, 0)));
|
||||
background: -webkit-linear-gradient(left, #000, rgba(0, 0, 0, 0));
|
||||
background: -o-linear-gradient(left, #000, rgba(0, 0, 0, 0));
|
||||
background: linear-gradient(to right, #000, rgba(0, 0, 0, 0));
|
||||
left: 0
|
||||
background: -moz-linear-gradient(left,#000 0,rgba(0,0,0,0) 100%);
|
||||
background: -webkit-linear-gradient(left,#000 0,rgba(0,0,0,0) 100%);
|
||||
background: linear-gradient(to right,#000,rgba(0,0,0,0));
|
||||
}
|
||||
|
||||
.scrollbuttoncontainer-right {
|
||||
background: rgba(20, 20, 20, .5);
|
||||
background: -webkit-linear-gradient(right, #000 0, rgba(0, 0, 0, 0) 100%);
|
||||
background: -webkit-gradient(linear, right top, left top, from(#000), to(rgba(0, 0, 0, 0)));
|
||||
background: -webkit-linear-gradient(right, #000, rgba(0, 0, 0, 0));
|
||||
background: -o-linear-gradient(right, #000, rgba(0, 0, 0, 0));
|
||||
background: linear-gradient(to left, #000, rgba(0, 0, 0, 0));
|
||||
right: 0
|
||||
background: -moz-linear-gradient(right,#000 0,rgba(0,0,0,0) 100%);
|
||||
background: -webkit-linear-gradient(right,#000 0,rgba(0,0,0,0) 100%);
|
||||
background: linear-gradient(to left,#000,rgba(0,0,0,0));
|
||||
}
|
||||
|
||||
.emby-scrollbuttons-scroller:hover .scrollbuttoncontainer {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.scrollbuttoncontainer-left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.scrollbuttoncontainer-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.emby-scrollbuttons-scrollbutton {
|
||||
margin: 0 -.2em;
|
||||
-webkit-transition: -webkit-transform 160ms ease-out;
|
||||
-o-transition: transform 160ms ease-out;
|
||||
transition: transform 160ms ease-out
|
||||
transition: transform 160ms ease-out;
|
||||
}
|
||||
|
||||
.scrollbuttoncontainer:hover>.emby-scrollbuttons-scrollbutton {
|
||||
-webkit-transform: scale(1.3, 1.3);
|
||||
transform: scale(1.3, 1.3)
|
||||
.scrollbuttoncontainer:hover > .emby-scrollbuttons-scrollbutton {
|
||||
transform: scale(1.3, 1.3);
|
||||
}
|
||||
|
||||
.emby-scrollbuttons-scrollbutton:after {
|
||||
content: '';
|
||||
display: none !important
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.emby-scrollbuttons-scrollbutton:focus {
|
||||
color: inherit !important
|
||||
}
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
@@ -1,75 +1,201 @@
|
||||
define(["layoutManager", "dom", "css!./emby-scrollbuttons", "registerElement", "paper-icon-button-light"], function(layoutManager, dom) {
|
||||
"use strict";
|
||||
define(['layoutManager', 'dom', 'css!./emby-scrollbuttons', 'registerElement', 'paper-icon-button-light'], function (layoutManager, dom) {
|
||||
'use strict';
|
||||
|
||||
var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
EmbyScrollButtonsPrototype.createdCallback = function () {
|
||||
|
||||
};
|
||||
|
||||
function getScrollButtonContainerHtml(direction) {
|
||||
var html = "";
|
||||
html += '<div class="scrollbuttoncontainer scrollbuttoncontainer-' + direction + ("left" === direction ? " hide" : "") + '">';
|
||||
var icon = "left" === direction ? "" : "";
|
||||
return html += '<button type="button" is="paper-icon-button-light" data-ripple="false" data-direction="' + direction + '" class="emby-scrollbuttons-scrollbutton">', html += '<i class="md-icon">' + icon + "</i>", html += "</button>", html += "</div>"
|
||||
|
||||
var html = '';
|
||||
|
||||
var hide = direction === 'left' ? ' hide' : '';
|
||||
html += '<div class="scrollbuttoncontainer scrollbuttoncontainer-' + direction + hide + '">';
|
||||
|
||||
var icon = direction === 'left' ? '' : '';
|
||||
|
||||
html += '<button type="button" is="paper-icon-button-light" data-ripple="false" data-direction="' + direction + '" class="emby-scrollbuttons-scrollbutton">';
|
||||
html += '<i class="md-icon">' + icon + '</i>';
|
||||
html += '</button>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function getScrollPosition(parent) {
|
||||
return parent.getScrollPosition ? parent.getScrollPosition() : 0
|
||||
|
||||
if (parent.getScrollPosition) {
|
||||
return parent.getScrollPosition();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getScrollWidth(parent) {
|
||||
return parent.getScrollSize ? parent.getScrollSize() : 0
|
||||
|
||||
if (parent.getScrollSize) {
|
||||
return parent.getScrollSize();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function onScrolledToPosition(scrollButtons, pos, scrollWidth) {
|
||||
pos > 0 ? scrollButtons.scrollButtonsLeft.classList.remove("hide") : scrollButtons.scrollButtonsLeft.classList.add("hide"), scrollWidth > 0 && (pos += scrollButtons.offsetWidth, pos >= scrollWidth ? scrollButtons.scrollButtonsRight.classList.add("hide") : scrollButtons.scrollButtonsRight.classList.remove("hide"))
|
||||
|
||||
if (pos > 0) {
|
||||
scrollButtons.scrollButtonsLeft.classList.remove('hide');
|
||||
} else {
|
||||
scrollButtons.scrollButtonsLeft.classList.add('hide');
|
||||
}
|
||||
|
||||
if (scrollWidth > 0) {
|
||||
|
||||
pos += scrollButtons.offsetWidth;
|
||||
|
||||
if (pos >= scrollWidth) {
|
||||
scrollButtons.scrollButtonsRight.classList.add('hide');
|
||||
} else {
|
||||
scrollButtons.scrollButtonsRight.classList.remove('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onScroll(e) {
|
||||
var scrollButtons = this,
|
||||
scroller = this.scroller;
|
||||
onScrolledToPosition(scrollButtons, getScrollPosition(scroller), getScrollWidth(scroller))
|
||||
|
||||
var scrollButtons = this;
|
||||
var scroller = this.scroller;
|
||||
var pos = getScrollPosition(scroller);
|
||||
var scrollWidth = getScrollWidth(scroller);
|
||||
|
||||
onScrolledToPosition(scrollButtons, pos, scrollWidth);
|
||||
}
|
||||
|
||||
function getStyleValue(style, name) {
|
||||
|
||||
var value = style.getPropertyValue(name);
|
||||
return value && (value = value.replace("px", "")) ? (value = parseInt(value), isNaN(value) ? 0 : value) : 0
|
||||
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = value.replace('px', '');
|
||||
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = parseInt(value);
|
||||
if (isNaN(value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function getScrollSize(elem) {
|
||||
var scrollSize = elem.offsetWidth,
|
||||
style = window.getComputedStyle(elem, null),
|
||||
paddingLeft = getStyleValue(style, "padding-left");
|
||||
paddingLeft && (scrollSize -= paddingLeft);
|
||||
var paddingRight = getStyleValue(style, "padding-right");
|
||||
paddingRight && (scrollSize -= paddingRight);
|
||||
|
||||
var scrollSize = elem.offsetWidth;
|
||||
|
||||
var style = window.getComputedStyle(elem, null);
|
||||
|
||||
var paddingLeft = getStyleValue(style, 'padding-left');
|
||||
|
||||
if (paddingLeft) {
|
||||
scrollSize -= paddingLeft;
|
||||
}
|
||||
var paddingRight = getStyleValue(style, 'padding-right');
|
||||
|
||||
if (paddingRight) {
|
||||
scrollSize -= paddingRight;
|
||||
}
|
||||
|
||||
var slider = elem.getScrollSlider();
|
||||
return style = window.getComputedStyle(slider, null), paddingLeft = getStyleValue(style, "padding-left"), paddingLeft && (scrollSize -= paddingLeft), paddingRight = getStyleValue(style, "padding-right"), paddingRight && (scrollSize -= paddingRight), scrollSize
|
||||
style = window.getComputedStyle(slider, null);
|
||||
|
||||
paddingLeft = getStyleValue(style, 'padding-left');
|
||||
|
||||
if (paddingLeft) {
|
||||
scrollSize -= paddingLeft;
|
||||
}
|
||||
paddingRight = getStyleValue(style, 'padding-right');
|
||||
|
||||
if (paddingRight) {
|
||||
scrollSize -= paddingRight;
|
||||
}
|
||||
|
||||
return scrollSize;
|
||||
}
|
||||
|
||||
function onScrollButtonClick(e) {
|
||||
var newPos, parent = dom.parentWithAttribute(this, "is", "emby-scroller"),
|
||||
direction = this.getAttribute("data-direction"),
|
||||
scrollSize = getScrollSize(parent),
|
||||
pos = getScrollPosition(parent);
|
||||
newPos = "left" === direction ? Math.max(0, pos - scrollSize) : pos + scrollSize, parent.scrollToPosition(newPos, !1)
|
||||
|
||||
var parent = dom.parentWithAttribute(this, 'is', 'emby-scroller');
|
||||
|
||||
var direction = this.getAttribute('data-direction');
|
||||
|
||||
var scrollSize = getScrollSize(parent);
|
||||
|
||||
var pos = getScrollPosition(parent);
|
||||
var newPos;
|
||||
|
||||
if (direction === 'left') {
|
||||
newPos = Math.max(0, pos - scrollSize);
|
||||
} else {
|
||||
newPos = pos + scrollSize;
|
||||
}
|
||||
|
||||
parent.scrollToPosition(newPos, false);
|
||||
}
|
||||
var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
|
||||
EmbyScrollButtonsPrototype.createdCallback = function() {}, EmbyScrollButtonsPrototype.attachedCallback = function() {
|
||||
var parent = dom.parentWithAttribute(this, "is", "emby-scroller");
|
||||
this.scroller = parent, parent.classList.add("emby-scrollbuttons-scroller"), this.innerHTML = getScrollButtonContainerHtml("left") + getScrollButtonContainerHtml("right");
|
||||
|
||||
EmbyScrollButtonsPrototype.attachedCallback = function () {
|
||||
|
||||
var parent = dom.parentWithAttribute(this, 'is', 'emby-scroller');
|
||||
this.scroller = parent;
|
||||
|
||||
parent.classList.add('emby-scrollbuttons-scroller');
|
||||
|
||||
this.innerHTML = getScrollButtonContainerHtml('left') + getScrollButtonContainerHtml('right');
|
||||
|
||||
var scrollHandler = onScroll.bind(this);
|
||||
this.scrollHandler = scrollHandler;
|
||||
var buttons = this.querySelectorAll(".emby-scrollbuttons-scrollbutton");
|
||||
buttons[0].addEventListener("click", onScrollButtonClick), buttons[1].addEventListener("click", onScrollButtonClick), buttons = this.querySelectorAll(".scrollbuttoncontainer"), this.scrollButtonsLeft = buttons[0], this.scrollButtonsRight = buttons[1], parent.addScrollEventListener(scrollHandler, {
|
||||
capture: !1,
|
||||
passive: !0
|
||||
})
|
||||
}, EmbyScrollButtonsPrototype.detachedCallback = function() {
|
||||
|
||||
var buttons = this.querySelectorAll('.emby-scrollbuttons-scrollbutton');
|
||||
buttons[0].addEventListener('click', onScrollButtonClick);
|
||||
buttons[1].addEventListener('click', onScrollButtonClick);
|
||||
|
||||
buttons = this.querySelectorAll('.scrollbuttoncontainer');
|
||||
this.scrollButtonsLeft = buttons[0];
|
||||
this.scrollButtonsRight = buttons[1];
|
||||
|
||||
parent.addScrollEventListener(scrollHandler, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
|
||||
EmbyScrollButtonsPrototype.detachedCallback = function () {
|
||||
|
||||
var parent = this.scroller;
|
||||
this.scroller = null;
|
||||
|
||||
var scrollHandler = this.scrollHandler;
|
||||
parent && scrollHandler && parent.removeScrollEventListener(scrollHandler, {
|
||||
capture: !1,
|
||||
passive: !0
|
||||
}), this.scrollHandler = null, this.scrollButtonsLeft = null, this.scrollButtonsRight = null
|
||||
}, document.registerElement("emby-scrollbuttons", {
|
||||
|
||||
if (parent && scrollHandler) {
|
||||
parent.removeScrollEventListener(scrollHandler, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
this.scrollHandler = null;
|
||||
this.scrollButtonsLeft = null;
|
||||
this.scrollButtonsRight = null;
|
||||
};
|
||||
|
||||
document.registerElement('emby-scrollbuttons', {
|
||||
prototype: EmbyScrollButtonsPrototype,
|
||||
extends: "div"
|
||||
})
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
||||
@@ -1,101 +1,224 @@
|
||||
define(["scroller", "dom", "layoutManager", "inputManager", "focusManager", "browser", "registerElement"], function(scroller, dom, layoutManager, inputManager, focusManager, browser) {
|
||||
"use strict";
|
||||
define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'browser', 'registerElement'], function (scroller, dom, layoutManager, inputManager, focusManager, browser) {
|
||||
'use strict';
|
||||
|
||||
var ScrollerProtoType = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
ScrollerProtoType.createdCallback = function () {
|
||||
this.classList.add('emby-scroller');
|
||||
};
|
||||
|
||||
function initCenterFocus(elem, scrollerInstance) {
|
||||
dom.addEventListener(elem, "focus", function(e) {
|
||||
|
||||
dom.addEventListener(elem, 'focus', function (e) {
|
||||
|
||||
var focused = focusManager.focusableParent(e.target);
|
||||
focused && scrollerInstance.toCenter(focused)
|
||||
|
||||
if (focused) {
|
||||
scrollerInstance.toCenter(focused);
|
||||
}
|
||||
|
||||
}, {
|
||||
capture: !0,
|
||||
passive: !0
|
||||
})
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
ScrollerProtoType.scrollToBeginning = function () {
|
||||
if (this.scroller) {
|
||||
this.scroller.slideTo(0, true);
|
||||
}
|
||||
};
|
||||
ScrollerProtoType.toStart = function (elem, immediate) {
|
||||
if (this.scroller) {
|
||||
this.scroller.toStart(elem, immediate);
|
||||
}
|
||||
};
|
||||
ScrollerProtoType.toCenter = function (elem, immediate) {
|
||||
if (this.scroller) {
|
||||
this.scroller.toCenter(elem, immediate);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.scrollToPosition = function (pos, immediate) {
|
||||
if (this.scroller) {
|
||||
this.scroller.slideTo(pos, immediate);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.getScrollPosition = function () {
|
||||
if (this.scroller) {
|
||||
return this.scroller.getScrollPosition();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.getScrollSize = function () {
|
||||
if (this.scroller) {
|
||||
return this.scroller.getScrollSize();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.getScrollEventName = function () {
|
||||
if (this.scroller) {
|
||||
return this.scroller.getScrollEventName();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.getScrollSlider = function () {
|
||||
if (this.scroller) {
|
||||
return this.scroller.getScrollSlider();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.addScrollEventListener = function (fn, options) {
|
||||
if (this.scroller) {
|
||||
dom.addEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.removeScrollEventListener = function (fn, options) {
|
||||
if (this.scroller) {
|
||||
dom.removeEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options);
|
||||
}
|
||||
};
|
||||
|
||||
function onInputCommand(e) {
|
||||
|
||||
var cmd = e.detail.command;
|
||||
"end" === cmd ? (focusManager.focusLast(this, "." + this.getAttribute("data-navcommands")), e.preventDefault(), e.stopPropagation()) : "pageup" === cmd ? (focusManager.moveFocus(e.target, this, "." + this.getAttribute("data-navcommands"), -12), e.preventDefault(), e.stopPropagation()) : "pagedown" === cmd && (focusManager.moveFocus(e.target, this, "." + this.getAttribute("data-navcommands"), 12), e.preventDefault(), e.stopPropagation())
|
||||
|
||||
if (cmd === 'end') {
|
||||
focusManager.focusLast(this, '.' + this.getAttribute('data-navcommands'));
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
else if (cmd === 'pageup') {
|
||||
focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), -12);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
else if (cmd === 'pagedown') {
|
||||
focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), 12);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
function initHeadroom(elem) {
|
||||
require(["headroom"], function(Headroom) {
|
||||
require(['headroom'], function (Headroom) {
|
||||
|
||||
var headroom = new Headroom([], {
|
||||
scroller: elem
|
||||
});
|
||||
headroom.init(), headroom.add(document.querySelector(".skinHeader")), elem.headroom = headroom
|
||||
})
|
||||
// initialise
|
||||
headroom.init();
|
||||
headroom.add(document.querySelector('.skinHeader'));
|
||||
elem.headroom = headroom;
|
||||
});
|
||||
}
|
||||
|
||||
ScrollerProtoType.attachedCallback = function () {
|
||||
|
||||
if (this.getAttribute('data-navcommands')) {
|
||||
inputManager.on(this, onInputCommand);
|
||||
}
|
||||
|
||||
var horizontal = this.getAttribute('data-horizontal') !== 'false';
|
||||
|
||||
var slider = this.querySelector('.scrollSlider');
|
||||
|
||||
if (horizontal) {
|
||||
slider.style['white-space'] = 'nowrap';
|
||||
}
|
||||
|
||||
var bindHeader = this.getAttribute('data-bindheader') === 'true';
|
||||
|
||||
var scrollFrame = this;
|
||||
var enableScrollButtons = layoutManager.desktop && horizontal && this.getAttribute('data-scrollbuttons') !== 'false';
|
||||
|
||||
var options = {
|
||||
horizontal: horizontal,
|
||||
mouseDragging: 1,
|
||||
mouseWheel: this.getAttribute('data-mousewheel') !== 'false',
|
||||
touchDragging: 1,
|
||||
slidee: slider,
|
||||
scrollBy: 200,
|
||||
speed: horizontal ? 270 : 240,
|
||||
//immediateSpeed: pageOptions.immediateSpeed,
|
||||
elasticBounds: 1,
|
||||
dragHandle: 1,
|
||||
scrollWidth: this.getAttribute('data-scrollsize') === 'auto' ? null : 5000000,
|
||||
autoImmediate: true,
|
||||
skipSlideToWhenVisible: this.getAttribute('data-skipfocuswhenvisible') === 'true',
|
||||
dispatchScrollEvent: enableScrollButtons || bindHeader || this.getAttribute('data-scrollevent') === 'true',
|
||||
hideScrollbar: enableScrollButtons || this.getAttribute('data-hidescrollbar') === 'true',
|
||||
allowNativeSmoothScroll: this.getAttribute('data-allownativesmoothscroll') === 'true' && !enableScrollButtons,
|
||||
allowNativeScroll: !enableScrollButtons,
|
||||
forceHideScrollbars: enableScrollButtons,
|
||||
|
||||
// In edge, with the native scroll, the content jumps around when hovering over the buttons
|
||||
requireAnimation: enableScrollButtons && browser.edge
|
||||
};
|
||||
|
||||
// If just inserted it might not have any height yet - yes this is a hack
|
||||
this.scroller = new scroller(scrollFrame, options);
|
||||
this.scroller.init();
|
||||
|
||||
if (layoutManager.tv && this.getAttribute('data-centerfocus')) {
|
||||
initCenterFocus(this, this.scroller);
|
||||
}
|
||||
|
||||
if (bindHeader) {
|
||||
initHeadroom(this);
|
||||
}
|
||||
|
||||
if (enableScrollButtons) {
|
||||
loadScrollButtons(this);
|
||||
}
|
||||
};
|
||||
|
||||
function loadScrollButtons(scroller) {
|
||||
require(["emby-scrollbuttons"], function() {
|
||||
scroller.insertAdjacentHTML("beforeend", '<div is="emby-scrollbuttons"></div>')
|
||||
})
|
||||
|
||||
require(['emby-scrollbuttons'], function () {
|
||||
scroller.insertAdjacentHTML('beforeend', '<div is="emby-scrollbuttons"></div>');
|
||||
});
|
||||
}
|
||||
var ScrollerProtoType = Object.create(HTMLDivElement.prototype);
|
||||
ScrollerProtoType.createdCallback = function() {
|
||||
this.classList.add("emby-scroller")
|
||||
}, ScrollerProtoType.scrollToBeginning = function() {
|
||||
this.scroller && this.scroller.slideTo(0, !0)
|
||||
}, ScrollerProtoType.toStart = function(elem, immediate) {
|
||||
this.scroller && this.scroller.toStart(elem, immediate)
|
||||
}, ScrollerProtoType.toCenter = function(elem, immediate) {
|
||||
this.scroller && this.scroller.toCenter(elem, immediate)
|
||||
}, ScrollerProtoType.scrollToPosition = function(pos, immediate) {
|
||||
this.scroller && this.scroller.slideTo(pos, immediate)
|
||||
}, ScrollerProtoType.getScrollPosition = function() {
|
||||
if (this.scroller) return this.scroller.getScrollPosition()
|
||||
}, ScrollerProtoType.getScrollSize = function() {
|
||||
if (this.scroller) return this.scroller.getScrollSize()
|
||||
}, ScrollerProtoType.getScrollEventName = function() {
|
||||
if (this.scroller) return this.scroller.getScrollEventName()
|
||||
}, ScrollerProtoType.getScrollSlider = function() {
|
||||
if (this.scroller) return this.scroller.getScrollSlider()
|
||||
}, ScrollerProtoType.addScrollEventListener = function(fn, options) {
|
||||
this.scroller && dom.addEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options)
|
||||
}, ScrollerProtoType.removeScrollEventListener = function(fn, options) {
|
||||
this.scroller && dom.removeEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options)
|
||||
}, ScrollerProtoType.attachedCallback = function() {
|
||||
this.getAttribute("data-navcommands") && inputManager.on(this, onInputCommand);
|
||||
var horizontal = "false" !== this.getAttribute("data-horizontal"),
|
||||
slider = this.querySelector(".scrollSlider");
|
||||
horizontal && (slider.style["white-space"] = "nowrap");
|
||||
var bindHeader = "true" === this.getAttribute("data-bindheader"),
|
||||
scrollFrame = this,
|
||||
enableScrollButtons = layoutManager.desktop && horizontal && "false" !== this.getAttribute("data-scrollbuttons"),
|
||||
options = {
|
||||
horizontal: horizontal,
|
||||
mouseDragging: 1,
|
||||
mouseWheel: "false" !== this.getAttribute("data-mousewheel"),
|
||||
touchDragging: 1,
|
||||
slidee: slider,
|
||||
scrollBy: 200,
|
||||
speed: horizontal ? 270 : 240,
|
||||
elasticBounds: 1,
|
||||
dragHandle: 1,
|
||||
scrollWidth: "auto" === this.getAttribute("data-scrollsize") ? null : 5e6,
|
||||
autoImmediate: !0,
|
||||
skipSlideToWhenVisible: "true" === this.getAttribute("data-skipfocuswhenvisible"),
|
||||
dispatchScrollEvent: enableScrollButtons || bindHeader || "true" === this.getAttribute("data-scrollevent"),
|
||||
hideScrollbar: enableScrollButtons || "true" === this.getAttribute("data-hidescrollbar"),
|
||||
allowNativeSmoothScroll: "true" === this.getAttribute("data-allownativesmoothscroll") && !enableScrollButtons,
|
||||
allowNativeScroll: !enableScrollButtons,
|
||||
forceHideScrollbars: enableScrollButtons,
|
||||
requireAnimation: enableScrollButtons && browser.edge
|
||||
};
|
||||
this.scroller = new scroller(scrollFrame, options), this.scroller.init(), layoutManager.tv && this.getAttribute("data-centerfocus") && initCenterFocus(this, this.scroller), bindHeader && initHeadroom(this), enableScrollButtons && loadScrollButtons(this)
|
||||
}, ScrollerProtoType.pause = function() {
|
||||
|
||||
ScrollerProtoType.pause = function () {
|
||||
|
||||
var headroom = this.headroom;
|
||||
headroom && headroom.pause()
|
||||
}, ScrollerProtoType.resume = function() {
|
||||
if (headroom) {
|
||||
headroom.pause();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.resume = function () {
|
||||
|
||||
var headroom = this.headroom;
|
||||
headroom && headroom.resume()
|
||||
}, ScrollerProtoType.detachedCallback = function() {
|
||||
this.getAttribute("data-navcommands") && inputManager.off(this, onInputCommand);
|
||||
if (headroom) {
|
||||
headroom.resume();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerProtoType.detachedCallback = function () {
|
||||
|
||||
if (this.getAttribute('data-navcommands')) {
|
||||
inputManager.off(this, onInputCommand);
|
||||
}
|
||||
|
||||
var headroom = this.headroom;
|
||||
headroom && (headroom.destroy(), this.headroom = null);
|
||||
if (headroom) {
|
||||
headroom.destroy();
|
||||
this.headroom = null;
|
||||
}
|
||||
|
||||
var scrollerInstance = this.scroller;
|
||||
scrollerInstance && (scrollerInstance.destroy(), this.scroller = null)
|
||||
}, document.registerElement("emby-scroller", {
|
||||
if (scrollerInstance) {
|
||||
scrollerInstance.destroy();
|
||||
this.scroller = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-scroller', {
|
||||
prototype: ScrollerProtoType,
|
||||
extends: "div"
|
||||
})
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
||||
@@ -2,91 +2,84 @@
|
||||
display: block;
|
||||
margin: 0;
|
||||
margin-bottom: 0 !important;
|
||||
/* Remove select styling */
|
||||
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
|
||||
font-size: 110%;
|
||||
/* General select styles: change as needed */
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
padding: .5em 1.9em .5em .5em;
|
||||
-webkit-box-sizing: border-box;
|
||||
/* Prevent padding from causing width overflow */
|
||||
box-sizing: border-box;
|
||||
outline: 0 !important;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
width: 100%
|
||||
outline: none !important;
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.emby-select[disabled] {
|
||||
background: 0 0 !important;
|
||||
border-color: transparent !important;
|
||||
color: inherit !important;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none
|
||||
}
|
||||
.emby-select[disabled] {
|
||||
background: none !important;
|
||||
border-color: transparent !important;
|
||||
color: inherit !important;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.selectContainer-inline>.emby-select {
|
||||
.selectContainer-inline > .emby-select {
|
||||
padding: .3em 1.9em .3em .5em;
|
||||
font-size: inherit
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.selectContainer-inline>.emby-select[disabled] {
|
||||
padding-left: 0;
|
||||
padding-right: 0
|
||||
}
|
||||
.selectContainer-inline > .emby-select[disabled] {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.emby-select::-moz-focus-inner {
|
||||
border: 0
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.emby-select-focusscale {
|
||||
-webkit-transition: -webkit-transform 180ms ease-out !important;
|
||||
-o-transition: transform 180ms ease-out !important;
|
||||
transition: transform 180ms ease-out !important;
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.emby-select-focusscale:focus {
|
||||
-webkit-transform: scale(1.04);
|
||||
transform: scale(1.04);
|
||||
z-index: 1
|
||||
}
|
||||
.emby-select-focusscale:focus {
|
||||
transform: scale(1.04);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.emby-select+.fieldDescription {
|
||||
margin-top: .25em
|
||||
.emby-select + .fieldDescription {
|
||||
margin-top: .25em;
|
||||
}
|
||||
|
||||
.selectContainer {
|
||||
margin-bottom: 1.8em;
|
||||
position: relative
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.selectContainer-inline {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex;
|
||||
margin-bottom: 0;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.selectLabel {
|
||||
display: block;
|
||||
margin-bottom: .25em
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
.selectContainer-inline>.selectLabel {
|
||||
.selectContainer-inline > .selectLabel {
|
||||
margin-bottom: 0;
|
||||
margin-right: .5em;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.emby-select-withcolor {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
-webkit-border-radius: .2em;
|
||||
border-radius: .2em
|
||||
border-radius: .2em;
|
||||
}
|
||||
|
||||
.selectArrowContainer {
|
||||
@@ -94,25 +87,24 @@
|
||||
right: .3em;
|
||||
top: .2em;
|
||||
color: inherit;
|
||||
pointer-events: none
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.selectContainer-inline>.selectArrowContainer {
|
||||
.selectContainer-inline > .selectArrowContainer {
|
||||
top: initial;
|
||||
bottom: .24em;
|
||||
font-size: 90%
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.emby-select[disabled]+.selectArrowContainer {
|
||||
display: none
|
||||
.emby-select[disabled] + .selectArrowContainer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selectArrow {
|
||||
margin-top: .35em;
|
||||
font-size: 1.7em
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
.emby-select-iconbutton {
|
||||
-webkit-align-self: flex-end;
|
||||
align-self: flex-end
|
||||
}
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
@@ -1,75 +1,168 @@
|
||||
define(["layoutManager", "browser", "actionsheet", "css!./emby-select", "registerElement"], function(layoutManager, browser, actionsheet) {
|
||||
"use strict";
|
||||
define(['layoutManager', 'browser', 'actionsheet', 'css!./emby-select', 'registerElement'], function (layoutManager, browser, actionsheet) {
|
||||
'use strict';
|
||||
|
||||
var EmbySelectPrototype = Object.create(HTMLSelectElement.prototype);
|
||||
|
||||
function enableNativeMenu() {
|
||||
return !(!browser.edgeUwp && !browser.xboxOne) || !(browser.tizen || browser.orsay || browser.web0s) && (!!browser.tv || !layoutManager.tv)
|
||||
|
||||
if (browser.edgeUwp || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Doesn't seem to work at all
|
||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Take advantage of the native input methods
|
||||
if (browser.tv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function triggerChange(select) {
|
||||
var evt = document.createEvent("HTMLEvents");
|
||||
evt.initEvent("change", !1, !0), select.dispatchEvent(evt)
|
||||
evt.initEvent("change", false, true);
|
||||
select.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
function setValue(select, value) {
|
||||
select.value = value
|
||||
|
||||
select.value = value;
|
||||
}
|
||||
|
||||
function showActionSheet(select) {
|
||||
var labelElem = getLabel(select),
|
||||
title = labelElem ? labelElem.textContent || labelElem.innerText : null;
|
||||
|
||||
var labelElem = getLabel(select);
|
||||
var title = labelElem ? (labelElem.textContent || labelElem.innerText) : null;
|
||||
|
||||
actionsheet.show({
|
||||
items: select.options,
|
||||
positionTo: select,
|
||||
title: title
|
||||
}).then(function(value) {
|
||||
setValue(select, value), triggerChange(select)
|
||||
})
|
||||
|
||||
}).then(function (value) {
|
||||
setValue(select, value);
|
||||
triggerChange(select);
|
||||
});
|
||||
}
|
||||
|
||||
function getLabel(select) {
|
||||
for (var elem = select.previousSibling; elem && "LABEL" !== elem.tagName;) elem = elem.previousSibling;
|
||||
return elem
|
||||
var elem = select.previousSibling;
|
||||
while (elem && elem.tagName !== 'LABEL') {
|
||||
elem = elem.previousSibling;
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
function onFocus(e) {
|
||||
var label = getLabel(this);
|
||||
label && label.classList.add("selectLabelFocused")
|
||||
if (label) {
|
||||
label.classList.add('selectLabelFocused');
|
||||
}
|
||||
}
|
||||
|
||||
function onBlur(e) {
|
||||
var label = getLabel(this);
|
||||
label && label.classList.remove("selectLabelFocused")
|
||||
if (label) {
|
||||
label.classList.remove('selectLabelFocused');
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
e.button || enableNativeMenu() || (e.preventDefault(), showActionSheet(this))
|
||||
|
||||
// e.button=0 for primary (left) mouse button click
|
||||
if (!e.button && !enableNativeMenu()) {
|
||||
e.preventDefault();
|
||||
showActionSheet(this);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDown(e) {
|
||||
|
||||
switch (e.keyCode) {
|
||||
|
||||
case 13:
|
||||
return void(enableNativeMenu() || (e.preventDefault(), showActionSheet(this)));
|
||||
if (!enableNativeMenu()) {
|
||||
e.preventDefault();
|
||||
showActionSheet(this);
|
||||
}
|
||||
return;
|
||||
case 37:
|
||||
case 38:
|
||||
case 39:
|
||||
case 40:
|
||||
return void(layoutManager.tv && e.preventDefault())
|
||||
if (layoutManager.tv) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
var EmbySelectPrototype = Object.create(HTMLSelectElement.prototype),
|
||||
inputId = 0;
|
||||
EmbySelectPrototype.createdCallback = function() {
|
||||
this.id || (this.id = "embyselect" + inputId, inputId++), browser.firefox || (this.classList.add("emby-select-withcolor"), layoutManager.tv && this.classList.add("emby-select-tv-withcolor")), layoutManager.tv && this.classList.add("emby-select-focusscale"), this.addEventListener("mousedown", onMouseDown), this.addEventListener("keydown", onKeyDown), this.addEventListener("focus", onFocus), this.addEventListener("blur", onBlur)
|
||||
}, EmbySelectPrototype.attachedCallback = function() {
|
||||
if (!this.classList.contains("emby-select")) {
|
||||
this.classList.add("emby-select");
|
||||
var label = this.ownerDocument.createElement("label");
|
||||
label.innerHTML = this.getAttribute("label") || "", label.classList.add("selectLabel"), label.htmlFor = this.id, this.parentNode.insertBefore(label, this), this.classList.contains("emby-select-withcolor") && this.parentNode.insertAdjacentHTML("beforeend", '<div class="selectArrowContainer"><div style="visibility:hidden;">0</div><i class="selectArrow md-icon"></i></div>')
|
||||
|
||||
var inputId = 0;
|
||||
|
||||
EmbySelectPrototype.createdCallback = function () {
|
||||
|
||||
if (!this.id) {
|
||||
this.id = 'embyselect' + inputId;
|
||||
inputId++;
|
||||
}
|
||||
}, EmbySelectPrototype.setLabel = function(text) {
|
||||
this.parentNode.querySelector("label").innerHTML = text
|
||||
}, document.registerElement("emby-select", {
|
||||
|
||||
if (!browser.firefox) {
|
||||
this.classList.add('emby-select-withcolor');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('emby-select-tv-withcolor');
|
||||
}
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('emby-select-focusscale');
|
||||
}
|
||||
|
||||
this.addEventListener('mousedown', onMouseDown);
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
|
||||
this.addEventListener('focus', onFocus);
|
||||
this.addEventListener('blur', onBlur);
|
||||
};
|
||||
|
||||
EmbySelectPrototype.attachedCallback = function () {
|
||||
|
||||
if (this.classList.contains('emby-select')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classList.add('emby-select');
|
||||
|
||||
var label = this.ownerDocument.createElement('label');
|
||||
label.innerHTML = this.getAttribute('label') || '';
|
||||
label.classList.add('selectLabel');
|
||||
label.htmlFor = this.id;
|
||||
this.parentNode.insertBefore(label, this);
|
||||
|
||||
if (this.classList.contains('emby-select-withcolor')) {
|
||||
this.parentNode.insertAdjacentHTML('beforeend', '<div class="selectArrowContainer"><div style="visibility:hidden;">0</div><i class="selectArrow md-icon"></i></div>');
|
||||
}
|
||||
};
|
||||
|
||||
EmbySelectPrototype.setLabel = function (text) {
|
||||
|
||||
var label = this.parentNode.querySelector('label');
|
||||
|
||||
label.innerHTML = text;
|
||||
};
|
||||
|
||||
document.registerElement('emby-select', {
|
||||
prototype: EmbySelectPrototype,
|
||||
extends: "select"
|
||||
})
|
||||
extends: 'select'
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
_:-ms-input-placeholder {
|
||||
-ms-appearance: none;
|
||||
height: 2.223em;
|
||||
margin: 0
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mdl-slider {
|
||||
@@ -11,87 +11,88 @@ _:-ms-input-placeholder {
|
||||
-ms-appearance: none;
|
||||
appearance: none;
|
||||
height: .2em;
|
||||
background: 0 0;
|
||||
background: transparent;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
outline: 0;
|
||||
padding: 1em 0;
|
||||
color: #00a4dc;
|
||||
color: #52B54B;
|
||||
-webkit-align-self: center;
|
||||
-ms-flex-item-align: center;
|
||||
align-self: center;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
display: block
|
||||
/* Disable webkit tap highlighting */
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
display: block;
|
||||
/**************************** Tracks ****************************/
|
||||
/**************************** Thumbs ****************************/
|
||||
/**************************** 0-value ****************************/
|
||||
/**************************** Disabled ****************************/
|
||||
}
|
||||
|
||||
.mdl-slider::-moz-focus-outer {
|
||||
border: 0
|
||||
}
|
||||
.mdl-slider::-moz-focus-outer {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.mdl-slider::-ms-tooltip {
|
||||
display: none
|
||||
}
|
||||
.mdl-slider::-ms-tooltip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mdl-slider::-webkit-slider-runnable-track {
|
||||
background: 0 0
|
||||
}
|
||||
.mdl-slider::-webkit-slider-runnable-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.mdl-slider::-moz-range-track {
|
||||
background: #444;
|
||||
border: none
|
||||
}
|
||||
.mdl-slider::-moz-range-track {
|
||||
background: #444;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mdl-slider::-moz-range-progress {
|
||||
background: #00a4dc
|
||||
}
|
||||
.mdl-slider::-moz-range-progress {
|
||||
background: #52B54B;
|
||||
}
|
||||
|
||||
.mdl-slider::-ms-track {
|
||||
background: 0 0;
|
||||
color: transparent;
|
||||
height: .2em;
|
||||
width: 100%;
|
||||
border: none
|
||||
}
|
||||
.mdl-slider::-ms-track {
|
||||
background: none;
|
||||
color: transparent;
|
||||
height: .2em;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mdl-slider::-ms-fill-lower {
|
||||
display: none
|
||||
}
|
||||
.mdl-slider::-ms-fill-lower {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mdl-slider::-ms-fill-upper {
|
||||
display: none
|
||||
}
|
||||
.mdl-slider::-ms-fill-upper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mdl-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 1.8em;
|
||||
height: 1.8em;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
background: #00a4dc;
|
||||
border: none;
|
||||
-webkit-transition: -webkit-transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), -webkit-box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1);
|
||||
transition: transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1)
|
||||
}
|
||||
.mdl-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 1.8em;
|
||||
height: 1.8em;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
background: #52B54B;
|
||||
border: none;
|
||||
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1), border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.mdl-slider-hoverthumb::-webkit-slider-thumb {
|
||||
margin-left: -.12em;
|
||||
-webkit-transform: scale(.7, .7);
|
||||
transform: scale(.7, .7)
|
||||
transform: scale(.7, .7);
|
||||
}
|
||||
|
||||
.mdl-slider:hover::-webkit-slider-thumb {
|
||||
-webkit-transform: none;
|
||||
transform: none
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.slider-no-webkit-thumb::-webkit-slider-thumb {
|
||||
opacity: 0 !important
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
.mdl-slider::-moz-range-thumb {
|
||||
@@ -100,8 +101,9 @@ _:-ms-input-placeholder {
|
||||
height: 1.8em;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
background: #00a4dc;
|
||||
border: none
|
||||
background-image: none;
|
||||
background: #52B54B;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mdl-slider::-ms-thumb {
|
||||
@@ -110,30 +112,30 @@ _:-ms-input-placeholder {
|
||||
height: 1.8em;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
background: #00a4dc;
|
||||
background: #52B54B;
|
||||
border: none;
|
||||
transition: transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1)
|
||||
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1), border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.mdl-slider-hoverthumb::-ms-thumb {
|
||||
margin-left: -.4em;
|
||||
transform: scale(.5, .5)
|
||||
transform: scale(.5, .5);
|
||||
}
|
||||
|
||||
.mdl-slider:hover::-ms-thumb {
|
||||
transform: none
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.mdl-slider[disabled]::-webkit-slider-thumb {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mdl-slider[disabled]::-moz-range-thumb {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mdl-slider[disabled]::-ms-thumb {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mdl-slider-ie-container {
|
||||
@@ -141,20 +143,15 @@ _:-ms-input-placeholder {
|
||||
overflow: visible;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mdl-slider-container {
|
||||
height: 1.25em;
|
||||
position: relative;
|
||||
background: 0 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
background: none;
|
||||
display: flex;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.mdl-slider-background-flex {
|
||||
@@ -165,70 +162,62 @@ _:-ms-input-placeholder {
|
||||
width: 100%;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
padding: 0
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mdl-slider-background-flex-inner {
|
||||
position: relative;
|
||||
width: 100%
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mdl-slider-background-lower {
|
||||
/*transition: width 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #00a4dc
|
||||
background-color: #52B54B;
|
||||
}
|
||||
|
||||
.mdl-slider-background-lower-clear {
|
||||
background-color: transparent
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.mdl-slider-background-lower-withtransform {
|
||||
width: 100%;
|
||||
-webkit-transform-origin: left center;
|
||||
/*transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/
|
||||
transform-origin: left center;
|
||||
-webkit-transform: scaleX(0);
|
||||
transform: scaleX(0)
|
||||
transform: scaleX(0);
|
||||
}
|
||||
|
||||
.mdl-slider-background-upper {
|
||||
/*transition: left 0.18s cubic-bezier(0.4, 0, 0.2, 1), width 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/
|
||||
background: #666;
|
||||
background: rgba(255, 255, 255, .4);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 0;
|
||||
top: 0;
|
||||
bottom: 0
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.sliderBubble {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
-webkit-transform: translate3d(-48%, -120%, 0);
|
||||
transform: translate3d(-48%, -120%, 0);
|
||||
background: #282828;
|
||||
color: #fff;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sliderBubbleText {
|
||||
margin: 0;
|
||||
padding: .5em .75em
|
||||
}
|
||||
padding: .5em .75em;
|
||||
}
|
||||
|
||||
@@ -1,101 +1,270 @@
|
||||
define(["browser", "dom", "layoutManager", "css!./emby-slider", "registerElement", "emby-input"], function(browser, dom, layoutManager) {
|
||||
"use strict";
|
||||
define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
var EmbySliderPrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
var supportsNativeProgressStyle = browser.firefox;
|
||||
var supportsValueSetOverride = false;
|
||||
|
||||
var enableWidthWithTransform;
|
||||
|
||||
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
|
||||
|
||||
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
|
||||
// descriptor returning null in webos
|
||||
if (descriptor && descriptor.configurable) {
|
||||
supportsValueSetOverride = true;
|
||||
}
|
||||
}
|
||||
|
||||
function updateValues() {
|
||||
var range = this,
|
||||
value = range.value;
|
||||
requestAnimationFrame(function() {
|
||||
|
||||
var range = this;
|
||||
var value = range.value;
|
||||
|
||||
// put this on a callback. Doing it within the event sometimes causes the slider to get hung up and not respond
|
||||
requestAnimationFrame(function () {
|
||||
|
||||
var backgroundLower = range.backgroundLower;
|
||||
|
||||
if (backgroundLower) {
|
||||
var fraction = (value - range.min) / (range.max - range.min);
|
||||
enableWidthWithTransform ? backgroundLower.style.transform = "scaleX(" + fraction + ")" : (fraction *= 100, backgroundLower.style.width = fraction + "%")
|
||||
|
||||
if (enableWidthWithTransform) {
|
||||
backgroundLower.style.transform = 'scaleX(' + (fraction) + ')';
|
||||
} else {
|
||||
fraction *= 100;
|
||||
backgroundLower.style.width = fraction + '%';
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function updateBubble(range, value, bubble, bubbleText) {
|
||||
requestAnimationFrame(function() {
|
||||
bubble.style.left = value + "%", range.getBubbleHtml ? value = range.getBubbleHtml(value) : (value = range.getBubbleText ? range.getBubbleText(value) : Math.round(value), value = '<h1 class="sliderBubbleText">' + value + "</h1>"), bubble.innerHTML = value
|
||||
})
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
|
||||
bubble.style.left = value + '%';
|
||||
|
||||
if (range.getBubbleHtml) {
|
||||
value = range.getBubbleHtml(value);
|
||||
} else {
|
||||
if (range.getBubbleText) {
|
||||
value = range.getBubbleText(value);
|
||||
} else {
|
||||
value = Math.round(value);
|
||||
}
|
||||
value = '<h1 class="sliderBubbleText">' + value + '</h1>';
|
||||
}
|
||||
|
||||
bubble.innerHTML = value;
|
||||
});
|
||||
}
|
||||
|
||||
EmbySliderPrototype.attachedCallback = function () {
|
||||
|
||||
if (this.getAttribute('data-embyslider') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enableWidthWithTransform == null) {
|
||||
//enableWidthWithTransform = browser.supportsCssAnimation();
|
||||
}
|
||||
|
||||
this.setAttribute('data-embyslider', 'true');
|
||||
|
||||
this.classList.add('mdl-slider');
|
||||
this.classList.add('mdl-js-slider');
|
||||
|
||||
if (browser.noFlex) {
|
||||
this.classList.add('slider-no-webkit-thumb');
|
||||
}
|
||||
if (!layoutManager.mobile) {
|
||||
this.classList.add('mdl-slider-hoverthumb');
|
||||
}
|
||||
|
||||
var containerElement = this.parentNode;
|
||||
containerElement.classList.add('mdl-slider-container');
|
||||
|
||||
var htmlToInsert = '';
|
||||
|
||||
if (!supportsNativeProgressStyle) {
|
||||
htmlToInsert += '<div class="mdl-slider-background-flex">';
|
||||
htmlToInsert += '<div class="mdl-slider-background-flex-inner">';
|
||||
|
||||
// the more of these, the more ranges we can display
|
||||
htmlToInsert += '<div class="mdl-slider-background-upper"></div>';
|
||||
|
||||
if (enableWidthWithTransform) {
|
||||
htmlToInsert += '<div class="mdl-slider-background-lower mdl-slider-background-lower-withtransform"></div>';
|
||||
} else {
|
||||
htmlToInsert += '<div class="mdl-slider-background-lower"></div>';
|
||||
}
|
||||
|
||||
htmlToInsert += '</div>';
|
||||
htmlToInsert += '</div>';
|
||||
}
|
||||
|
||||
htmlToInsert += '<div class="sliderBubble hide"></div>';
|
||||
|
||||
containerElement.insertAdjacentHTML('beforeend', htmlToInsert);
|
||||
|
||||
this.backgroundLower = containerElement.querySelector('.mdl-slider-background-lower');
|
||||
this.backgroundUpper = containerElement.querySelector('.mdl-slider-background-upper');
|
||||
var sliderBubble = containerElement.querySelector('.sliderBubble');
|
||||
|
||||
var hasHideClass = sliderBubble.classList.contains('hide');
|
||||
|
||||
dom.addEventListener(this, 'input', function (e) {
|
||||
this.dragging = true;
|
||||
|
||||
updateBubble(this, this.value, sliderBubble);
|
||||
|
||||
if (hasHideClass) {
|
||||
sliderBubble.classList.remove('hide');
|
||||
hasHideClass = false;
|
||||
}
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(this, 'change', function () {
|
||||
this.dragging = false;
|
||||
updateValues.call(this);
|
||||
|
||||
sliderBubble.classList.add('hide');
|
||||
hasHideClass = true;
|
||||
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
// In firefox this feature disrupts the ability to move the slider
|
||||
if (!browser.firefox) {
|
||||
dom.addEventListener(this, (window.PointerEvent ? 'pointermove' : 'mousemove'), function (e) {
|
||||
|
||||
if (!this.dragging) {
|
||||
var rect = this.getBoundingClientRect();
|
||||
var clientX = e.clientX;
|
||||
var bubbleValue = (clientX - rect.left) / rect.width;
|
||||
bubbleValue *= 100;
|
||||
updateBubble(this, bubbleValue, sliderBubble);
|
||||
|
||||
if (hasHideClass) {
|
||||
sliderBubble.classList.remove('hide');
|
||||
hasHideClass = false;
|
||||
}
|
||||
}
|
||||
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(this, (window.PointerEvent ? 'pointerleave' : 'mouseleave'), function () {
|
||||
sliderBubble.classList.add('hide');
|
||||
hasHideClass = true;
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!supportsNativeProgressStyle) {
|
||||
|
||||
if (supportsValueSetOverride) {
|
||||
this.addEventListener('valueset', updateValues);
|
||||
} else {
|
||||
startInterval(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function setRange(elem, startPercent, endPercent) {
|
||||
|
||||
var style = elem.style;
|
||||
style.left = Math.max(startPercent, 0) + "%";
|
||||
style.left = Math.max(startPercent, 0) + '%';
|
||||
|
||||
var widthPercent = endPercent - startPercent;
|
||||
style.width = Math.max(Math.min(widthPercent, 100), 0) + "%"
|
||||
style.width = Math.max(Math.min(widthPercent, 100), 0) + '%';
|
||||
}
|
||||
|
||||
function mapRangesFromRuntimeToPercent(ranges, runtime) {
|
||||
return runtime ? ranges.map(function(r) {
|
||||
|
||||
if (!runtime) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ranges.map(function (r) {
|
||||
|
||||
return {
|
||||
start: r.start / runtime * 100,
|
||||
end: r.end / runtime * 100
|
||||
}
|
||||
}) : []
|
||||
start: (r.start / runtime) * 100,
|
||||
end: (r.end / runtime) * 100
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
EmbySliderPrototype.setBufferedRanges = function (ranges, runtime, position) {
|
||||
|
||||
var elem = this.backgroundUpper;
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (runtime != null) {
|
||||
ranges = mapRangesFromRuntimeToPercent(ranges, runtime);
|
||||
|
||||
position = (position / runtime) * 100;
|
||||
}
|
||||
|
||||
for (var i = 0, length = ranges.length; i < length; i++) {
|
||||
|
||||
var range = ranges[i];
|
||||
|
||||
if (position != null) {
|
||||
if (position >= range.end) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
setRange(elem, range.start, range.end);
|
||||
return;
|
||||
}
|
||||
|
||||
setRange(elem, 0, 0);
|
||||
};
|
||||
|
||||
EmbySliderPrototype.setIsClear = function (isClear) {
|
||||
|
||||
var backgroundLower = this.backgroundLower;
|
||||
if (backgroundLower) {
|
||||
if (isClear) {
|
||||
backgroundLower.classList.add('mdl-slider-background-lower-clear');
|
||||
} else {
|
||||
backgroundLower.classList.remove('mdl-slider-background-lower-clear');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function startInterval(range) {
|
||||
var interval = range.interval;
|
||||
interval && clearInterval(interval), range.interval = setInterval(updateValues.bind(range), 100)
|
||||
}
|
||||
var enableWidthWithTransform, EmbySliderPrototype = Object.create(HTMLInputElement.prototype),
|
||||
supportsNativeProgressStyle = browser.firefox,
|
||||
supportsValueSetOverride = !1;
|
||||
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
|
||||
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
|
||||
descriptor && descriptor.configurable && (supportsValueSetOverride = !0)
|
||||
}
|
||||
EmbySliderPrototype.attachedCallback = function() {
|
||||
if ("true" !== this.getAttribute("data-embyslider")) {
|
||||
this.setAttribute("data-embyslider", "true"), this.classList.add("mdl-slider"), this.classList.add("mdl-js-slider"), browser.noFlex && this.classList.add("slider-no-webkit-thumb"), layoutManager.mobile || this.classList.add("mdl-slider-hoverthumb");
|
||||
var containerElement = this.parentNode;
|
||||
containerElement.classList.add("mdl-slider-container");
|
||||
var htmlToInsert = "";
|
||||
supportsNativeProgressStyle || (htmlToInsert += '<div class="mdl-slider-background-flex">', htmlToInsert += '<div class="mdl-slider-background-flex-inner">', htmlToInsert += '<div class="mdl-slider-background-upper"></div>', htmlToInsert += enableWidthWithTransform ? '<div class="mdl-slider-background-lower mdl-slider-background-lower-withtransform"></div>' : '<div class="mdl-slider-background-lower"></div>', htmlToInsert += "</div>", htmlToInsert += "</div>"), htmlToInsert += '<div class="sliderBubble hide"></div>', containerElement.insertAdjacentHTML("beforeend", htmlToInsert), this.backgroundLower = containerElement.querySelector(".mdl-slider-background-lower"), this.backgroundUpper = containerElement.querySelector(".mdl-slider-background-upper");
|
||||
var sliderBubble = containerElement.querySelector(".sliderBubble"),
|
||||
hasHideClass = sliderBubble.classList.contains("hide");
|
||||
dom.addEventListener(this, "input", function(e) {
|
||||
this.dragging = !0, updateBubble(this, this.value, sliderBubble), hasHideClass && (sliderBubble.classList.remove("hide"), hasHideClass = !1)
|
||||
}, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "change", function() {
|
||||
this.dragging = !1, updateValues.call(this), sliderBubble.classList.add("hide"), hasHideClass = !0
|
||||
}, {
|
||||
passive: !0
|
||||
}), browser.firefox || (dom.addEventListener(this, window.PointerEvent ? "pointermove" : "mousemove", function(e) {
|
||||
if (!this.dragging) {
|
||||
var rect = this.getBoundingClientRect(),
|
||||
clientX = e.clientX,
|
||||
bubbleValue = (clientX - rect.left) / rect.width;
|
||||
bubbleValue *= 100, updateBubble(this, bubbleValue, sliderBubble), hasHideClass && (sliderBubble.classList.remove("hide"), hasHideClass = !1)
|
||||
}
|
||||
}, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, window.PointerEvent ? "pointerleave" : "mouseleave", function() {
|
||||
sliderBubble.classList.add("hide"), hasHideClass = !0
|
||||
}, {
|
||||
passive: !0
|
||||
})), supportsNativeProgressStyle || (supportsValueSetOverride ? this.addEventListener("valueset", updateValues) : startInterval(this))
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, EmbySliderPrototype.setBufferedRanges = function(ranges, runtime, position) {
|
||||
var elem = this.backgroundUpper;
|
||||
if (elem) {
|
||||
null != runtime && (ranges = mapRangesFromRuntimeToPercent(ranges, runtime), position = position / runtime * 100);
|
||||
for (var i = 0, length = ranges.length; i < length; i++) {
|
||||
var range = ranges[i];
|
||||
if (!(null != position && position >= range.end)) return void setRange(elem, range.start, range.end)
|
||||
}
|
||||
setRange(elem, 0, 0)
|
||||
}
|
||||
}, EmbySliderPrototype.setIsClear = function(isClear) {
|
||||
var backgroundLower = this.backgroundLower;
|
||||
backgroundLower && (isClear ? backgroundLower.classList.add("mdl-slider-background-lower-clear") : backgroundLower.classList.remove("mdl-slider-background-lower-clear"))
|
||||
}, EmbySliderPrototype.detachedCallback = function() {
|
||||
range.interval = setInterval(updateValues.bind(range), 100);
|
||||
}
|
||||
|
||||
EmbySliderPrototype.detachedCallback = function () {
|
||||
|
||||
var interval = this.interval;
|
||||
interval && clearInterval(interval), this.interval = null, this.backgroundUpper = null, this.backgroundLower = null
|
||||
}, document.registerElement("emby-slider", {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
this.interval = null;
|
||||
this.backgroundUpper = null;
|
||||
this.backgroundLower = null;
|
||||
};
|
||||
|
||||
document.registerElement('emby-slider', {
|
||||
prototype: EmbySliderPrototype,
|
||||
extends: "input"
|
||||
})
|
||||
extends: 'input'
|
||||
});
|
||||
});
|
||||
@@ -1,43 +1,47 @@
|
||||
.emby-tab-button,
|
||||
.emby-tabs-slider {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.emby-tab-button {
|
||||
background: 0 0;
|
||||
-webkit-box-shadow: none;
|
||||
.emby-tab-button {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
outline: 0 !important;
|
||||
outline: none !important;
|
||||
width: auto;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
margin: 0;
|
||||
padding: 1em .9em;
|
||||
position: relative;
|
||||
height: auto;
|
||||
min-width: initial;
|
||||
line-height: initial;
|
||||
-webkit-border-radius: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
overflow: hidden;
|
||||
font-weight: 600
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.emby-tab-button.emby-button-tv:focus {
|
||||
-webkit-transform: scale(1.32);
|
||||
transform: scale(1.32);
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center
|
||||
/*.emby-tab-button-active {
|
||||
color: #52B54B;
|
||||
}
|
||||
|
||||
.emby-tab-button-active.emby-button-tv {
|
||||
color: #fff;
|
||||
}*/
|
||||
|
||||
.emby-tab-button.emby-button-tv:focus {
|
||||
/*color: #52B54B;*/
|
||||
transform: scale(1.32);
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.emby-tabs-slider {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.emby-tab-button-ripple-effect {
|
||||
background: rgba(0, 0, 0, .7) !important
|
||||
background: rgba(0,0,0,.7) !important;
|
||||
}
|
||||
|
||||
.tabContent:not(.is-active) {
|
||||
display: none
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,191 +1,370 @@
|
||||
define(["dom", "scroller", "browser", "layoutManager", "focusManager", "registerElement", "css!./emby-tabs", "scrollStyles"], function(dom, scroller, browser, layoutManager, focusManager) {
|
||||
"use strict";
|
||||
define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'registerElement', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser, layoutManager, focusManager) {
|
||||
'use strict';
|
||||
|
||||
var EmbyTabs = Object.create(HTMLDivElement.prototype);
|
||||
var buttonClass = 'emby-tab-button';
|
||||
var activeButtonClass = buttonClass + '-active';
|
||||
|
||||
function setActiveTabButton(tabs, newButton, oldButton, animate) {
|
||||
newButton.classList.add(activeButtonClass)
|
||||
|
||||
newButton.classList.add(activeButtonClass);
|
||||
}
|
||||
|
||||
function getFocusCallback(tabs, e) {
|
||||
return function() {
|
||||
onClick.call(tabs, e)
|
||||
}
|
||||
return function () {
|
||||
onClick.call(tabs, e);
|
||||
};
|
||||
}
|
||||
|
||||
function onFocus(e) {
|
||||
layoutManager.tv && (this.focusTimeout && clearTimeout(this.focusTimeout), this.focusTimeout = setTimeout(getFocusCallback(this, e), 700))
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
||||
if (this.focusTimeout) {
|
||||
clearTimeout(this.focusTimeout);
|
||||
}
|
||||
this.focusTimeout = setTimeout(getFocusCallback(this, e), 700);
|
||||
}
|
||||
}
|
||||
|
||||
function getTabPanel(tabs, index) {
|
||||
return null
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function removeActivePanelClass(tabs, index) {
|
||||
var tabPanel = getTabPanel(tabs, index);
|
||||
tabPanel && tabPanel.classList.remove("is-active")
|
||||
if (tabPanel) {
|
||||
tabPanel.classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
function addActivePanelClass(tabs, index) {
|
||||
var tabPanel = getTabPanel(tabs, index);
|
||||
if (tabPanel) {
|
||||
tabPanel.classList.add('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
function fadeInRight(elem) {
|
||||
var pct = browser.mobile ? "4%" : "0.5%",
|
||||
keyframes = [{
|
||||
opacity: "0",
|
||||
transform: "translate3d(" + pct + ", 0, 0)",
|
||||
offset: 0
|
||||
}, {
|
||||
opacity: "1",
|
||||
transform: "none",
|
||||
offset: 1
|
||||
}];
|
||||
|
||||
var pct = browser.mobile ? '4%' : '0.5%';
|
||||
|
||||
var keyframes = [
|
||||
{ opacity: '0', transform: 'translate3d(' + pct + ', 0, 0)', offset: 0 },
|
||||
{ opacity: '1', transform: 'none', offset: 1 }];
|
||||
|
||||
elem.animate(keyframes, {
|
||||
duration: 160,
|
||||
iterations: 1,
|
||||
easing: "ease-out"
|
||||
})
|
||||
easing: 'ease-out'
|
||||
});
|
||||
}
|
||||
|
||||
function triggerBeforeTabChange(tabs, index, previousIndex) {
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent("beforetabchange", {
|
||||
detail: {
|
||||
selectedTabIndex: index,
|
||||
previousIndex: previousIndex
|
||||
}
|
||||
})), null != previousIndex && previousIndex !== index && removeActivePanelClass(tabs, previousIndex);
|
||||
}));
|
||||
if (previousIndex != null && previousIndex !== index) {
|
||||
removeActivePanelClass(tabs, previousIndex);
|
||||
}
|
||||
|
||||
var newPanel = getTabPanel(tabs, index);
|
||||
newPanel && (newPanel.animate && fadeInRight(newPanel), newPanel.classList.add("is-active"))
|
||||
|
||||
if (newPanel) {
|
||||
// animate new panel ?
|
||||
if (newPanel.animate) {
|
||||
fadeInRight(newPanel);
|
||||
}
|
||||
|
||||
newPanel.classList.add('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
this.focusTimeout && clearTimeout(this.focusTimeout);
|
||||
var tabs = this,
|
||||
current = tabs.querySelector("." + activeButtonClass),
|
||||
tabButton = dom.parentWithClass(e.target, buttonClass);
|
||||
|
||||
if (this.focusTimeout) {
|
||||
clearTimeout(this.focusTimeout);
|
||||
}
|
||||
|
||||
var tabs = this;
|
||||
|
||||
var current = tabs.querySelector('.' + activeButtonClass);
|
||||
var tabButton = dom.parentWithClass(e.target, buttonClass);
|
||||
|
||||
if (tabButton && tabButton !== current) {
|
||||
current && current.classList.remove(activeButtonClass);
|
||||
var previousIndex = current ? parseInt(current.getAttribute("data-index")) : null;
|
||||
setActiveTabButton(tabs, tabButton, current, !0);
|
||||
var index = parseInt(tabButton.getAttribute("data-index"));
|
||||
triggerBeforeTabChange(tabs, index, previousIndex), setTimeout(function() {
|
||||
tabs.selectedTabIndex = index, tabs.dispatchEvent(new CustomEvent("tabchange", {
|
||||
|
||||
if (current) {
|
||||
current.classList.remove(activeButtonClass);
|
||||
}
|
||||
|
||||
var previousIndex = current ? parseInt(current.getAttribute('data-index')) : null;
|
||||
|
||||
setActiveTabButton(tabs, tabButton, current, true);
|
||||
|
||||
var index = parseInt(tabButton.getAttribute('data-index'));
|
||||
|
||||
triggerBeforeTabChange(tabs, index, previousIndex);
|
||||
|
||||
// If toCenter is called syncronously within the click event, it sometimes ends up canceling it
|
||||
setTimeout(function () {
|
||||
|
||||
tabs.selectedTabIndex = index;
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
||||
detail: {
|
||||
selectedTabIndex: index,
|
||||
previousIndex: previousIndex
|
||||
}
|
||||
}))
|
||||
}, 120), tabs.scroller && tabs.scroller.toCenter(tabButton, !1)
|
||||
}));
|
||||
}, 120);
|
||||
|
||||
if (tabs.scroller) {
|
||||
tabs.scroller.toCenter(tabButton, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function initScroller(tabs) {
|
||||
if (!tabs.scroller) {
|
||||
var contentScrollSlider = tabs.querySelector(".emby-tabs-slider");
|
||||
contentScrollSlider ? (tabs.scroller = new scroller(tabs, {
|
||||
|
||||
if (tabs.scroller) {
|
||||
return;
|
||||
}
|
||||
|
||||
var contentScrollSlider = tabs.querySelector('.emby-tabs-slider');
|
||||
if (contentScrollSlider) {
|
||||
tabs.scroller = new scroller(tabs, {
|
||||
horizontal: 1,
|
||||
itemNav: 0,
|
||||
mouseDragging: 1,
|
||||
touchDragging: 1,
|
||||
slidee: contentScrollSlider,
|
||||
smart: !0,
|
||||
releaseSwing: !0,
|
||||
smart: true,
|
||||
releaseSwing: true,
|
||||
scrollBy: 200,
|
||||
speed: 120,
|
||||
elasticBounds: 1,
|
||||
dragHandle: 1,
|
||||
dynamicHandle: 1,
|
||||
clickBar: 1,
|
||||
hiddenScroll: !0,
|
||||
hiddenScroll: true,
|
||||
|
||||
// In safari the transform is causing the headers to occasionally disappear or flicker
|
||||
requireAnimation: !browser.safari,
|
||||
allowNativeSmoothScroll: !0
|
||||
}), tabs.scroller.init()) : (tabs.classList.add("scrollX"), tabs.classList.add("hiddenScrollX"), tabs.classList.add("smoothScrollX"))
|
||||
}
|
||||
allowNativeSmoothScroll: true
|
||||
});
|
||||
tabs.scroller.init();
|
||||
} else {
|
||||
tabs.classList.add('scrollX');
|
||||
tabs.classList.add('hiddenScrollX');
|
||||
tabs.classList.add('smoothScrollX');
|
||||
}
|
||||
}
|
||||
|
||||
EmbyTabs.createdCallback = function () {
|
||||
|
||||
if (this.classList.contains('emby-tabs')) {
|
||||
return;
|
||||
}
|
||||
this.classList.add('emby-tabs');
|
||||
this.classList.add('focusable');
|
||||
|
||||
dom.addEventListener(this, 'click', onClick, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'focus', onFocus, {
|
||||
passive: true,
|
||||
capture: true
|
||||
});
|
||||
};
|
||||
|
||||
EmbyTabs.focus = function () {
|
||||
|
||||
var selected = this.querySelector('.' + activeButtonClass);
|
||||
|
||||
if (selected) {
|
||||
focusManager.focus(selected);
|
||||
} else {
|
||||
focusManager.autoFocus(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.refresh = function () {
|
||||
|
||||
if (this.scroller) {
|
||||
this.scroller.reload();
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.attachedCallback = function () {
|
||||
|
||||
initScroller(this);
|
||||
|
||||
var current = this.querySelector('.' + activeButtonClass);
|
||||
var currentIndex = current ? parseInt(current.getAttribute('data-index')) : parseInt(this.getAttribute('data-index') || '0');
|
||||
|
||||
if (currentIndex !== -1) {
|
||||
|
||||
this.selectedTabIndex = currentIndex;
|
||||
|
||||
var tabButtons = this.querySelectorAll('.' + buttonClass);
|
||||
|
||||
var newTabButton = tabButtons[currentIndex];
|
||||
|
||||
if (newTabButton) {
|
||||
setActiveTabButton(this, newTabButton, current, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.readyFired) {
|
||||
this.readyFired = true;
|
||||
this.dispatchEvent(new CustomEvent("ready", {}));
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.detachedCallback = function () {
|
||||
|
||||
if (this.scroller) {
|
||||
this.scroller.destroy();
|
||||
this.scroller = null;
|
||||
}
|
||||
|
||||
dom.removeEventListener(this, 'click', onClick, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'focus', onFocus, {
|
||||
passive: true,
|
||||
capture: true
|
||||
});
|
||||
};
|
||||
|
||||
function getSelectedTabButton(elem) {
|
||||
return elem.querySelector("." + activeButtonClass)
|
||||
|
||||
return elem.querySelector('.' + activeButtonClass);
|
||||
}
|
||||
|
||||
function getSibling(elem, method) {
|
||||
for (var sibling = elem[method]; sibling;) {
|
||||
if (sibling.classList.contains(buttonClass) && !sibling.classList.contains("hide")) return sibling;
|
||||
sibling = sibling[method]
|
||||
}
|
||||
return null
|
||||
}
|
||||
var EmbyTabs = Object.create(HTMLDivElement.prototype),
|
||||
buttonClass = "emby-tab-button",
|
||||
activeButtonClass = buttonClass + "-active";
|
||||
EmbyTabs.createdCallback = function() {
|
||||
this.classList.contains("emby-tabs") || (this.classList.add("emby-tabs"), this.classList.add("focusable"), dom.addEventListener(this, "click", onClick, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(this, "focus", onFocus, {
|
||||
passive: !0,
|
||||
capture: !0
|
||||
}))
|
||||
}, EmbyTabs.focus = function() {
|
||||
var selected = this.querySelector("." + activeButtonClass);
|
||||
selected ? focusManager.focus(selected) : focusManager.autoFocus(this)
|
||||
}, EmbyTabs.refresh = function() {
|
||||
this.scroller && this.scroller.reload()
|
||||
}, EmbyTabs.attachedCallback = function() {
|
||||
initScroller(this);
|
||||
var current = this.querySelector("." + activeButtonClass),
|
||||
currentIndex = current ? parseInt(current.getAttribute("data-index")) : parseInt(this.getAttribute("data-index") || "0");
|
||||
if (-1 !== currentIndex) {
|
||||
this.selectedTabIndex = currentIndex;
|
||||
var tabButtons = this.querySelectorAll("." + buttonClass),
|
||||
newTabButton = tabButtons[currentIndex];
|
||||
newTabButton && setActiveTabButton(this, newTabButton, current, !1)
|
||||
}
|
||||
this.readyFired || (this.readyFired = !0, this.dispatchEvent(new CustomEvent("ready", {})))
|
||||
}, EmbyTabs.detachedCallback = function() {
|
||||
this.scroller && (this.scroller.destroy(), this.scroller = null), dom.removeEventListener(this, "click", onClick, {
|
||||
passive: !0
|
||||
}), dom.removeEventListener(this, "focus", onFocus, {
|
||||
passive: !0,
|
||||
capture: !0
|
||||
})
|
||||
}, EmbyTabs.selectedIndex = function(selected, triggerEvent) {
|
||||
EmbyTabs.selectedIndex = function (selected, triggerEvent) {
|
||||
|
||||
var tabs = this;
|
||||
if (null == selected) return tabs.selectedTabIndex || 0;
|
||||
|
||||
if (selected == null) {
|
||||
|
||||
return tabs.selectedTabIndex || 0;
|
||||
}
|
||||
|
||||
var current = tabs.selectedIndex();
|
||||
|
||||
tabs.selectedTabIndex = selected;
|
||||
var tabButtons = tabs.querySelectorAll("." + buttonClass);
|
||||
if (current === selected || !1 === triggerEvent) {
|
||||
triggerBeforeTabChange(tabs, selected, current), tabs.dispatchEvent(new CustomEvent("tabchange", {
|
||||
|
||||
var tabButtons = tabs.querySelectorAll('.' + buttonClass);
|
||||
|
||||
if (current === selected || triggerEvent === false) {
|
||||
|
||||
triggerBeforeTabChange(tabs, selected, current);
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
||||
detail: {
|
||||
selectedTabIndex: selected
|
||||
}
|
||||
}));
|
||||
|
||||
var currentTabButton = tabButtons[current];
|
||||
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, !1), current !== selected && currentTabButton && currentTabButton.classList.remove(activeButtonClass)
|
||||
} else onClick.call(tabs, {
|
||||
target: tabButtons[selected]
|
||||
})
|
||||
}, EmbyTabs.selectNext = function() {
|
||||
var current = getSelectedTabButton(this),
|
||||
sibling = getSibling(current, "nextSibling");
|
||||
sibling && onClick.call(this, {
|
||||
target: sibling
|
||||
})
|
||||
}, EmbyTabs.selectPrevious = function() {
|
||||
var current = getSelectedTabButton(this),
|
||||
sibling = getSibling(current, "previousSibling");
|
||||
sibling && onClick.call(this, {
|
||||
target: sibling
|
||||
})
|
||||
}, EmbyTabs.triggerBeforeTabChange = function(selected) {
|
||||
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, false);
|
||||
|
||||
if (current !== selected && currentTabButton) {
|
||||
currentTabButton.classList.remove(activeButtonClass);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
onClick.call(tabs, {
|
||||
target: tabButtons[selected]
|
||||
});
|
||||
//tabButtons[selected].click();
|
||||
}
|
||||
};
|
||||
|
||||
function getSibling(elem, method) {
|
||||
|
||||
var sibling = elem[method];
|
||||
|
||||
while (sibling) {
|
||||
if (sibling.classList.contains(buttonClass)) {
|
||||
|
||||
if (!sibling.classList.contains('hide')) {
|
||||
return sibling;
|
||||
}
|
||||
}
|
||||
|
||||
sibling = sibling[method];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
EmbyTabs.selectNext = function () {
|
||||
|
||||
var current = getSelectedTabButton(this);
|
||||
|
||||
var sibling = getSibling(current, 'nextSibling');
|
||||
|
||||
if (sibling) {
|
||||
onClick.call(this, {
|
||||
target: sibling
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.selectPrevious = function () {
|
||||
|
||||
var current = getSelectedTabButton(this);
|
||||
|
||||
var sibling = getSibling(current, 'previousSibling');
|
||||
|
||||
if (sibling) {
|
||||
onClick.call(this, {
|
||||
target: sibling
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.triggerBeforeTabChange = function (selected) {
|
||||
|
||||
var tabs = this;
|
||||
triggerBeforeTabChange(tabs, tabs.selectedIndex())
|
||||
}, EmbyTabs.triggerTabChange = function(selected) {
|
||||
|
||||
triggerBeforeTabChange(tabs, tabs.selectedIndex());
|
||||
};
|
||||
|
||||
EmbyTabs.triggerTabChange = function (selected) {
|
||||
|
||||
var tabs = this;
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
||||
detail: {
|
||||
selectedTabIndex: tabs.selectedIndex()
|
||||
}
|
||||
}))
|
||||
}, EmbyTabs.setTabEnabled = function(index, enabled) {
|
||||
}));
|
||||
};
|
||||
|
||||
EmbyTabs.setTabEnabled = function (index, enabled) {
|
||||
|
||||
var tabs = this;
|
||||
var btn = this.querySelector('.emby-tab-button[data-index="' + index + '"]');
|
||||
enabled ? btn.classList.remove("hide") : btn.classList.remove("add")
|
||||
}, document.registerElement("emby-tabs", {
|
||||
|
||||
if (enabled) {
|
||||
btn.classList.remove('hide');
|
||||
} else {
|
||||
btn.classList.remove('add');
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-tabs', {
|
||||
prototype: EmbyTabs,
|
||||
extends: "div"
|
||||
})
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
||||
@@ -2,30 +2,31 @@
|
||||
display: block;
|
||||
margin: 0;
|
||||
margin-bottom: 0 !important;
|
||||
/* Remove select styling */
|
||||
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
|
||||
font-size: inherit;
|
||||
/* General select styles: change as needed */
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
padding: .35em .25em;
|
||||
-webkit-box-sizing: border-box;
|
||||
/* Prevent padding from causing width overflow */
|
||||
box-sizing: border-box;
|
||||
outline: 0 !important;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
width: 100%
|
||||
outline: none !important;
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.emby-textarea::-moz-focus-inner {
|
||||
border: 0
|
||||
}
|
||||
.emby-textarea::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.textareaLabel {
|
||||
display: inline-block;
|
||||
-webkit-transition: all .2s ease-out;
|
||||
-o-transition: all .2s ease-out;
|
||||
transition: all .2s ease-out;
|
||||
margin-bottom: .25em
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
.emby-textarea+.fieldDescription {
|
||||
margin-top: .25em
|
||||
}
|
||||
.emby-textarea + .fieldDescription {
|
||||
margin-top: .25em;
|
||||
}
|
||||
|
||||
@@ -1,55 +1,138 @@
|
||||
define(["layoutManager", "browser", "css!./emby-textarea", "registerElement", "emby-input"], function(layoutManager, browser) {
|
||||
"use strict";
|
||||
define(['layoutManager', 'browser', 'css!./emby-textarea', 'registerElement', 'emby-input'], function (layoutManager, browser) {
|
||||
'use strict';
|
||||
|
||||
function autoGrow(textarea, maxLines) {
|
||||
var self = this;
|
||||
|
||||
if (maxLines === undefined) {
|
||||
maxLines = 999;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the vertical padding of the element
|
||||
* @param textarea
|
||||
* @returns {number}
|
||||
*/
|
||||
self.getOffset = function (textarea) {
|
||||
var style = window.getComputedStyle(textarea, null),
|
||||
props = ['paddingTop', 'paddingBottom'],
|
||||
offset = 0;
|
||||
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
offset += parseInt(style[props[i]]);
|
||||
}
|
||||
return offset;
|
||||
};
|
||||
|
||||
var offset;
|
||||
function reset() {
|
||||
textarea.rows = 1, offset = self.getOffset(textarea), self.rows = textarea.rows || 1, self.lineHeight = textarea.scrollHeight / self.rows - offset / self.rows, self.maxAllowedHeight = self.lineHeight * maxLines - offset
|
||||
textarea.rows = 1;
|
||||
offset = self.getOffset(textarea);
|
||||
self.rows = textarea.rows || 1;
|
||||
self.lineHeight = (textarea.scrollHeight / self.rows) - (offset / self.rows);
|
||||
self.maxAllowedHeight = (self.lineHeight * maxLines) - offset;
|
||||
}
|
||||
|
||||
function autogrowFn() {
|
||||
if ((!self.lineHeight || self.lineHeight <= 0) && reset(), self.lineHeight <= 0) return textarea.style.overflowY = "scroll", textarea.style.height = "auto", void(textarea.rows = 3);
|
||||
var newHeight = 0;
|
||||
textarea.scrollHeight - offset > self.maxAllowedHeight ? (textarea.style.overflowY = "scroll", newHeight = self.maxAllowedHeight) : (textarea.style.overflowY = "hidden", textarea.style.height = "auto", newHeight = textarea.scrollHeight), textarea.style.height = newHeight + "px"
|
||||
if (!self.lineHeight || self.lineHeight <= 0) {
|
||||
reset();
|
||||
}
|
||||
if (self.lineHeight <= 0) {
|
||||
textarea.style.overflowY = 'scroll';
|
||||
textarea.style.height = 'auto';
|
||||
textarea.rows = 3;
|
||||
return;
|
||||
}
|
||||
var newHeight = 0, hasGrown = false;
|
||||
|
||||
if ((textarea.scrollHeight - offset) > self.maxAllowedHeight) {
|
||||
textarea.style.overflowY = 'scroll';
|
||||
newHeight = self.maxAllowedHeight;
|
||||
}
|
||||
else {
|
||||
textarea.style.overflowY = 'hidden';
|
||||
textarea.style.height = 'auto';
|
||||
newHeight = textarea.scrollHeight/* - offset*/;
|
||||
hasGrown = true;
|
||||
}
|
||||
textarea.style.height = newHeight + 'px';
|
||||
}
|
||||
var self = this;
|
||||
void 0 === maxLines && (maxLines = 999), self.getOffset = function(textarea) {
|
||||
for (var style = window.getComputedStyle(textarea, null), props = ["paddingTop", "paddingBottom"], offset = 0, i = 0; i < props.length; i++) offset += parseInt(style[props[i]]);
|
||||
return offset
|
||||
};
|
||||
var offset;
|
||||
textarea.addEventListener("input", autogrowFn), textarea.addEventListener("focus", autogrowFn), textarea.addEventListener("valueset", autogrowFn), autogrowFn()
|
||||
|
||||
// Call autogrowFn() when textarea's value is changed
|
||||
textarea.addEventListener('input', autogrowFn);
|
||||
textarea.addEventListener('focus', autogrowFn);
|
||||
textarea.addEventListener('valueset', autogrowFn);
|
||||
|
||||
autogrowFn();
|
||||
}
|
||||
var EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype),
|
||||
elementId = 0;
|
||||
|
||||
var EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype);
|
||||
|
||||
var elementId = 0;
|
||||
|
||||
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
|
||||
var descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value");
|
||||
|
||||
var descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
|
||||
|
||||
// descriptor returning null in webos
|
||||
if (descriptor && descriptor.configurable) {
|
||||
var baseSetMethod = descriptor.set;
|
||||
descriptor.set = function(value) {
|
||||
baseSetMethod.call(this, value), this.dispatchEvent(new CustomEvent("valueset", {
|
||||
bubbles: !1,
|
||||
cancelable: !1
|
||||
}))
|
||||
}, Object.defineProperty(HTMLTextAreaElement.prototype, "value", descriptor)
|
||||
descriptor.set = function (value) {
|
||||
baseSetMethod.call(this, value);
|
||||
|
||||
this.dispatchEvent(new CustomEvent('valueset', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
};
|
||||
|
||||
Object.defineProperty(HTMLTextAreaElement.prototype, 'value', descriptor);
|
||||
}
|
||||
}
|
||||
EmbyTextAreaPrototype.createdCallback = function() {
|
||||
this.id || (this.id = "embytextarea" + elementId, elementId++)
|
||||
}, EmbyTextAreaPrototype.attachedCallback = function() {
|
||||
if (!this.classList.contains("emby-textarea")) {
|
||||
this.rows = 1, this.classList.add("emby-textarea");
|
||||
var parentNode = this.parentNode,
|
||||
label = this.ownerDocument.createElement("label");
|
||||
label.innerHTML = this.getAttribute("label") || "", label.classList.add("textareaLabel"), label.htmlFor = this.id, parentNode.insertBefore(label, this), this.addEventListener("focus", function() {
|
||||
label.classList.add("textareaLabelFocused"), label.classList.remove("textareaLabelUnfocused")
|
||||
}), this.addEventListener("blur", function() {
|
||||
label.classList.remove("textareaLabelFocused"), label.classList.add("textareaLabelUnfocused")
|
||||
}), this.label = function(text) {
|
||||
label.innerHTML = text
|
||||
}, new autoGrow(this)
|
||||
|
||||
EmbyTextAreaPrototype.createdCallback = function () {
|
||||
|
||||
if (!this.id) {
|
||||
this.id = 'embytextarea' + elementId;
|
||||
elementId++;
|
||||
}
|
||||
}, document.registerElement("emby-textarea", {
|
||||
};
|
||||
|
||||
EmbyTextAreaPrototype.attachedCallback = function () {
|
||||
|
||||
if (this.classList.contains('emby-textarea')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rows = 1;
|
||||
this.classList.add('emby-textarea');
|
||||
|
||||
var parentNode = this.parentNode;
|
||||
var label = this.ownerDocument.createElement('label');
|
||||
label.innerHTML = this.getAttribute('label') || '';
|
||||
label.classList.add('textareaLabel');
|
||||
|
||||
label.htmlFor = this.id;
|
||||
parentNode.insertBefore(label, this);
|
||||
|
||||
this.addEventListener('focus', function () {
|
||||
label.classList.add('textareaLabelFocused');
|
||||
label.classList.remove('textareaLabelUnfocused');
|
||||
});
|
||||
this.addEventListener('blur', function () {
|
||||
label.classList.remove('textareaLabelFocused');
|
||||
label.classList.add('textareaLabelUnfocused');
|
||||
});
|
||||
|
||||
this.label = function (text) {
|
||||
label.innerHTML = text;
|
||||
};
|
||||
|
||||
new autoGrow(this);
|
||||
};
|
||||
|
||||
document.registerElement('emby-textarea', {
|
||||
prototype: EmbyTextAreaPrototype,
|
||||
extends: "textarea"
|
||||
})
|
||||
extends: 'textarea'
|
||||
});
|
||||
});
|
||||
@@ -2,13 +2,8 @@
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
@@ -19,17 +14,12 @@
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: reverse;
|
||||
-webkit-flex-direction: row-reverse;
|
||||
flex-direction: row-reverse;
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.toggleContainer {
|
||||
margin-bottom: 1.8em
|
||||
margin-bottom: 1.8em;
|
||||
}
|
||||
|
||||
.mdl-switch__input {
|
||||
@@ -42,29 +32,28 @@
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
border: none
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mdl-switch__trackContainer {
|
||||
position: relative;
|
||||
width: 2.9em
|
||||
width: 2.9em;
|
||||
}
|
||||
|
||||
.mdl-switch__track {
|
||||
background: rgba(0, 0, 0, .2);
|
||||
background: rgba(0,0,0, 0.2);
|
||||
height: 1em;
|
||||
-webkit-border-radius: 1em;
|
||||
border-radius: 1em;
|
||||
cursor: pointer
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mdl-switch__input:checked+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__track {
|
||||
background: rgba(0,164,220, .5)
|
||||
.mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track {
|
||||
background: rgba(82,181,75, 0.5);
|
||||
}
|
||||
|
||||
.mdl-switch__input[disabled]+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__track {
|
||||
background: rgba(0, 0, 0, .12);
|
||||
cursor: auto
|
||||
.mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track {
|
||||
background: rgba(0,0,0, 0.12);
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.mdl-switch__thumb {
|
||||
@@ -74,41 +63,26 @@
|
||||
top: -.25em;
|
||||
height: 1.44em;
|
||||
width: 1.44em;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
|
||||
-webkit-transition-duration: .28s;
|
||||
-o-transition-duration: .28s;
|
||||
transition-duration: .28s;
|
||||
-webkit-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
-o-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
-webkit-transition-property: left;
|
||||
-o-transition-property: left;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||
transition-duration: 0.28s;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-property: left;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mdl-switch__input:checked+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__thumb {
|
||||
background: #00a4dc;
|
||||
.mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb {
|
||||
background: rgb(82,181,75);
|
||||
left: 1.466em;
|
||||
-webkit-box-shadow: 0 3px .28em 0 rgba(0, 0, 0, .14), 0 3px 3px -2px rgba(0, 0, 0, .2), 0 1px .56em 0 rgba(0, 0, 0, .12);
|
||||
box-shadow: 0 3px .28em 0 rgba(0, 0, 0, .14), 0 3px 3px -2px rgba(0, 0, 0, .2), 0 1px .56em 0 rgba(0, 0, 0, .12)
|
||||
box-shadow: 0 3px 0.28em 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.2), 0 1px .56em 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.mdl-switch__input[disabled]+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__thumb {
|
||||
background: #bdbdbd;
|
||||
cursor: auto
|
||||
.mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb {
|
||||
background: rgb(189,189,189);
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.mdl-switch__focus-helper {
|
||||
@@ -118,38 +92,31 @@
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
display: inline-block;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: .6em;
|
||||
height: .6em;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
background-color: transparent
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.mdl-switch__input:focus+.mdl-switch__label+.mdl-switch__trackContainer .mdl-switch__focus-helper {
|
||||
-webkit-box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05);
|
||||
box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05)
|
||||
.mdl-switch__input:focus + .mdl-switch__label + .mdl-switch__trackContainer .mdl-switch__focus-helper {
|
||||
box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05);
|
||||
}
|
||||
|
||||
.mdl-switch__input:checked:focus+.mdl-switch__label+.mdl-switch__trackContainer .mdl-switch__focus-helper {
|
||||
-webkit-box-shadow: 0 0 0 1.39em rgba(0,164,220, .26);
|
||||
box-shadow: 0 0 0 1.39em rgba(0,164,220, .26);
|
||||
background-color: rgba(0,164,220, .26)
|
||||
.mdl-switch__input:checked:focus + .mdl-switch__label + .mdl-switch__trackContainer .mdl-switch__focus-helper {
|
||||
box-shadow: 0 0 0 1.39em rgba(82,181,75, 0.26);
|
||||
background-color: rgba(82,181,75, 0.26);
|
||||
}
|
||||
|
||||
.mdl-switch__label {
|
||||
cursor: pointer;
|
||||
margin: 0 0 0 .7em;
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
margin: 0;
|
||||
display: inline-flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center
|
||||
align-items: center;
|
||||
margin-left: .7em;
|
||||
}
|
||||
|
||||
.mdl-switch__input[disabled] .mdl-switch__label {
|
||||
color: #bdbdbd;
|
||||
cursor: auto
|
||||
}
|
||||
color: rgb(189,189,189);
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,50 @@
|
||||
define(["css!./emby-toggle", "registerElement"], function() {
|
||||
"use strict";
|
||||
define(['css!./emby-toggle', 'registerElement'], function () {
|
||||
'use strict';
|
||||
|
||||
var EmbyTogglePrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (13 === e.keyCode) return e.preventDefault(), this.checked = !this.checked, this.dispatchEvent(new CustomEvent("change", {
|
||||
bubbles: !0
|
||||
})), !1
|
||||
}
|
||||
var EmbyTogglePrototype = Object.create(HTMLInputElement.prototype);
|
||||
EmbyTogglePrototype.attachedCallback = function() {
|
||||
if ("true" !== this.getAttribute("data-embytoggle")) {
|
||||
this.setAttribute("data-embytoggle", "true"), this.classList.add("mdl-switch__input");
|
||||
var labelElement = this.parentNode;
|
||||
labelElement.classList.add("mdl-switch"), labelElement.classList.add("mdl-js-switch");
|
||||
var labelTextElement = labelElement.querySelector("span");
|
||||
labelElement.insertAdjacentHTML("beforeend", '<div class="mdl-switch__trackContainer"><div class="mdl-switch__track"></div><div class="mdl-switch__thumb"><span class="mdl-switch__focus-helper"></span></div></div>'), labelTextElement.classList.add("toggleButtonLabel"), labelTextElement.classList.add("mdl-switch__label"), this.addEventListener("keydown", onKeyDown)
|
||||
|
||||
// Don't submit form on enter
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
|
||||
this.checked = !this.checked;
|
||||
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
|
||||
return false;
|
||||
}
|
||||
}, document.registerElement("emby-toggle", {
|
||||
}
|
||||
|
||||
EmbyTogglePrototype.attachedCallback = function () {
|
||||
|
||||
if (this.getAttribute('data-embytoggle') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setAttribute('data-embytoggle', 'true');
|
||||
|
||||
this.classList.add('mdl-switch__input');
|
||||
|
||||
var labelElement = this.parentNode;
|
||||
labelElement.classList.add('mdl-switch');
|
||||
labelElement.classList.add('mdl-js-switch');
|
||||
|
||||
var labelTextElement = labelElement.querySelector('span');
|
||||
|
||||
labelElement.insertAdjacentHTML('beforeend', '<div class="mdl-switch__trackContainer"><div class="mdl-switch__track"></div><div class="mdl-switch__thumb"><span class="mdl-switch__focus-helper"></span></div></div>');
|
||||
|
||||
labelTextElement.classList.add('toggleButtonLabel');
|
||||
labelTextElement.classList.add('mdl-switch__label');
|
||||
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
};
|
||||
|
||||
document.registerElement('emby-toggle', {
|
||||
prototype: EmbyTogglePrototype,
|
||||
extends: "input"
|
||||
})
|
||||
extends: 'input'
|
||||
});
|
||||
});
|
||||
@@ -1,54 +1,132 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function getFetchPromise(request) {
|
||||
|
||||
var headers = request.headers || {};
|
||||
"json" === request.dataType && (headers.accept = "application/json");
|
||||
|
||||
if (request.dataType === 'json') {
|
||||
headers.accept = 'application/json';
|
||||
}
|
||||
|
||||
var fetchRequest = {
|
||||
headers: headers,
|
||||
method: request.type,
|
||||
credentials: "same-origin"
|
||||
},
|
||||
contentType = request.contentType;
|
||||
request.data && ("string" == typeof request.data ? fetchRequest.body = request.data : (fetchRequest.body = paramsToString(request.data), contentType = contentType || "application/x-www-form-urlencoded; charset=UTF-8")), contentType && (headers["Content-Type"] = contentType);
|
||||
headers: headers,
|
||||
method: request.type,
|
||||
credentials: 'same-origin'
|
||||
};
|
||||
|
||||
var contentType = request.contentType;
|
||||
|
||||
if (request.data) {
|
||||
|
||||
if (typeof request.data === 'string') {
|
||||
fetchRequest.body = request.data;
|
||||
} else {
|
||||
fetchRequest.body = paramsToString(request.data);
|
||||
|
||||
contentType = contentType || 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||
}
|
||||
}
|
||||
|
||||
if (contentType) {
|
||||
|
||||
headers['Content-Type'] = contentType;
|
||||
}
|
||||
|
||||
var url = request.url;
|
||||
|
||||
if (request.query) {
|
||||
var paramString = paramsToString(request.query);
|
||||
paramString && (url += "?" + paramString)
|
||||
if (paramString) {
|
||||
url += '?' + paramString;
|
||||
}
|
||||
}
|
||||
return request.timeout ? fetchWithTimeout(url, fetchRequest, request.timeout) : fetch(url, fetchRequest)
|
||||
|
||||
if (!request.timeout) {
|
||||
return fetch(url, fetchRequest);
|
||||
}
|
||||
|
||||
return fetchWithTimeout(url, fetchRequest, request.timeout);
|
||||
}
|
||||
|
||||
function fetchWithTimeout(url, options, timeoutMs) {
|
||||
return console.log("fetchWithTimeout: timeoutMs: " + timeoutMs + ", url: " + url), new Promise(function(resolve, reject) {
|
||||
|
||||
console.log('fetchWithTimeout: timeoutMs: ' + timeoutMs + ', url: ' + url);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var timeout = setTimeout(reject, timeoutMs);
|
||||
options = options || {}, options.credentials = "same-origin", fetch(url, options).then(function(response) {
|
||||
clearTimeout(timeout), console.log("fetchWithTimeout: succeeded connecting to url: " + url), resolve(response)
|
||||
}, function(error) {
|
||||
clearTimeout(timeout), console.log("fetchWithTimeout: timed out connecting to url: " + url), reject()
|
||||
})
|
||||
})
|
||||
|
||||
options = options || {};
|
||||
options.credentials = 'same-origin';
|
||||
|
||||
fetch(url, options).then(function (response) {
|
||||
clearTimeout(timeout);
|
||||
|
||||
console.log('fetchWithTimeout: succeeded connecting to url: ' + url);
|
||||
|
||||
resolve(response);
|
||||
}, function (error) {
|
||||
|
||||
clearTimeout(timeout);
|
||||
|
||||
console.log('fetchWithTimeout: timed out connecting to url: ' + url);
|
||||
|
||||
reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function paramsToString(params) {
|
||||
|
||||
var values = [];
|
||||
|
||||
for (var key in params) {
|
||||
|
||||
var value = params[key];
|
||||
null !== value && void 0 !== value && "" !== value && values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value))
|
||||
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
|
||||
}
|
||||
}
|
||||
return values.join("&")
|
||||
return values.join('&');
|
||||
}
|
||||
|
||||
function ajax(request) {
|
||||
if (!request) throw new Error("Request cannot be null");
|
||||
return request.headers = request.headers || {}, console.log("requesting url: " + request.url), getFetchPromise(request).then(function(response) {
|
||||
return console.log("response status: " + response.status + ", url: " + request.url), response.status < 400 ? "json" === request.dataType || "application/json" === request.headers.accept ? response.json() : "text" === request.dataType || 0 === (response.headers.get("Content-Type") || "").toLowerCase().indexOf("text/") ? response.text() : response : Promise.reject(response)
|
||||
}, function(err) {
|
||||
throw console.log("request failed to url: " + request.url), err
|
||||
})
|
||||
|
||||
if (!request) {
|
||||
throw new Error("Request cannot be null");
|
||||
}
|
||||
|
||||
request.headers = request.headers || {};
|
||||
|
||||
console.log('requesting url: ' + request.url);
|
||||
|
||||
return getFetchPromise(request).then(function (response) {
|
||||
|
||||
console.log('response status: ' + response.status + ', url: ' + request.url);
|
||||
|
||||
if (response.status < 400) {
|
||||
|
||||
if (request.dataType === 'json' || request.headers.accept === 'application/json') {
|
||||
return response.json();
|
||||
} else if (request.dataType === 'text' || (response.headers.get('Content-Type') || '').toLowerCase().indexOf('text/') === 0) {
|
||||
return response.text();
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
} else {
|
||||
return Promise.reject(response);
|
||||
}
|
||||
|
||||
}, function (err) {
|
||||
|
||||
console.log('request failed to url: ' + request.url);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
return {
|
||||
getFetchPromise: getFetchPromise,
|
||||
ajax: ajax
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,10 +1,12 @@
|
||||
define(["multi-download"], function(multiDownload) {
|
||||
"use strict";
|
||||
define(['multi-download'], function (multiDownload) {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
download: function(items) {
|
||||
multiDownload(items.map(function(item) {
|
||||
return item.url
|
||||
}))
|
||||
download: function (items) {
|
||||
|
||||
multiDownload(items.map(function (item) {
|
||||
return item.url;
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,11 +1,12 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
fileExists: function(path) {
|
||||
return Promise.reject()
|
||||
fileExists: function (path) {
|
||||
return Promise.reject();
|
||||
},
|
||||
directoryExists: function(path) {
|
||||
return Promise.reject()
|
||||
directoryExists: function (path) {
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,125 +1,348 @@
|
||||
define(["require", "dom", "focusManager", "dialogHelper", "loading", "apphost", "inputManager", "layoutManager", "connectionManager", "appRouter", "globalize", "userSettings", "emby-checkbox", "emby-input", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button", "emby-linkbutton", "flexStyles"], function(require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) {
|
||||
"use strict";
|
||||
define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', 'inputManager', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) {
|
||||
'use strict';
|
||||
|
||||
function onSubmit(e) {
|
||||
return e.preventDefault(), !1
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
|
||||
var elem = context.querySelector(selector);
|
||||
items.length ? elem.classList.remove("hide") : elem.classList.add("hide");
|
||||
var html = "";
|
||||
html += items.map(function(filter) {
|
||||
var itemHtml = "",
|
||||
checkedHtml = isCheckedFn(filter) ? " checked" : "";
|
||||
return itemHtml += "<label>", itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>', itemHtml += "<span>" + filter.Name + "</span>", itemHtml += "</label>"
|
||||
}).join(""), elem.querySelector(".filterOptions").innerHTML = html
|
||||
|
||||
if (items.length) {
|
||||
|
||||
elem.classList.remove('hide');
|
||||
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
html += items.map(function (filter) {
|
||||
|
||||
var itemHtml = '';
|
||||
|
||||
var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
|
||||
itemHtml += '<label>';
|
||||
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>';
|
||||
itemHtml += '<span>' + filter.Name + '</span>';
|
||||
itemHtml += '</label>';
|
||||
|
||||
return itemHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
elem.querySelector('.filterOptions').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderDynamicFilters(context, result, options) {
|
||||
renderOptions(context, ".genreFilters", "chkGenreFilter", result.Genres, function(i) {
|
||||
var delimeter = -1 === (options.settings.GenreIds || "").indexOf("|") ? "," : "|";
|
||||
return -1 !== (delimeter + (options.settings.GenreIds || "") + delimeter).indexOf(delimeter + i.Id + delimeter)
|
||||
})
|
||||
|
||||
// If there's a huge number of these they will be really show to render
|
||||
//if (result.Tags) {
|
||||
// result.Tags.length = Math.min(result.Tags.length, 50);
|
||||
//}
|
||||
|
||||
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
|
||||
|
||||
// Switching from | to ,
|
||||
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
|
||||
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
|
||||
});
|
||||
|
||||
//renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
|
||||
// var delimeter = '|';
|
||||
// return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
|
||||
//renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
|
||||
// var delimeter = '|';
|
||||
// return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
|
||||
//renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
|
||||
|
||||
// var delimeter = ',';
|
||||
// return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
}
|
||||
|
||||
function loadDynamicFilters(context, options) {
|
||||
var apiClient = connectionManager.getApiClient(options.serverId),
|
||||
filterMenuOptions = Object.assign(options.filterMenuOptions, {
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ParentId: options.parentId,
|
||||
IncludeItemTypes: options.itemTypes.join(",")
|
||||
});
|
||||
apiClient.getFilters(filterMenuOptions).then(function(result) {
|
||||
renderDynamicFilters(context, result, options)
|
||||
}, function() {})
|
||||
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
|
||||
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
|
||||
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ParentId: options.parentId,
|
||||
IncludeItemTypes: options.itemTypes.join(',')
|
||||
});
|
||||
|
||||
apiClient.getFilters(filterMenuOptions).then(function (result) {
|
||||
|
||||
renderDynamicFilters(context, result, options);
|
||||
}, function () {
|
||||
|
||||
// older server
|
||||
});
|
||||
}
|
||||
|
||||
function initEditor(context, settings) {
|
||||
context.querySelector("form").addEventListener("submit", onSubmit);
|
||||
var i, length, elems = context.querySelectorAll(".simpleFilter");
|
||||
for (i = 0, length = elems.length; i < length; i++) "INPUT" === elems[i].tagName ? elems[i].checked = settings[elems[i].getAttribute("data-settingname")] || !1 : elems[i].querySelector("input").checked = settings[elems[i].getAttribute("data-settingname")] || !1;
|
||||
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(",") : [];
|
||||
for (elems = context.querySelectorAll(".chkVideoTypeFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked = -1 !== videoTypes.indexOf(elems[i].getAttribute("data-filter"));
|
||||
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(",") : [];
|
||||
for (elems = context.querySelectorAll(".chkSeriesStatus"), i = 0, length = elems.length; i < length; i++) elems[i].checked = -1 !== seriesStatuses.indexOf(elems[i].getAttribute("data-filter"));
|
||||
context.querySelector(".basicFilterSection .viewSetting:not(.hide)") ? context.querySelector(".basicFilterSection").classList.remove("hide") : context.querySelector(".basicFilterSection").classList.add("hide"), context.querySelector(".featureSection .viewSetting:not(.hide)") ? context.querySelector(".featureSection").classList.remove("hide") : context.querySelector(".featureSection").classList.add("hide")
|
||||
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i, length;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
} else {
|
||||
elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
}
|
||||
}
|
||||
|
||||
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.basicFilterSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.basicFilterSection').classList.add('hide');
|
||||
}
|
||||
|
||||
if (context.querySelector('.featureSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.featureSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.featureSection').classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
var i, length, elems = context.querySelectorAll(".simpleFilter");
|
||||
for (i = 0, length = elems.length; i < length; i++) "INPUT" === elems[i].tagName ? setBasicFilter(context, settingsKey + "-filter-" + elems[i].getAttribute("data-settingname"), elems[i]) : setBasicFilter(context, settingsKey + "-filter-" + elems[i].getAttribute("data-settingname"), elems[i].querySelector("input"));
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i, length;
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
|
||||
} else {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input'));
|
||||
}
|
||||
}
|
||||
|
||||
// Video type
|
||||
var videoTypes = [];
|
||||
for (elems = context.querySelectorAll(".chkVideoTypeFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked && videoTypes.push(elems[i].getAttribute("data-filter"));
|
||||
userSettings.setFilter(settingsKey + "-filter-VideoTypes", videoTypes.join(","));
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
videoTypes.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
|
||||
|
||||
// Series status
|
||||
var seriesStatuses = [];
|
||||
for (elems = context.querySelectorAll(".chkSeriesStatus"), i = 0, length = elems.length; i < length; i++) elems[i].checked && seriesStatuses.push(elems[i].getAttribute("data-filter"));
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
seriesStatuses.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
// Genres
|
||||
var genres = [];
|
||||
for (elems = context.querySelectorAll(".chkGenreFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked && genres.push(elems[i].getAttribute("data-filter"));
|
||||
userSettings.setFilter(settingsKey + "-filter-GenreIds", genres.join(","))
|
||||
elems = context.querySelectorAll('.chkGenreFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
genres.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
}
|
||||
|
||||
function setBasicFilter(context, key, elem) {
|
||||
|
||||
var value = elem.checked;
|
||||
value = value || null, userSettings.setFilter(key, value)
|
||||
value = value ? value : null;
|
||||
userSettings.setFilter(key, value);
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(["scrollHelper"], function(scrollHelper) {
|
||||
var fn = on ? "on" : "off";
|
||||
scrollHelper.centerFocus[fn](elem, horiz)
|
||||
})
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function moveCheckboxFocus(elem, offset) {
|
||||
for (var parent = dom.parentWithClass(elem, "checkboxList-verticalwrap"), elems = focusManager.getFocusableElements(parent), index = -1, i = 0, length = elems.length; i < length; i++)
|
||||
|
||||
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
|
||||
var elems = focusManager.getFocusableElements(parent);
|
||||
|
||||
var index = -1;
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i] === elem) {
|
||||
index = i;
|
||||
break
|
||||
} index += offset, index = Math.min(elems.length - 1, index), index = Math.max(0, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index += offset;
|
||||
|
||||
index = Math.min(elems.length - 1, index);
|
||||
index = Math.max(0, index);
|
||||
|
||||
var newElem = elems[index];
|
||||
newElem && focusManager.focus(newElem)
|
||||
if (newElem) {
|
||||
focusManager.focus(newElem);
|
||||
}
|
||||
}
|
||||
|
||||
function onInputCommand(e) {
|
||||
switch (e.detail.command) {
|
||||
case "left":
|
||||
moveCheckboxFocus(e.target, -1), e.preventDefault();
|
||||
|
||||
case 'left':
|
||||
moveCheckboxFocus(e.target, -1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'right':
|
||||
moveCheckboxFocus(e.target, 1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case "right":
|
||||
moveCheckboxFocus(e.target, 1), e.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
function FilterMenu() {}
|
||||
function FilterMenu() {
|
||||
|
||||
}
|
||||
|
||||
function bindCheckboxInput(context, on) {
|
||||
for (var elems = context.querySelectorAll(".checkboxList-verticalwrap"), i = 0, length = elems.length; i < length; i++) on ? inputManager.on(elems[i], onInputCommand) : inputManager.off(elems[i], onInputCommand)
|
||||
|
||||
var elems = context.querySelectorAll('.checkboxList-verticalwrap');
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
if (on) {
|
||||
inputManager.on(elems[i], onInputCommand);
|
||||
} else {
|
||||
inputManager.off(elems[i], onInputCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
return FilterMenu.prototype.show = function(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
require(["text!./filtermenu.template.html"], function(template) {
|
||||
|
||||
FilterMenu.prototype.show = function (options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['text!./filtermenu.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: !0,
|
||||
scrollY: !1
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small";
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add("formDialog");
|
||||
var html = "";
|
||||
html += '<div class="formDialogHeader">', html += '<button is="paper-icon-button-light" class="btnCancel hide-mouse-idle-tv" tabindex="-1"><i class="md-icon"></i></button>', html += '<h3 class="formDialogHeaderTitle">${Filters}</h3>', html += "</div>", html += template, dlg.innerHTML = globalize.translateDocument(html, "sharedcomponents");
|
||||
for (var settingElements = dlg.querySelectorAll(".viewSetting"), i = 0, length = settingElements.length; i < length; i++) - 1 === options.visibleSettings.indexOf(settingElements[i].getAttribute("data-settingname")) ? settingElements[i].classList.add("hide") : settingElements[i].classList.remove("hide");
|
||||
initEditor(dlg, options.settings), loadDynamicFilters(dlg, options), bindCheckboxInput(dlg, !0), dlg.querySelector(".btnCancel").addEventListener("click", function() {
|
||||
dialogHelper.close(dlg)
|
||||
}), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel hide-mouse-idle-tv" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">${Filters}</h3>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += template;
|
||||
|
||||
dlg.innerHTML = globalize.translateDocument(html, 'sharedcomponents');
|
||||
|
||||
var settingElements = dlg.querySelectorAll('.viewSetting');
|
||||
for (var i = 0, length = settingElements.length; i < length; i++) {
|
||||
if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) {
|
||||
settingElements[i].classList.add('hide');
|
||||
} else {
|
||||
settingElements[i].classList.remove('hide');
|
||||
}
|
||||
}
|
||||
|
||||
initEditor(dlg, options.settings);
|
||||
loadDynamicFilters(dlg, options);
|
||||
|
||||
bindCheckboxInput(dlg, true);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
||||
}
|
||||
|
||||
var submitted;
|
||||
dlg.querySelector("form").addEventListener("change", function() {
|
||||
submitted = !0
|
||||
}, !0), dialogHelper.open(dlg).then(function() {
|
||||
if (bindCheckboxInput(dlg, !1), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted) return saveValues(dlg, options.settings, options.settingsKey), void resolve();
|
||||
reject()
|
||||
})
|
||||
})
|
||||
})
|
||||
}, FilterMenu
|
||||
|
||||
dlg.querySelector('form').addEventListener('change', function () {
|
||||
|
||||
submitted = true;
|
||||
//if (options.onChange) {
|
||||
// saveValues(dlg, options.settings, options.settingsKey);
|
||||
// options.onChange();
|
||||
//}
|
||||
|
||||
}, true);
|
||||
|
||||
dialogHelper.open(dlg).then(function () {
|
||||
|
||||
bindCheckboxInput(dlg, false);
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
|
||||
//if (!options.onChange) {
|
||||
saveValues(dlg, options.settings, options.settingsKey);
|
||||
resolve();
|
||||
//}
|
||||
return;
|
||||
}
|
||||
|
||||
reject();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return FilterMenu;
|
||||
});
|
||||
@@ -1,70 +1,47 @@
|
||||
.flex {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.inline-flex {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.flex-direction-column {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex-direction-row {
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.flex-grow {
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.flex-shrink-zero {
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.align-items-center {
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.align-items-flex-start {
|
||||
-webkit-box-align: start;
|
||||
-webkit-align-items: flex-start;
|
||||
align-items: flex-start
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.justify-content-center {
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.justify-content-flex-end {
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.flex-wrap-wrap {
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.align-self-flex-end {
|
||||
-webkit-align-self: flex-end;
|
||||
align-self: flex-end
|
||||
align-self: flex-end;
|
||||
}
|
||||
6284
src/bower_components/emby-webcomponents/flvjs/flv.min.js
vendored
6284
src/bower_components/emby-webcomponents/flvjs/flv.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,249 +1,544 @@
|
||||
define(["dom"], function(dom) {
|
||||
"use strict";
|
||||
define(['dom'], function (dom) {
|
||||
'use strict';
|
||||
|
||||
var scopes = [];
|
||||
function pushScope(elem) {
|
||||
scopes.push(elem)
|
||||
scopes.push(elem);
|
||||
}
|
||||
|
||||
function popScope(elem) {
|
||||
scopes.length && (scopes.length -= 1)
|
||||
}
|
||||
|
||||
function autoFocus(view, defaultToFirst, findAutoFocusElement) {
|
||||
var element;
|
||||
return !1 !== findAutoFocusElement && (element = view.querySelector("*[autofocus]")) ? (focus(element), element) : !1 !== defaultToFirst && (element = getFocusableElements(view, 1, "noautofocus")[0]) ? (focus(element), element) : null
|
||||
}
|
||||
|
||||
function focus(element) {
|
||||
try {
|
||||
element.focus({
|
||||
preventScroll: !0
|
||||
})
|
||||
} catch (err) {
|
||||
console.log("Error in focusManager.autoFocus: " + err)
|
||||
if (scopes.length) {
|
||||
scopes.length -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
function autoFocus(view, defaultToFirst, findAutoFocusElement) {
|
||||
|
||||
var element;
|
||||
if (findAutoFocusElement !== false) {
|
||||
element = view.querySelector('*[autofocus]');
|
||||
if (element) {
|
||||
focus(element);
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultToFirst !== false) {
|
||||
element = getFocusableElements(view, 1, 'noautofocus')[0];
|
||||
|
||||
if (element) {
|
||||
focus(element);
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function focus(element) {
|
||||
|
||||
try {
|
||||
element.focus({
|
||||
preventScroll: true
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('Error in focusManager.autoFocus: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'];
|
||||
var focusableContainerTagNames = ['BODY', 'DIALOG'];
|
||||
var focusableQuery = focusableTagNames.map(function (t) {
|
||||
|
||||
if (t === 'INPUT') {
|
||||
t += ':not([type="range"]):not([type="file"])';
|
||||
}
|
||||
return t + ':not([tabindex="-1"]):not(:disabled)';
|
||||
|
||||
}).join(',') + ',.focusable';
|
||||
|
||||
function isFocusable(elem) {
|
||||
return -1 !== focusableTagNames.indexOf(elem.tagName) || !(!elem.classList || !elem.classList.contains("focusable"))
|
||||
|
||||
if (focusableTagNames.indexOf(elem.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (elem.classList && elem.classList.contains('focusable')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function normalizeFocusable(elem, originalElement) {
|
||||
if (elem) {
|
||||
var tagName = elem.tagName;
|
||||
tagName && "HTML" !== tagName && "BODY" !== tagName || (elem = originalElement)
|
||||
if (!tagName || tagName === 'HTML' || tagName === 'BODY') {
|
||||
elem = originalElement;
|
||||
}
|
||||
}
|
||||
return elem
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function focusableParent(elem) {
|
||||
for (var originalElement = elem; !isFocusable(elem);) {
|
||||
|
||||
var originalElement = elem;
|
||||
|
||||
while (!isFocusable(elem)) {
|
||||
var parent = elem.parentNode;
|
||||
if (!parent) return normalizeFocusable(elem, originalElement);
|
||||
elem = parent
|
||||
|
||||
if (!parent) {
|
||||
return normalizeFocusable(elem, originalElement);
|
||||
}
|
||||
|
||||
elem = parent;
|
||||
}
|
||||
return normalizeFocusable(elem, originalElement)
|
||||
|
||||
return normalizeFocusable(elem, originalElement);
|
||||
}
|
||||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusableInternal(elem) {
|
||||
return null !== elem.offsetParent
|
||||
|
||||
// http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
|
||||
if (elem.offsetParent === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusable(elem) {
|
||||
if (elem.disabled) return !1;
|
||||
if ("-1" === elem.getAttribute("tabindex")) return !1;
|
||||
if ("INPUT" === elem.tagName) {
|
||||
var type = elem.type;
|
||||
if ("range" === type) return !1;
|
||||
if ("file" === type) return !1
|
||||
|
||||
if (elem.disabled) {
|
||||
return false;
|
||||
}
|
||||
return isCurrentlyFocusableInternal(elem)
|
||||
|
||||
if (elem.getAttribute('tabindex') === "-1") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elem.tagName === 'INPUT') {
|
||||
var type = elem.type;
|
||||
if (type === 'range') {
|
||||
return false;
|
||||
}
|
||||
if (type === 'file') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return isCurrentlyFocusableInternal(elem);
|
||||
}
|
||||
|
||||
function getDefaultScope() {
|
||||
return scopes[0] || document.body
|
||||
return scopes[0] || document.body;
|
||||
}
|
||||
|
||||
function getFocusableElements(parent, limit, excludeClass) {
|
||||
for (var elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery), focusableElements = [], i = 0, length = elems.length; i < length; i++) {
|
||||
var elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery);
|
||||
var focusableElements = [];
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
if ((!excludeClass || !elem.classList.contains(excludeClass)) && (isCurrentlyFocusableInternal(elem) && (focusableElements.push(elem), limit && focusableElements.length >= limit))) break
|
||||
|
||||
if (excludeClass && elem.classList.contains(excludeClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
focusableElements.push(elem);
|
||||
|
||||
if (limit && focusableElements.length >= limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return focusableElements
|
||||
|
||||
return focusableElements;
|
||||
}
|
||||
|
||||
function isFocusContainer(elem, direction) {
|
||||
if (-1 !== focusableContainerTagNames.indexOf(elem.tagName)) return !0;
|
||||
var classList = elem.classList;
|
||||
if (classList.contains("focuscontainer")) return !0;
|
||||
if (0 === direction) {
|
||||
if (classList.contains("focuscontainer-x")) return !0;
|
||||
if (classList.contains("focuscontainer-left")) return !0
|
||||
} else if (1 === direction) {
|
||||
if (classList.contains("focuscontainer-x")) return !0;
|
||||
if (classList.contains("focuscontainer-right")) return !0
|
||||
} else if (2 === direction) {
|
||||
if (classList.contains("focuscontainer-y")) return !0
|
||||
} else if (3 === direction) {
|
||||
if (classList.contains("focuscontainer-y")) return !0;
|
||||
if (classList.contains("focuscontainer-down")) return !0
|
||||
|
||||
if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
return !1
|
||||
|
||||
var classList = elem.classList;
|
||||
|
||||
if (classList.contains('focuscontainer')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (direction === 0) {
|
||||
if (classList.contains('focuscontainer-x')) {
|
||||
return true;
|
||||
}
|
||||
if (classList.contains('focuscontainer-left')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (direction === 1) {
|
||||
if (classList.contains('focuscontainer-x')) {
|
||||
return true;
|
||||
}
|
||||
if (classList.contains('focuscontainer-right')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (direction === 2) {
|
||||
if (classList.contains('focuscontainer-y')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (direction === 3) {
|
||||
if (classList.contains('focuscontainer-y')) {
|
||||
return true;
|
||||
}
|
||||
if (classList.contains('focuscontainer-down')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getFocusContainer(elem, direction) {
|
||||
for (; !isFocusContainer(elem, direction);)
|
||||
if (!(elem = elem.parentNode)) return getDefaultScope();
|
||||
return elem
|
||||
while (!isFocusContainer(elem, direction)) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return getDefaultScope();
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function getOffset(elem) {
|
||||
|
||||
var box;
|
||||
if (box = elem.getBoundingClientRect ? elem.getBoundingClientRect() : {
|
||||
|
||||
// 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();
|
||||
} else {
|
||||
box = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: 0,
|
||||
height: 0
|
||||
}, null === box.right) {
|
||||
box = {
|
||||
};
|
||||
}
|
||||
|
||||
if (box.right === null) {
|
||||
|
||||
// Create a new object because some browsers will throw an error when trying to set data onto the Rect object
|
||||
var newBox = {
|
||||
top: box.top,
|
||||
left: box.left,
|
||||
width: box.width,
|
||||
height: box.height
|
||||
}, box.right = box.left + box.width, box.bottom = box.top + box.height
|
||||
};
|
||||
|
||||
box = newBox;
|
||||
|
||||
box.right = box.left + box.width;
|
||||
box.bottom = box.top + box.height;
|
||||
}
|
||||
return box
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
function nav(activeElement, direction, container, focusableElements) {
|
||||
if (activeElement = activeElement || document.activeElement, activeElement && (activeElement = focusableParent(activeElement)), container = container || (activeElement ? getFocusContainer(activeElement, direction) : getDefaultScope()), !activeElement) return void autoFocus(container, !0, !1);
|
||||
for (var nearestElement, focusableContainer = dom.parentWithClass(activeElement, "focusable"), rect = getOffset(activeElement), point1x = parseFloat(rect.left) || 0, point1y = parseFloat(rect.top) || 0, point2x = parseFloat(point1x + rect.width - 1) || point1x, point2y = parseFloat(point1y + rect.height - 1) || point1y, sourceMidX = (Math.min, Math.max, rect.left + rect.width / 2), sourceMidY = rect.top + rect.height / 2, focusable = focusableElements || container.querySelectorAll(focusableQuery), minDistance = 1 / 0, i = 0, length = focusable.length; i < length; i++) {
|
||||
|
||||
activeElement = activeElement || document.activeElement;
|
||||
|
||||
if (activeElement) {
|
||||
activeElement = focusableParent(activeElement);
|
||||
}
|
||||
|
||||
container = container || (activeElement ? getFocusContainer(activeElement, direction) : getDefaultScope());
|
||||
|
||||
if (!activeElement) {
|
||||
autoFocus(container, true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
var focusableContainer = dom.parentWithClass(activeElement, 'focusable');
|
||||
|
||||
var rect = getOffset(activeElement);
|
||||
|
||||
// Get elements and work out x/y points
|
||||
var cache = [],
|
||||
point1x = parseFloat(rect.left) || 0,
|
||||
point1y = parseFloat(rect.top) || 0,
|
||||
point2x = parseFloat(point1x + rect.width - 1) || point1x,
|
||||
point2y = parseFloat(point1y + rect.height - 1) || point1y,
|
||||
// Shortcuts to help with compression
|
||||
min = Math.min,
|
||||
max = Math.max;
|
||||
|
||||
var sourceMidX = rect.left + (rect.width / 2);
|
||||
var sourceMidY = rect.top + (rect.height / 2);
|
||||
|
||||
var focusable = focusableElements || container.querySelectorAll(focusableQuery);
|
||||
|
||||
var maxDistance = Infinity;
|
||||
var minDistance = maxDistance;
|
||||
var nearestElement;
|
||||
|
||||
for (var i = 0, length = focusable.length; i < length; i++) {
|
||||
var curr = focusable[i];
|
||||
if (curr !== activeElement && curr !== focusableContainer) {
|
||||
var elementRect = getOffset(curr);
|
||||
if (elementRect.width || elementRect.height) {
|
||||
switch (direction) {
|
||||
case 0:
|
||||
if (elementRect.left >= rect.left) continue;
|
||||
if (elementRect.right === rect.right) continue;
|
||||
break;
|
||||
case 1:
|
||||
if (elementRect.right <= rect.right) continue;
|
||||
if (elementRect.left === rect.left) continue;
|
||||
break;
|
||||
case 2:
|
||||
if (elementRect.top >= rect.top) continue;
|
||||
if (elementRect.bottom >= rect.bottom) continue;
|
||||
break;
|
||||
case 3:
|
||||
if (elementRect.bottom <= rect.bottom) continue;
|
||||
if (elementRect.top <= rect.top) continue
|
||||
|
||||
if (curr === activeElement) {
|
||||
continue;
|
||||
}
|
||||
// Don't refocus into the same container
|
||||
if (curr === focusableContainer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//if (!isCurrentlyFocusableInternal(curr)) {
|
||||
// continue;
|
||||
//}
|
||||
|
||||
var elementRect = getOffset(curr);
|
||||
|
||||
// not currently visible
|
||||
if (!elementRect.width && !elementRect.height) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
if (elementRect.left >= rect.left) {
|
||||
continue;
|
||||
}
|
||||
var distX, distY, x = elementRect.left,
|
||||
y = elementRect.top,
|
||||
x2 = x + elementRect.width - 1,
|
||||
y2 = y + elementRect.height - 1,
|
||||
intersectX = intersects(point1x, point2x, x, x2),
|
||||
intersectY = intersects(point1y, point2y, y, y2),
|
||||
midX = elementRect.left + elementRect.width / 2,
|
||||
midY = elementRect.top + elementRect.height / 2;
|
||||
switch (direction) {
|
||||
case 0:
|
||||
distX = Math.abs(point1x - Math.min(point1x, x2)), distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
|
||||
break;
|
||||
case 1:
|
||||
distX = Math.abs(point2x - Math.max(point2x, x)), distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
|
||||
break;
|
||||
case 2:
|
||||
distY = Math.abs(point1y - Math.min(point1y, y2)), distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
|
||||
break;
|
||||
case 3:
|
||||
distY = Math.abs(point2y - Math.max(point2y, y)), distX = intersectX ? 0 : Math.abs(sourceMidX - midX)
|
||||
if (elementRect.right === rect.right) {
|
||||
continue;
|
||||
}
|
||||
var dist = Math.sqrt(distX * distX + distY * distY);
|
||||
dist < minDistance && (nearestElement = curr, minDistance = dist)
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
var x = elementRect.left,
|
||||
y = elementRect.top,
|
||||
x2 = x + elementRect.width - 1,
|
||||
y2 = y + elementRect.height - 1;
|
||||
|
||||
var intersectX = intersects(point1x, point2x, x, x2);
|
||||
var intersectY = intersects(point1y, point2y, y, y2);
|
||||
|
||||
var midX = elementRect.left + (elementRect.width / 2);
|
||||
var midY = elementRect.top + (elementRect.height / 2);
|
||||
|
||||
var distX;
|
||||
var distY;
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
distX = Math.abs(point1x - Math.min(point1x, x2));
|
||||
distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
|
||||
break;
|
||||
case 1:
|
||||
// right
|
||||
distX = Math.abs(point2x - Math.max(point2x, x));
|
||||
distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
|
||||
break;
|
||||
case 2:
|
||||
// up
|
||||
distY = Math.abs(point1y - Math.min(point1y, y2));
|
||||
distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
|
||||
break;
|
||||
case 3:
|
||||
// down
|
||||
distY = Math.abs(point2y - Math.max(point2y, y));
|
||||
distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
var dist = Math.sqrt(distX * distX + distY * distY);
|
||||
|
||||
if (dist < minDistance) {
|
||||
nearestElement = curr;
|
||||
minDistance = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearestElement) {
|
||||
|
||||
// See if there's a focusable container, and if so, send the focus command to that
|
||||
if (activeElement) {
|
||||
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, "focusable");
|
||||
nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement && focusableContainer !== nearestElementFocusableParent && (nearestElement = nearestElementFocusableParent)
|
||||
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
|
||||
if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) {
|
||||
if (focusableContainer !== nearestElementFocusableParent) {
|
||||
nearestElement = nearestElementFocusableParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
focus(nearestElement)
|
||||
focus(nearestElement);
|
||||
}
|
||||
}
|
||||
|
||||
function intersectsInternal(a1, a2, b1, b2) {
|
||||
return b1 >= a1 && b1 <= a2 || b2 >= a1 && b2 <= a2
|
||||
|
||||
return (b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2);
|
||||
}
|
||||
|
||||
function intersects(a1, a2, b1, b2) {
|
||||
return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2)
|
||||
|
||||
return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2);
|
||||
}
|
||||
|
||||
function sendText(text) {
|
||||
document.activeElement.value = text
|
||||
var elem = document.activeElement;
|
||||
|
||||
elem.value = text;
|
||||
}
|
||||
|
||||
function focusFirst(container, focusableSelector) {
|
||||
for (var elems = container.querySelectorAll(focusableSelector), i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elems = container.querySelectorAll(focusableSelector);
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
focus(elem);
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function focusLast(container, focusableSelector) {
|
||||
for (var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse(), i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse();
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
focus(elem);
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function moveFocus(sourceElement, container, focusableSelector, offset) {
|
||||
var i, length, elem, elems = container.querySelectorAll(focusableSelector),
|
||||
list = [];
|
||||
for (i = 0, length = elems.length; i < length; i++) elem = elems[i], isCurrentlyFocusableInternal(elem) && list.push(elem);
|
||||
|
||||
var elems = container.querySelectorAll(focusableSelector);
|
||||
var list = [];
|
||||
var i, length, elem;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
list.push(elem);
|
||||
}
|
||||
}
|
||||
|
||||
var currentIndex = -1;
|
||||
for (i = 0, length = list.length; i < length; i++)
|
||||
if (elem = list[i], sourceElement === elem || elem.contains(sourceElement)) {
|
||||
|
||||
for (i = 0, length = list.length; i < length; i++) {
|
||||
|
||||
elem = list[i];
|
||||
|
||||
if (sourceElement === elem || elem.contains(sourceElement)) {
|
||||
currentIndex = i;
|
||||
break
|
||||
} if (-1 !== currentIndex) {
|
||||
var newIndex = currentIndex + offset;
|
||||
newIndex = Math.max(0, newIndex), newIndex = Math.min(newIndex, list.length - 1);
|
||||
var newElem = list[newIndex];
|
||||
newElem && focus(newElem)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentIndex === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var newIndex = currentIndex + offset;
|
||||
newIndex = Math.max(0, newIndex);
|
||||
newIndex = Math.min(newIndex, list.length - 1);
|
||||
|
||||
var newElem = list[newIndex];
|
||||
if (newElem) {
|
||||
focus(newElem);
|
||||
}
|
||||
}
|
||||
var scopes = [],
|
||||
focusableTagNames = ["INPUT", "TEXTAREA", "SELECT", "BUTTON", "A"],
|
||||
focusableContainerTagNames = ["BODY", "DIALOG"],
|
||||
focusableQuery = focusableTagNames.map(function(t) {
|
||||
return "INPUT" === t && (t += ':not([type="range"]):not([type="file"])'), t + ':not([tabindex="-1"]):not(:disabled)'
|
||||
}).join(",") + ",.focusable";
|
||||
|
||||
return {
|
||||
autoFocus: autoFocus,
|
||||
focus: focus,
|
||||
focusableParent: focusableParent,
|
||||
getFocusableElements: getFocusableElements,
|
||||
moveLeft: function(sourceElement, options) {
|
||||
nav(sourceElement, 0, options ? options.container : null, options ? options.focusableElements : null)
|
||||
moveLeft: function (sourceElement, options) {
|
||||
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 0, container, focusableElements);
|
||||
|
||||
},
|
||||
moveRight: function(sourceElement, options) {
|
||||
nav(sourceElement, 1, options ? options.container : null, options ? options.focusableElements : null)
|
||||
moveRight: function (sourceElement, options) {
|
||||
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 1, container, focusableElements);
|
||||
|
||||
},
|
||||
moveUp: function(sourceElement, options) {
|
||||
nav(sourceElement, 2, options ? options.container : null, options ? options.focusableElements : null)
|
||||
moveUp: function (sourceElement, options) {
|
||||
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 2, container, focusableElements);
|
||||
|
||||
},
|
||||
moveDown: function(sourceElement, options) {
|
||||
nav(sourceElement, 3, options ? options.container : null, options ? options.focusableElements : null)
|
||||
moveDown: function (sourceElement, options) {
|
||||
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 3, container, focusableElements);
|
||||
|
||||
},
|
||||
sendText: sendText,
|
||||
isCurrentlyFocusable: isCurrentlyFocusable,
|
||||
@@ -252,5 +547,5 @@ define(["dom"], function(dom) {
|
||||
focusFirst: focusFirst,
|
||||
focusLast: focusLast,
|
||||
moveFocus: moveFocus
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,39 +1,37 @@
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-weight: 500
|
||||
html {
|
||||
font-family: -apple-system, "Helvetica", system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: -apple-system, Helvetica, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", 'Open Sans', sans-serif;
|
||||
font-size: 93%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-moz-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%
|
||||
text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", 'Open Sans', sans-serif
|
||||
h1, h2, h3 {
|
||||
/* For better bolding, since Helvetica does not support 500 weight, and 600 is too thick */
|
||||
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.8em
|
||||
font-weight: 500;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em
|
||||
font-weight: 500;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.17em
|
||||
font-weight: 500;
|
||||
font-size: 1.17em;
|
||||
}
|
||||
|
||||
.layout-tv {
|
||||
font-size: 2.5vh
|
||||
font-size: 2.5vh;
|
||||
}
|
||||
|
||||
.layout-mobile {
|
||||
font-size: 90%
|
||||
}
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-weight: 500
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.8em
|
||||
font-weight: 500;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.layout-desktop h1 {
|
||||
font-size: 2em
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em
|
||||
font-weight: 500;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.17em
|
||||
font-weight: 500;
|
||||
font-size: 1.17em;
|
||||
}
|
||||
|
||||
@media all and (min-height:720px) {
|
||||
@media all and (min-height: 720px) {
|
||||
html {
|
||||
font-size: 20px
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-height:1000px) {
|
||||
/* This is supposed to be 1080p, but had to reduce the min height to account for possible browser chrome */
|
||||
@media all and (min-height: 1000px) {
|
||||
|
||||
html {
|
||||
font-size: 27px
|
||||
font-size: 27px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Material Icons'), local('MaterialIcons-Regular'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff) format('woff')
|
||||
src: local('Material Icons'), local('MaterialIcons-Regular'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff) format('woff');
|
||||
}
|
||||
|
||||
.md-icon {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: 400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
@@ -15,12 +15,11 @@
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-webkit-font-feature-settings: 'liga';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-feature-settings: "liga"1;
|
||||
-moz-font-feature-settings: "liga"1;
|
||||
font-feature-settings: "liga"1;
|
||||
font-feature-settings: "liga" 1;
|
||||
line-height: 1;
|
||||
overflow: hidden;
|
||||
vertical-align: middle
|
||||
}
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@@ -1,145 +1,115 @@
|
||||
.formDialog,
|
||||
.formDialogHeader {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex
|
||||
}
|
||||
|
||||
.formDialog,
|
||||
.formDialogFooter-vertical {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal
|
||||
}
|
||||
|
||||
.formDialog {
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
position: relative
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.formDialogHeader {
|
||||
padding: 1em .5em;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.formDialogHeaderTitle {
|
||||
margin-left: .25em;
|
||||
/* In case of h1, h2, h3 */
|
||||
margin-top: 0;
|
||||
margin-bottom: 0
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.formDialogContent:not(.no-grow) {
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.dialogContentInner {
|
||||
padding: .5em 1em 20em
|
||||
padding: .5em 1em 20em 1em;
|
||||
}
|
||||
|
||||
.dialogContentInner-mini {
|
||||
padding-bottom: 10em
|
||||
padding-bottom: 10em;
|
||||
}
|
||||
|
||||
.dialog-content-centered {
|
||||
margin: 0 auto;
|
||||
max-width: 53em
|
||||
max-width: 53em;
|
||||
}
|
||||
|
||||
.dialogContentTitle {
|
||||
margin-top: 1em
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.formDialogFooter {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
padding: 1.25em 1em;
|
||||
/* Without this emby-checkbox is able to appear on top */
|
||||
z-index: 1;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.formDialogFooter-flex {
|
||||
position: static;
|
||||
width: 100%
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.formDialogFooter-vertical {
|
||||
padding-bottom: 1.5em;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
width: 80% !important;
|
||||
padding-top: .5em
|
||||
padding-top: .5em;
|
||||
}
|
||||
|
||||
.formDialogFooterItem {
|
||||
margin: .5em !important;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
-webkit-flex-basis: 0;
|
||||
flex-basis: 0
|
||||
flex-basis: 0;
|
||||
}
|
||||
|
||||
.formDialogFooterItem-vertical {
|
||||
max-width: none !important;
|
||||
width: 100%;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
margin: 1em !important
|
||||
margin: 1em !important;
|
||||
}
|
||||
|
||||
.formDialogFooterItem-nomarginbottom {
|
||||
margin-bottom: 0 !important
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.formDialogFooterItem-autosize {
|
||||
-webkit-flex-basis: initial;
|
||||
flex-basis: initial;
|
||||
-webkit-box-flex: initial;
|
||||
-webkit-flex-grow: initial;
|
||||
flex-grow: initial;
|
||||
padding-left: 2em;
|
||||
padding-right: 2em
|
||||
padding-right: 2em;
|
||||
}
|
||||
|
||||
@media all and (min-width:50em) {
|
||||
@media all and (min-width: 50em) {
|
||||
|
||||
.formDialogFooterItem {
|
||||
max-width: 80%
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.dialogContentInner {
|
||||
padding-left: 1.5em;
|
||||
padding-right: 1.5em
|
||||
padding-right: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width:80em) {
|
||||
@media all and (min-width: 80em) {
|
||||
|
||||
.formDialogFooterItem {
|
||||
max-width: 70%
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.dialogContentInner {
|
||||
padding-left: 2em;
|
||||
padding-right: 2em
|
||||
padding-right: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
define(["dom", "fullscreenManager"], function(dom, fullscreenManager) {
|
||||
"use strict";
|
||||
define(['dom', 'fullscreenManager'], function (dom, fullscreenManager) {
|
||||
'use strict';
|
||||
|
||||
function isTargetValid(target) {
|
||||
return !dom.parentWithTag(target, ["BUTTON", "INPUT", "TEXTAREA"])
|
||||
|
||||
if (dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
dom.addEventListener(window, "dblclick", function(e) {
|
||||
isTargetValid(e.target) && (fullscreenManager.isFullScreen() ? fullscreenManager.exitFullscreen() : fullscreenManager.requestFullscreen())
|
||||
|
||||
dom.addEventListener(window, 'dblclick', function (e) {
|
||||
|
||||
if (isTargetValid(e.target)) {
|
||||
if (fullscreenManager.isFullScreen()) {
|
||||
fullscreenManager.exitFullscreen();
|
||||
} else {
|
||||
fullscreenManager.requestFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
}, {
|
||||
passive: !0
|
||||
})
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
@@ -1,24 +1,74 @@
|
||||
define(["events", "dom"], function(events, dom) {
|
||||
"use strict";
|
||||
define(['events', 'dom'], function (events, dom) {
|
||||
'use strict';
|
||||
|
||||
function fullscreenManager() {}
|
||||
function fullscreenManager() {
|
||||
|
||||
}
|
||||
|
||||
fullscreenManager.prototype.requestFullscreen = function (element) {
|
||||
|
||||
element = element || document.documentElement;
|
||||
|
||||
if (element.requestFullscreen) {
|
||||
element.requestFullscreen();
|
||||
return;
|
||||
} else if (element.mozRequestFullScreen) {
|
||||
element.mozRequestFullScreen();
|
||||
return;
|
||||
} else if (element.webkitRequestFullscreen) {
|
||||
element.webkitRequestFullscreen();
|
||||
return;
|
||||
} else if (element.msRequestFullscreen) {
|
||||
element.msRequestFullscreen();
|
||||
return;
|
||||
}
|
||||
|
||||
// Hack - This is only available for video elements in ios safari
|
||||
if (element.tagName !== 'VIDEO') {
|
||||
element = document.querySelector('video') || element;
|
||||
}
|
||||
if (element.webkitEnterFullscreen) {
|
||||
element.webkitEnterFullscreen();
|
||||
}
|
||||
};
|
||||
|
||||
fullscreenManager.prototype.exitFullscreen = function () {
|
||||
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (document.webkitCancelFullscreen) {
|
||||
document.webkitCancelFullscreen();
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen();
|
||||
}
|
||||
};
|
||||
|
||||
fullscreenManager.prototype.isFullScreen = function () {
|
||||
|
||||
return document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement ? true : false;
|
||||
};
|
||||
|
||||
var manager = new fullscreenManager();
|
||||
|
||||
function onFullScreenChange() {
|
||||
events.trigger(manager, "fullscreenchange")
|
||||
events.trigger(manager, 'fullscreenchange');
|
||||
}
|
||||
fullscreenManager.prototype.requestFullscreen = function(element) {
|
||||
return element = element || document.documentElement, element.requestFullscreen ? void element.requestFullscreen() : element.mozRequestFullScreen ? void element.mozRequestFullScreen() : element.webkitRequestFullscreen ? void element.webkitRequestFullscreen() : element.msRequestFullscreen ? void element.msRequestFullscreen() : ("VIDEO" !== element.tagName && (element = document.querySelector("video") || element), void(element.webkitEnterFullscreen && element.webkitEnterFullscreen()))
|
||||
}, fullscreenManager.prototype.exitFullscreen = function() {
|
||||
document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen ? document.webkitExitFullscreen() : document.webkitCancelFullscreen ? document.webkitCancelFullscreen() : document.msExitFullscreen && document.msExitFullscreen()
|
||||
}, fullscreenManager.prototype.isFullScreen = function() {
|
||||
return !!(document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement)
|
||||
};
|
||||
var manager = new fullscreenManager;
|
||||
return dom.addEventListener(document, "fullscreenchange", onFullScreenChange, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(document, "webkitfullscreenchange", onFullScreenChange, {
|
||||
passive: !0
|
||||
}), dom.addEventListener(document, "mozfullscreenchange", onFullScreenChange, {
|
||||
passive: !0
|
||||
}), manager
|
||||
|
||||
dom.addEventListener(document, 'fullscreenchange', onFullScreenChange, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(document, 'webkitfullscreenchange', onFullScreenChange, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(document, 'mozfullscreenchange', onFullScreenChange, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
return manager;
|
||||
});
|
||||
312
src/bower_components/emby-webcomponents/globalize.js
vendored
312
src/bower_components/emby-webcomponents/globalize.js
vendored
@@ -1,127 +1,287 @@
|
||||
define(["connectionManager", "userSettings", "events"], function(connectionManager, userSettings, events) {
|
||||
"use strict";
|
||||
define(['connectionManager', 'userSettings', 'events'], function (connectionManager, userSettings, events) {
|
||||
'use strict';
|
||||
|
||||
var allTranslations = {};
|
||||
var currentCulture;
|
||||
var currentDateTimeCulture;
|
||||
|
||||
function getCurrentLocale() {
|
||||
return currentCulture
|
||||
|
||||
return currentCulture;
|
||||
}
|
||||
|
||||
function getCurrentDateTimeLocale() {
|
||||
return currentDateTimeCulture
|
||||
return currentDateTimeCulture;
|
||||
}
|
||||
|
||||
function getDefaultLanguage() {
|
||||
var culture = document.documentElement.getAttribute("data-culture");
|
||||
return culture || (navigator.language ? navigator.language : navigator.userLanguage ? navigator.userLanguage : navigator.languages && navigator.languages.length ? navigator.languages[0] : "en-us")
|
||||
|
||||
var culture = document.documentElement.getAttribute('data-culture');
|
||||
|
||||
if (culture) {
|
||||
return culture;
|
||||
}
|
||||
|
||||
if (navigator.language) {
|
||||
return navigator.language;
|
||||
}
|
||||
if (navigator.userLanguage) {
|
||||
return navigator.userLanguage;
|
||||
}
|
||||
if (navigator.languages && navigator.languages.length) {
|
||||
return navigator.languages[0];
|
||||
}
|
||||
|
||||
return 'en-us';
|
||||
}
|
||||
|
||||
function updateCurrentCulture() {
|
||||
|
||||
var culture;
|
||||
try {
|
||||
culture = userSettings.language()
|
||||
} catch (err) {}
|
||||
culture = culture || getDefaultLanguage(), currentCulture = normalizeLocaleName(culture);
|
||||
culture = userSettings.language();
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
culture = culture || getDefaultLanguage();
|
||||
|
||||
currentCulture = normalizeLocaleName(culture);
|
||||
|
||||
var dateTimeCulture;
|
||||
try {
|
||||
dateTimeCulture = userSettings.dateTimeLocale()
|
||||
} catch (err) {}
|
||||
currentDateTimeCulture = dateTimeCulture ? normalizeLocaleName(dateTimeCulture) : currentCulture, ensureTranslations(currentCulture)
|
||||
dateTimeCulture = userSettings.dateTimeLocale();
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
|
||||
if (dateTimeCulture) {
|
||||
currentDateTimeCulture = normalizeLocaleName(dateTimeCulture);
|
||||
}
|
||||
else {
|
||||
currentDateTimeCulture = currentCulture;
|
||||
}
|
||||
|
||||
ensureTranslations(currentCulture);
|
||||
}
|
||||
|
||||
function ensureTranslations(culture) {
|
||||
for (var i in allTranslations) ensureTranslation(allTranslations[i], culture)
|
||||
}
|
||||
|
||||
function ensureTranslation(translationInfo, culture) {
|
||||
return translationInfo.dictionaries[culture] ? Promise.resolve() : loadTranslation(translationInfo.translations, culture).then(function(dictionary) {
|
||||
translationInfo.dictionaries[culture] = dictionary
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeLocaleName(culture) {
|
||||
culture = culture.replace("_", "-");
|
||||
var parts = culture.split("-");
|
||||
2 === parts.length && parts[0].toLowerCase() === parts[1].toLowerCase() && (culture = parts[0].toLowerCase());
|
||||
var lower = culture.toLowerCase();
|
||||
return "ca-es" === lower ? "ca" : "sv-se" === lower ? "sv" : lower
|
||||
}
|
||||
|
||||
function getDictionary(module) {
|
||||
module || (module = defaultModule());
|
||||
var translations = allTranslations[module];
|
||||
return translations ? translations.dictionaries[getCurrentLocale()] : {}
|
||||
}
|
||||
|
||||
function register(options) {
|
||||
allTranslations[options.name] = {
|
||||
translations: options.strings || options.translations,
|
||||
dictionaries: {}
|
||||
for (var i in allTranslations) {
|
||||
ensureTranslation(allTranslations[i], culture);
|
||||
}
|
||||
}
|
||||
|
||||
function loadStrings(options) {
|
||||
var locale = getCurrentLocale();
|
||||
return "string" == typeof options ? ensureTranslation(allTranslations[options], locale) : (register(options), ensureTranslation(allTranslations[options.name], locale))
|
||||
function ensureTranslation(translationInfo, culture) {
|
||||
|
||||
if (translationInfo.dictionaries[culture]) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return loadTranslation(translationInfo.translations, culture).then(function (dictionary) {
|
||||
|
||||
translationInfo.dictionaries[culture] = dictionary;
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeLocaleName(culture) {
|
||||
|
||||
culture = culture.replace('_', '-');
|
||||
|
||||
// If it's de-DE, convert to just de
|
||||
var parts = culture.split('-');
|
||||
if (parts.length === 2) {
|
||||
if (parts[0].toLowerCase() === parts[1].toLowerCase()) {
|
||||
culture = parts[0].toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
var lower = culture.toLowerCase();
|
||||
|
||||
if (lower === 'ca-es') {
|
||||
return 'ca';
|
||||
}
|
||||
|
||||
// normalize Swedish
|
||||
if (lower === 'sv-se') {
|
||||
return 'sv';
|
||||
}
|
||||
|
||||
return lower;
|
||||
}
|
||||
|
||||
function getDictionary(module) {
|
||||
|
||||
if (!module) {
|
||||
module = defaultModule();
|
||||
}
|
||||
|
||||
var translations = allTranslations[module];
|
||||
|
||||
if (!translations) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return translations.dictionaries[getCurrentLocale()];
|
||||
}
|
||||
|
||||
function register(options) {
|
||||
|
||||
allTranslations[options.name] = {
|
||||
translations: options.strings || options.translations,
|
||||
dictionaries: {}
|
||||
};
|
||||
}
|
||||
|
||||
function loadStrings(options) {
|
||||
|
||||
var locale = getCurrentLocale();
|
||||
|
||||
if (typeof options === 'string') {
|
||||
return ensureTranslation(allTranslations[options], locale);
|
||||
} else {
|
||||
register(options);
|
||||
return ensureTranslation(allTranslations[options.name], locale);
|
||||
}
|
||||
}
|
||||
|
||||
var cacheParam = new Date().getTime();
|
||||
function loadTranslation(translations, lang) {
|
||||
|
||||
lang = normalizeLocaleName(lang);
|
||||
var filtered = translations.filter(function(t) {
|
||||
return normalizeLocaleName(t.lang) === lang
|
||||
|
||||
var filtered = translations.filter(function (t) {
|
||||
return normalizeLocaleName(t.lang) === lang;
|
||||
});
|
||||
return filtered.length || (filtered = translations.filter(function(t) {
|
||||
return "en-us" === normalizeLocaleName(t.lang)
|
||||
})), new Promise(function(resolve, reject) {
|
||||
if (!filtered.length) return void resolve();
|
||||
|
||||
if (!filtered.length) {
|
||||
filtered = translations.filter(function (t) {
|
||||
return normalizeLocaleName(t.lang) === 'en-us';
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
if (!filtered.length) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var url = filtered[0].path;
|
||||
url += -1 === url.indexOf("?") ? "?" : "&", url += "v=" + cacheParam;
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open("GET", url, !0), xhr.onload = function(e) {
|
||||
resolve(this.status < 400 ? JSON.parse(this.response) : {})
|
||||
}, xhr.onerror = function() {
|
||||
resolve({})
|
||||
}, xhr.send()
|
||||
})
|
||||
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 'v=' + cacheParam;
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (this.status < 400) {
|
||||
resolve(JSON.parse(this.response));
|
||||
} else {
|
||||
resolve({});
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function () {
|
||||
resolve({});
|
||||
};
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function translateKey(key) {
|
||||
var module, parts = key.split("#");
|
||||
return parts.length > 1 && (module = parts[0], key = parts[1]), translateKeyFromModule(key, module)
|
||||
|
||||
var parts = key.split('#');
|
||||
var module;
|
||||
|
||||
if (parts.length > 1) {
|
||||
module = parts[0];
|
||||
key = parts[1];
|
||||
}
|
||||
|
||||
return translateKeyFromModule(key, module);
|
||||
}
|
||||
|
||||
function translateKeyFromModule(key, module) {
|
||||
|
||||
var dictionary = getDictionary(module);
|
||||
return dictionary ? dictionary[key] || key : key
|
||||
|
||||
if (!dictionary) {
|
||||
return key;
|
||||
}
|
||||
|
||||
return dictionary[key] || key;
|
||||
}
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.split(find).join(replace)
|
||||
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
|
||||
function translate(key) {
|
||||
for (var val = translateKey(key), i = 1; i < arguments.length; i++) val = replaceAll(val, "{" + (i - 1) + "}", arguments[i]);
|
||||
return val
|
||||
|
||||
var val = translateKey(key);
|
||||
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
|
||||
val = replaceAll(val, '{' + (i - 1) + '}', arguments[i]);
|
||||
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
function translateHtml(html, module) {
|
||||
if (module || (module = defaultModule()), !module) throw new Error("module cannot be null or empty");
|
||||
var startIndex = html.indexOf("${");
|
||||
if (-1 === startIndex) return html;
|
||||
|
||||
if (!module) {
|
||||
module = defaultModule();
|
||||
}
|
||||
|
||||
if (!module) {
|
||||
throw new Error('module cannot be null or empty');
|
||||
}
|
||||
|
||||
var startIndex = html.indexOf('${');
|
||||
|
||||
if (startIndex === -1) {
|
||||
return html;
|
||||
}
|
||||
|
||||
startIndex += 2;
|
||||
var endIndex = html.indexOf("}", startIndex);
|
||||
if (-1 === endIndex) return html;
|
||||
var key = html.substring(startIndex, endIndex),
|
||||
val = translateKeyFromModule(key, module);
|
||||
return html = html.replace("${" + key + "}", val), translateHtml(html, module)
|
||||
var endIndex = html.indexOf('}', startIndex);
|
||||
|
||||
if (endIndex === -1) {
|
||||
return html;
|
||||
}
|
||||
|
||||
var key = html.substring(startIndex, endIndex);
|
||||
var val = translateKeyFromModule(key, module);
|
||||
|
||||
html = html.replace('${' + key + '}', val);
|
||||
return translateHtml(html, module);
|
||||
}
|
||||
|
||||
var _defaultModule;
|
||||
function defaultModule(val) {
|
||||
return val && (_defaultModule = val), _defaultModule
|
||||
|
||||
if (val) {
|
||||
|
||||
_defaultModule = val;
|
||||
}
|
||||
|
||||
return _defaultModule;
|
||||
}
|
||||
var currentCulture, currentDateTimeCulture, _defaultModule, allTranslations = {},
|
||||
cacheParam = (new Date).getTime();
|
||||
return updateCurrentCulture(), events.on(connectionManager, "localusersignedin", updateCurrentCulture), events.on(userSettings, "change", function(e, name) {
|
||||
"language" !== name && "datetimelocale" !== name || updateCurrentCulture()
|
||||
}), {
|
||||
|
||||
updateCurrentCulture();
|
||||
|
||||
events.on(connectionManager, 'localusersignedin', updateCurrentCulture);
|
||||
events.on(userSettings, 'change', function (e, name) {
|
||||
if (name === 'language' || name === 'datetimelocale') {
|
||||
updateCurrentCulture();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
getString: translate,
|
||||
translate: translate,
|
||||
translateDocument: translateHtml,
|
||||
@@ -131,5 +291,5 @@ define(["connectionManager", "userSettings", "events"], function(connectionManag
|
||||
getCurrentLocale: getCurrentLocale,
|
||||
getCurrentDateTimeLocale: getCurrentDateTimeLocale,
|
||||
register: register
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,71 +1,172 @@
|
||||
define(["dialogHelper", "globalize", "userSettings", "layoutManager", "connectionManager", "require", "loading", "scrollHelper", "emby-checkbox", "emby-radio", "css!./../formdialog", "material-icons"], function(dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
|
||||
"use strict";
|
||||
define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
|
||||
'use strict';
|
||||
|
||||
function saveCategories(context, options) {
|
||||
for (var categories = [], chkCategorys = context.querySelectorAll(".chkCategory"), i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
var type = chkCategorys[i].getAttribute("data-type");
|
||||
chkCategorys[i].checked && categories.push(type)
|
||||
|
||||
var categories = [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
if (chkCategorys[i].checked) {
|
||||
categories.push(type);
|
||||
}
|
||||
}
|
||||
categories.length >= 4 && categories.push("series"), categories.push("all"), options.categories = categories
|
||||
|
||||
if (categories.length >= 4) {
|
||||
categories.push('series');
|
||||
}
|
||||
|
||||
// differentiate between none and all
|
||||
categories.push('all');
|
||||
options.categories = categories;
|
||||
}
|
||||
|
||||
function loadCategories(context, options) {
|
||||
for (var selectedCategories = options.categories || [], chkCategorys = context.querySelectorAll(".chkCategory"), i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
var type = chkCategorys[i].getAttribute("data-type");
|
||||
chkCategorys[i].checked = !selectedCategories.length || -1 !== selectedCategories.indexOf(type)
|
||||
|
||||
var selectedCategories = options.categories || [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
function save(context) {
|
||||
var i, length, chkIndicators = context.querySelectorAll(".chkIndicator");
|
||||
|
||||
var i, length;
|
||||
|
||||
var chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
for (i = 0, length = chkIndicators.length; i < length; i++) {
|
||||
var type = chkIndicators[i].getAttribute("data-type");
|
||||
userSettings.set("guide-indicator-" + type, chkIndicators[i].checked)
|
||||
|
||||
var type = chkIndicators[i].getAttribute('data-type');
|
||||
userSettings.set('guide-indicator-' + type, chkIndicators[i].checked);
|
||||
}
|
||||
userSettings.set("guide-colorcodedbackgrounds", context.querySelector(".chkColorCodedBackgrounds").checked), userSettings.set("livetv-favoritechannelsattop", context.querySelector(".chkFavoriteChannelsAtTop").checked);
|
||||
var sortBys = context.querySelectorAll(".chkSortOrder");
|
||||
for (i = 0, length = sortBys.length; i < length; i++)
|
||||
|
||||
userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked);
|
||||
userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked);
|
||||
|
||||
var sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
if (sortBys[i].checked) {
|
||||
userSettings.set("livetv-channelorder", sortBys[i].value);
|
||||
break
|
||||
userSettings.set('livetv-channelorder', sortBys[i].value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function load(context) {
|
||||
var i, length, chkIndicators = context.querySelectorAll(".chkIndicator");
|
||||
|
||||
var i, length;
|
||||
|
||||
var chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
for (i = 0, length = chkIndicators.length; i < length; i++) {
|
||||
var type = chkIndicators[i].getAttribute("data-type");
|
||||
"true" === chkIndicators[i].getAttribute("data-default") ? chkIndicators[i].checked = "false" !== userSettings.get("guide-indicator-" + type) : chkIndicators[i].checked = "true" === userSettings.get("guide-indicator-" + type)
|
||||
|
||||
var type = chkIndicators[i].getAttribute('data-type');
|
||||
|
||||
if (chkIndicators[i].getAttribute('data-default') === 'true') {
|
||||
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) !== 'false';
|
||||
} else {
|
||||
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) === 'true';
|
||||
}
|
||||
}
|
||||
|
||||
context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true';
|
||||
context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false';
|
||||
|
||||
var sortByValue = userSettings.get('livetv-channelorder') || 'Number';
|
||||
|
||||
var sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
sortBys[i].checked = sortBys[i].value === sortByValue;
|
||||
}
|
||||
}
|
||||
|
||||
function onSortByChange() {
|
||||
var newValue = this.value;
|
||||
if (this.checked) {
|
||||
var changed = options.query.SortBy !== newValue;
|
||||
|
||||
options.query.SortBy = newValue.replace('_', ',');
|
||||
options.query.StartIndex = 0;
|
||||
|
||||
if (options.callback && changed) {
|
||||
options.callback();
|
||||
}
|
||||
}
|
||||
context.querySelector(".chkColorCodedBackgrounds").checked = "true" === userSettings.get("guide-colorcodedbackgrounds"), context.querySelector(".chkFavoriteChannelsAtTop").checked = "false" !== userSettings.get("livetv-favoritechannelsattop");
|
||||
var sortByValue = userSettings.get("livetv-channelorder") || "Number",
|
||||
sortBys = context.querySelectorAll(".chkSortOrder");
|
||||
for (i = 0, length = sortBys.length; i < length; i++) sortBys[i].checked = sortBys[i].value === sortByValue
|
||||
}
|
||||
|
||||
function showEditor(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var settingsChanged = !1;
|
||||
require(["text!./guide-settings.template.html"], function(template) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var settingsChanged = false;
|
||||
|
||||
require(['text!./guide-settings.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: !0,
|
||||
scrollY: !1
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small";
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add("formDialog");
|
||||
var html = "";
|
||||
html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, dlg.addEventListener("change", function() {
|
||||
settingsChanged = !0
|
||||
}), dlg.addEventListener("close", function() {
|
||||
layoutManager.tv && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), save(dlg), saveCategories(dlg, options), settingsChanged ? resolve() : reject()
|
||||
}), dlg.querySelector(".btnCancel").addEventListener("click", function() {
|
||||
dialogHelper.close(dlg)
|
||||
}), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), load(dlg), loadCategories(dlg, options), dialogHelper.open(dlg)
|
||||
})
|
||||
})
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
|
||||
html += globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
dlg.addEventListener('change', function () {
|
||||
|
||||
settingsChanged = true;
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
save(dlg);
|
||||
saveCategories(dlg, options);
|
||||
|
||||
if (settingsChanged) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
load(dlg);
|
||||
loadCategories(dlg, options);
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: showEditor
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,194 +1,141 @@
|
||||
.tvGuideHeader,
|
||||
.tvguide {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex
|
||||
}
|
||||
|
||||
.channelPrograms,
|
||||
.programContainer,
|
||||
.timeslotHeadersInner,
|
||||
.tvProgram {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.channelPrograms,
|
||||
.channelsContainer,
|
||||
.tvGuideHeader,
|
||||
.tvguide {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal
|
||||
}
|
||||
|
||||
.guideChannelName,
|
||||
.guideChannelNumber,
|
||||
.guideProgramName,
|
||||
.guideProgramNameText {
|
||||
-o-text-overflow: ellipsis
|
||||
}
|
||||
|
||||
.tvguide {
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-align: initial;
|
||||
-webkit-align-items: initial;
|
||||
align-items: initial
|
||||
align-items: initial;
|
||||
}
|
||||
|
||||
.tvGuideHeader {
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
contain: layout style paint
|
||||
contain: layout style paint;
|
||||
}
|
||||
|
||||
.layout-desktop .tvGuideHeader {
|
||||
margin-bottom: .5em
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
.guideHeaderDateSelection {
|
||||
font-size: 86%;
|
||||
padding: .4em 0
|
||||
padding: .4em 0;
|
||||
}
|
||||
|
||||
.guide-headerTimeslots {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tvProgramSectionHeader {
|
||||
margin: 0
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tvProgram {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
white-space: nowrap
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.guideProgramIndicator {
|
||||
text-transform: uppercase;
|
||||
-webkit-border-radius: .25em;
|
||||
border-radius: .25em;
|
||||
margin-right: .5em;
|
||||
font-size: 82%;
|
||||
padding: .2em .25em;
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
margin-left: 1em
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.guide-channelTimeslotHeader {
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.timeslotHeaders {
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
font-size: 120%
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.programContainer {
|
||||
white-space: nowrap;
|
||||
-webkit-box-align: start;
|
||||
-webkit-align-items: flex-start;
|
||||
position: relative;
|
||||
align-items: flex-start;
|
||||
contain: strict
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.channelPrograms {
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
contain: strict;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.timeslotHeadersInner {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.guideSpacer {
|
||||
width: .3em;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.channelPrograms,
|
||||
.timeslotHeadersInner {
|
||||
width: 1800vw
|
||||
.channelPrograms, .timeslotHeadersInner {
|
||||
width: 1800vw;
|
||||
}
|
||||
|
||||
@media all and (min-width:37.5em) {
|
||||
@media all and (min-width: 37.5em) {
|
||||
|
||||
.channelPrograms,
|
||||
.timeslotHeadersInner {
|
||||
width: 1400vw
|
||||
.channelPrograms, .timeslotHeadersInner {
|
||||
width: 1400vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width:50em) {
|
||||
@media all and (min-width: 50em) {
|
||||
|
||||
.channelPrograms,
|
||||
.timeslotHeadersInner {
|
||||
width: 1200vw
|
||||
.channelPrograms, .timeslotHeadersInner {
|
||||
width: 1200vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width:80em) {
|
||||
@media all and (min-width: 80em) {
|
||||
|
||||
.channelPrograms,
|
||||
.timeslotHeadersInner {
|
||||
width: 810vw
|
||||
.channelPrograms, .timeslotHeadersInner {
|
||||
width: 810vw;
|
||||
}
|
||||
}
|
||||
|
||||
.timeslotHeader {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
text-indent: .25em;
|
||||
width: 2.0833333333333333333333333333333%
|
||||
width: 2.0833333333333333333333333333333%;
|
||||
}
|
||||
|
||||
.guide-channelHeaderCell,
|
||||
.guide-channelTimeslotHeader,
|
||||
.programCell {
|
||||
color: inherit;
|
||||
.guide-channelHeaderCell, .guide-channelTimeslotHeader {
|
||||
padding: 0 !important;
|
||||
cursor: pointer;
|
||||
outline: none !important;
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
font-family: inherit;
|
||||
text-decoration: none;
|
||||
-webkit-box-align: center;
|
||||
text-align: left;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.guide-channelHeaderCell,
|
||||
.guide-channelTimeslotHeader {
|
||||
padding: 0 !important;
|
||||
outline: 0 !important;
|
||||
width: 100%;
|
||||
font-size: inherit;
|
||||
-o-text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 0 1px 0 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
/* Needed in firefox */
|
||||
text-align: left;
|
||||
contain: strict;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
-webkit-border-radius: .12em;
|
||||
border-radius: .12em
|
||||
border-radius: .12em;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.guide-channelHeaderCell {
|
||||
@@ -198,187 +145,151 @@
|
||||
height: 4.42em;
|
||||
contain: strict;
|
||||
position: relative;
|
||||
background: 0 0
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.guide-channelTimeslotHeader {
|
||||
border: 0 !important;
|
||||
border-right-color: transparent
|
||||
}
|
||||
|
||||
.channelsContainer,
|
||||
.guide-channelTimeslotHeader {
|
||||
width: 24vw
|
||||
/* Important - have to put the fixed width on channelsContainer, not the individual channelHeaderCell
|
||||
This was causing channelsContainer to extend beyond the fixed width on ps4, tizen, lg and opera tv.
|
||||
*/
|
||||
.channelsContainer, .guide-channelTimeslotHeader {
|
||||
width: 24vw;
|
||||
}
|
||||
|
||||
@media all and (min-width:31.25em) {
|
||||
|
||||
.channelsContainer,
|
||||
.guide-channelTimeslotHeader {
|
||||
width: 16vw
|
||||
.channelsContainer, .guide-channelTimeslotHeader {
|
||||
width: 16vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width:37.5em) {
|
||||
|
||||
.channelsContainer,
|
||||
.guide-channelTimeslotHeader {
|
||||
width: 16vw
|
||||
.channelsContainer, .guide-channelTimeslotHeader {
|
||||
width: 16vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width:50em) {
|
||||
|
||||
.channelsContainer,
|
||||
.guide-channelTimeslotHeader {
|
||||
width: 14vw
|
||||
.channelsContainer, .guide-channelTimeslotHeader {
|
||||
width: 14vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width:80em) {
|
||||
|
||||
.channelsContainer,
|
||||
.guide-channelTimeslotHeader {
|
||||
width: 12vw
|
||||
.channelsContainer, .guide-channelTimeslotHeader {
|
||||
width: 12vw;
|
||||
}
|
||||
}
|
||||
|
||||
.btnGuideViewSettings {
|
||||
margin: 0;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btnGuideViewSettingsIcon {
|
||||
font-size: 1.5em !important
|
||||
font-size: 1.5em !important;
|
||||
}
|
||||
|
||||
.selectDateIcon {
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media all and (max-width:50em) {
|
||||
@media all and (max-width: 50em) {
|
||||
|
||||
.guideHdIcon,
|
||||
.liveTvProgram,
|
||||
.newTvProgram,
|
||||
.premiereTvProgram {
|
||||
display: none
|
||||
.newTvProgram, .liveTvProgram, .premiereTvProgram, .guideHdIcon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.channelPrograms,
|
||||
.programCell {
|
||||
border-style: solid;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
contain: strict
|
||||
}
|
||||
|
||||
.channelPrograms {
|
||||
white-space: nowrap;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
height: 4.42em;
|
||||
contain: strict;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
border-width: 1px 0
|
||||
border-style: solid;
|
||||
border-width: 1px 0 1px 0;
|
||||
}
|
||||
|
||||
.channelPrograms+.channelPrograms,
|
||||
.guide-channelHeaderCell+.guide-channelHeaderCell {
|
||||
margin-top: -1px
|
||||
.channelPrograms + .channelPrograms, .guide-channelHeaderCell + .guide-channelHeaderCell {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.channelPrograms-tv, .guide-channelHeaderCell-tv {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.channelPrograms-tv,
|
||||
.guide-channelHeaderCell-tv {
|
||||
height: 3em
|
||||
.guide-channelTimeslotHeader {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
.guide-channelTimeslotHeader,
|
||||
.timeslotHeader {
|
||||
background: 0 0 !important;
|
||||
height: 2.8em
|
||||
.guide-channelTimeslotHeader, .timeslotHeader {
|
||||
background: transparent !important;
|
||||
height: 2.8em;
|
||||
}
|
||||
|
||||
.programGrid {
|
||||
padding-bottom: 4px;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.programCell {
|
||||
background: 0 0;
|
||||
color: inherit;
|
||||
background: transparent;
|
||||
border-style: solid;
|
||||
border-width: 0 0 0 1px;
|
||||
padding: 0 !important;
|
||||
cursor: pointer;
|
||||
outline: none !important;
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
/* Needed for Firefox */
|
||||
text-align: left;
|
||||
contain: strict;
|
||||
flex-grow: 1;
|
||||
margin: 0 !important
|
||||
}
|
||||
|
||||
.channelsContainer,
|
||||
.guideProgramName,
|
||||
.programGrid {
|
||||
contain: layout style paint
|
||||
}
|
||||
|
||||
.guide-programNameCaret,
|
||||
.guideProgramName {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
-webkit-box-align: center
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.guideProgramName {
|
||||
padding: 0 .7em;
|
||||
padding: 0 .7em 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
position: relative;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1
|
||||
flex-grow: 1;
|
||||
contain: layout style paint;
|
||||
/*transition: transform 60ms ease-out;*/
|
||||
}
|
||||
|
||||
.guide-programNameCaret {
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
font-size: 200%
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
.guideProgramNameText {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
font-weight: normal;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.guideProgramSecondaryInfo {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
margin-top: .1em
|
||||
margin-top: .1em;
|
||||
}
|
||||
|
||||
.programIcon {
|
||||
@@ -387,26 +298,22 @@
|
||||
width: 1em;
|
||||
font-size: 1.6em;
|
||||
color: #ddd;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
-webkit-box-flex: 0;
|
||||
-webkit-flex-grow: 0;
|
||||
flex-grow: 0
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.guide-programTextIcon {
|
||||
font-weight: 700;
|
||||
font-weight: bold;
|
||||
font-size: .9em;
|
||||
padding: .16em .3em;
|
||||
-webkit-border-radius: .25em;
|
||||
border-radius: .25em;
|
||||
margin-right: .35em;
|
||||
width: auto;
|
||||
height: auto
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.guide-programTextIcon-tv {
|
||||
font-size: .74em
|
||||
font-size: .74em;
|
||||
}
|
||||
|
||||
.guideChannelNumber {
|
||||
@@ -414,8 +321,8 @@
|
||||
max-width: 30%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
font-weight: 400;
|
||||
margin: 0
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.guideChannelName {
|
||||
@@ -423,7 +330,7 @@
|
||||
margin-right: 1em;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: 70%
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.guideChannelImage {
|
||||
@@ -432,68 +339,62 @@
|
||||
top: 15%;
|
||||
bottom: 15%;
|
||||
width: 40%;
|
||||
-webkit-background-size: contain;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
@media all and (min-width:62.5em) {
|
||||
@media all and (min-width: 62.5em) {
|
||||
|
||||
.guideChannelName {
|
||||
max-width: 40%
|
||||
max-width: 40%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width:62.5em) {
|
||||
@media all and (max-width: 62.5em) {
|
||||
|
||||
.guideChannelNumber {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
.guideChannelImage {
|
||||
width: 70%
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.channelsContainer {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.guide-channelHeaderCell,
|
||||
.programCell {
|
||||
outline: 0 !important
|
||||
.channelsContainer, .programGrid {
|
||||
contain: layout style paint;
|
||||
}
|
||||
|
||||
.seriesTimerIcon,
|
||||
.timerIcon {
|
||||
color: #c33 !important
|
||||
.programCell, .guide-channelHeaderCell {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.timerIcon, .seriesTimerIcon {
|
||||
color: #cc3333 !important;
|
||||
}
|
||||
|
||||
.seriesTimerIcon-inactive {
|
||||
color: inherit !important;
|
||||
opacity: .7
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.guideOptions {
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media all and (max-width:50em),
|
||||
all and (max-height:37.5em) {
|
||||
@media all and (max-width: 50em), all and (max-height: 37.5em) {
|
||||
|
||||
.tvGuideHeader {
|
||||
padding-left: 0
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,31 +402,29 @@ all and (max-height:37.5em) {
|
||||
margin: 1em auto;
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.noRubberBanding {
|
||||
padding-bottom: 7em
|
||||
/* This is needed to combat the rubber banding in iOS */
|
||||
padding-bottom: 7em;
|
||||
}
|
||||
|
||||
.guideDateTabsSlider {
|
||||
text-align: center
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.guide-date-tab-button {
|
||||
padding: .3em .7em !important;
|
||||
margin: 0 .3em !important;
|
||||
font-weight: 400
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.guide-date-tab-button.emby-tab-button-active {
|
||||
border-color: transparent !important
|
||||
}
|
||||
.guide-date-tab-button.emby-tab-button-active {
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
.guide-date-tab-button.emby-button-tv:focus {
|
||||
-webkit-border-radius: .15em !important;
|
||||
border-radius: .15em !important;
|
||||
-webkit-transform: none !important;
|
||||
transform: none !important
|
||||
}
|
||||
.guide-date-tab-button.emby-button-tv:focus {
|
||||
border-radius: .15em !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
1447
src/bower_components/emby-webcomponents/guide/guide.js
vendored
1447
src/bower_components/emby-webcomponents/guide/guide.js
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,19 @@
|
||||
.newTvProgram {
|
||||
background: #38c;
|
||||
color: #fff
|
||||
background: #3388cc;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.liveTvProgram {
|
||||
background: #c33;
|
||||
color: #fff
|
||||
background: #cc3333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.premiereTvProgram {
|
||||
background: #EF6C00;
|
||||
color: #fff
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.repeatTvProgram {
|
||||
background: #009688;
|
||||
color: #fff
|
||||
}
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
.headroom {
|
||||
-webkit-transition: -webkit-transform 140ms linear;
|
||||
-o-transition: transform 140ms linear;
|
||||
transition: transform 140ms linear
|
||||
transition: transform 140ms linear;
|
||||
}
|
||||
|
||||
.headroom--pinned {
|
||||
-webkit-transform: none;
|
||||
transform: none
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.headroom--unpinned:not(.headroomDisabled) {
|
||||
-webkit-transform: translateY(-100%);
|
||||
transform: translateY(-100%)
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
@@ -1,136 +1,349 @@
|
||||
define(["dom", "layoutManager", "browser", "css!./headroom"], function(dom, layoutManager, browser) {
|
||||
"use strict";
|
||||
/*!
|
||||
* headroom.js v0.7.0 - Give your page some headroom. Hide your header until you need it
|
||||
* Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/headroom.js
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, layoutManager, browser) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/* exported features */
|
||||
|
||||
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
|
||||
|
||||
/**
|
||||
* Handles debouncing of events via requestAnimationFrame
|
||||
* @see http://www.html5rocks.com/en/tutorials/speed/animations/
|
||||
* @param {Function} callback The callback to handle whichever event
|
||||
*/
|
||||
function Debouncer(callback) {
|
||||
this.callback = callback, this.ticking = !1
|
||||
this.callback = callback;
|
||||
this.ticking = false;
|
||||
}
|
||||
Debouncer.prototype = {
|
||||
constructor: Debouncer,
|
||||
|
||||
/**
|
||||
* dispatches the event to the supplied callback
|
||||
* @private
|
||||
*/
|
||||
update: function () {
|
||||
if (this.callback) {
|
||||
this.callback();
|
||||
}
|
||||
this.ticking = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach this as the event listeners
|
||||
*/
|
||||
handleEvent: function () {
|
||||
if (!this.ticking) {
|
||||
requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
|
||||
this.ticking = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onHeadroomClearedExternally() {
|
||||
this.state = null
|
||||
this.state = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* UI enhancement for fixed headers.
|
||||
* Hides header when scrolling down
|
||||
* Shows header when scrolling up
|
||||
* @constructor
|
||||
* @param {DOMElement} elem the header element
|
||||
* @param {Object} options options for the widget
|
||||
*/
|
||||
function Headroom(elems, options) {
|
||||
options = Object.assign(Headroom.options, options || {}), this.lastKnownScrollY = 0, this.elems = elems, this.scroller = options.scroller, this.debouncer = onScroll.bind(this), this.offset = options.offset, this.initialised = !1, this.initialClass = options.initialClass, this.unPinnedClass = options.unPinnedClass, this.pinnedClass = options.pinnedClass, this.state = "clear"
|
||||
options = Object.assign(Headroom.options, options || {});
|
||||
|
||||
this.lastKnownScrollY = 0;
|
||||
this.elems = elems;
|
||||
|
||||
this.scroller = options.scroller;
|
||||
|
||||
this.debouncer = onScroll.bind(this);
|
||||
this.offset = options.offset;
|
||||
this.initialised = false;
|
||||
|
||||
this.initialClass = options.initialClass;
|
||||
this.unPinnedClass = options.unPinnedClass;
|
||||
this.pinnedClass = options.pinnedClass;
|
||||
|
||||
this.state = 'clear';
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
this.paused || requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)))
|
||||
}
|
||||
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
|
||||
return Debouncer.prototype = {
|
||||
constructor: Debouncer,
|
||||
update: function() {
|
||||
this.callback && this.callback(), this.ticking = !1
|
||||
},
|
||||
handleEvent: function() {
|
||||
this.ticking || (requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))), this.ticking = !0)
|
||||
|
||||
if (this.paused) {
|
||||
return;
|
||||
}
|
||||
}, Headroom.prototype = {
|
||||
|
||||
requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
|
||||
}
|
||||
|
||||
Headroom.prototype = {
|
||||
constructor: Headroom,
|
||||
init: function() {
|
||||
|
||||
/**
|
||||
* Initialises the widget
|
||||
*/
|
||||
init: function () {
|
||||
|
||||
if (browser.supportsCssAnimation()) {
|
||||
for (var i = 0, length = this.elems.length; i < length; i++) this.elems[i].classList.add(this.initialClass), this.elems[i].addEventListener("clearheadroom", onHeadroomClearedExternally.bind(this));
|
||||
this.attachEvent()
|
||||
for (var i = 0, length = this.elems.length; i < length; i++) {
|
||||
this.elems[i].classList.add(this.initialClass);
|
||||
this.elems[i].addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this));
|
||||
}
|
||||
|
||||
this.attachEvent();
|
||||
}
|
||||
return this
|
||||
|
||||
return this;
|
||||
},
|
||||
add: function(elem) {
|
||||
browser.supportsCssAnimation() && (elem.classList.add(this.initialClass), elem.addEventListener("clearheadroom", onHeadroomClearedExternally.bind(this)), this.elems.push(elem))
|
||||
|
||||
add: function (elem) {
|
||||
|
||||
if (browser.supportsCssAnimation()) {
|
||||
elem.classList.add(this.initialClass);
|
||||
elem.addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this));
|
||||
this.elems.push(elem);
|
||||
}
|
||||
},
|
||||
remove: function(elem) {
|
||||
elem.classList.remove(this.unPinnedClass), elem.classList.remove(this.initialClass), elem.classList.remove(this.pinnedClass);
|
||||
var i = this.elems.indexOf(elem); - 1 !== i && this.elems.splice(i, 1)
|
||||
|
||||
remove: function (elem) {
|
||||
|
||||
elem.classList.remove(this.unPinnedClass);
|
||||
elem.classList.remove(this.initialClass);
|
||||
elem.classList.remove(this.pinnedClass);
|
||||
|
||||
var i = this.elems.indexOf(elem);
|
||||
if (i !== -1) {
|
||||
this.elems.splice(i, 1);
|
||||
}
|
||||
},
|
||||
pause: function() {
|
||||
this.paused = !0
|
||||
|
||||
pause: function () {
|
||||
this.paused = true;
|
||||
},
|
||||
resume: function() {
|
||||
this.paused = !1
|
||||
|
||||
resume: function () {
|
||||
this.paused = false;
|
||||
},
|
||||
destroy: function() {
|
||||
this.initialised = !1;
|
||||
|
||||
/**
|
||||
* Unattaches events and removes any classes that were added
|
||||
*/
|
||||
destroy: function () {
|
||||
|
||||
this.initialised = false;
|
||||
|
||||
for (var i = 0, length = this.elems.length; i < length; i++) {
|
||||
|
||||
var classList = this.elems[i].classList;
|
||||
|
||||
classList.remove(this.unPinnedClass);
|
||||
classList.remove(this.initialClass);
|
||||
classList.remove(this.pinnedClass);
|
||||
}
|
||||
|
||||
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : 'scroll';
|
||||
|
||||
dom.removeEventListener(this.scroller, scrollEventName, this.debouncer, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Attaches the scroll event
|
||||
* @private
|
||||
*/
|
||||
attachEvent: function () {
|
||||
if (!this.initialised) {
|
||||
this.lastKnownScrollY = this.getScrollY();
|
||||
this.initialised = true;
|
||||
|
||||
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : 'scroll';
|
||||
|
||||
dom.addEventListener(this.scroller, scrollEventName, this.debouncer, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Unpins the header if it's currently pinned
|
||||
*/
|
||||
clear: function () {
|
||||
|
||||
if (this.state === 'clear') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = 'clear';
|
||||
|
||||
var unpinnedClass = this.unPinnedClass;
|
||||
var pinnedClass = this.pinnedClass;
|
||||
|
||||
for (var i = 0, length = this.elems.length; i < length; i++) {
|
||||
var classList = this.elems[i].classList;
|
||||
classList.remove(this.unPinnedClass), classList.remove(this.initialClass), classList.remove(this.pinnedClass)
|
||||
}
|
||||
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : "scroll";
|
||||
dom.removeEventListener(this.scroller, scrollEventName, this.debouncer, {
|
||||
capture: !1,
|
||||
passive: !0
|
||||
})
|
||||
},
|
||||
attachEvent: function() {
|
||||
if (!this.initialised) {
|
||||
this.lastKnownScrollY = this.getScrollY(), this.initialised = !0;
|
||||
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : "scroll";
|
||||
dom.addEventListener(this.scroller, scrollEventName, this.debouncer, {
|
||||
capture: !1,
|
||||
passive: !0
|
||||
}), this.update()
|
||||
|
||||
classList.remove(unpinnedClass);
|
||||
//classList.remove(pinnedClass);
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
if ("clear" !== this.state) {
|
||||
this.state = "clear";
|
||||
for (var unpinnedClass = this.unPinnedClass, i = (this.pinnedClass, 0), length = this.elems.length; i < length; i++) {
|
||||
this.elems[i].classList.remove(unpinnedClass)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins the header if it's currently pinned
|
||||
*/
|
||||
pin: function () {
|
||||
|
||||
if (this.state === 'pin') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = 'pin';
|
||||
|
||||
var unpinnedClass = this.unPinnedClass;
|
||||
var pinnedClass = this.pinnedClass;
|
||||
|
||||
for (var i = 0, length = this.elems.length; i < length; i++) {
|
||||
var classList = this.elems[i].classList;
|
||||
|
||||
classList.remove(unpinnedClass);
|
||||
classList.add(pinnedClass);
|
||||
}
|
||||
},
|
||||
pin: function() {
|
||||
if ("pin" !== this.state) {
|
||||
this.state = "pin";
|
||||
for (var unpinnedClass = this.unPinnedClass, pinnedClass = this.pinnedClass, i = 0, length = this.elems.length; i < length; i++) {
|
||||
var classList = this.elems[i].classList;
|
||||
classList.remove(unpinnedClass), classList.add(pinnedClass)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins the header if it's currently pinned
|
||||
*/
|
||||
unpin: function () {
|
||||
|
||||
if (this.state === 'unpin') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = 'unpin';
|
||||
|
||||
var unpinnedClass = this.unPinnedClass;
|
||||
var pinnedClass = this.pinnedClass;
|
||||
|
||||
for (var i = 0, length = this.elems.length; i < length; i++) {
|
||||
var classList = this.elems[i].classList;
|
||||
|
||||
classList.add(unpinnedClass);
|
||||
//classList.remove(pinnedClass);
|
||||
}
|
||||
},
|
||||
unpin: function() {
|
||||
if ("unpin" !== this.state) {
|
||||
this.state = "unpin";
|
||||
for (var unpinnedClass = this.unPinnedClass, i = (this.pinnedClass, 0), length = this.elems.length; i < length; i++) {
|
||||
this.elems[i].classList.add(unpinnedClass)
|
||||
}
|
||||
}
|
||||
},
|
||||
getScrollY: function() {
|
||||
|
||||
/**
|
||||
* Gets the Y scroll position
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY
|
||||
* @return {Number} pixels the page has scrolled along the Y-axis
|
||||
*/
|
||||
getScrollY: function () {
|
||||
|
||||
var scroller = this.scroller;
|
||||
if (scroller.getScrollPosition) return scroller.getScrollPosition();
|
||||
|
||||
if (scroller.getScrollPosition) {
|
||||
return scroller.getScrollPosition();
|
||||
}
|
||||
|
||||
var pageYOffset = scroller.pageYOffset;
|
||||
if (void 0 !== pageYOffset) return pageYOffset;
|
||||
if (pageYOffset !== undefined) {
|
||||
return pageYOffset;
|
||||
}
|
||||
|
||||
var scrollTop = scroller.scrollTop;
|
||||
return void 0 !== scrollTop ? scrollTop : (document.documentElement || document.body).scrollTop
|
||||
if (scrollTop !== undefined) {
|
||||
return scrollTop;
|
||||
}
|
||||
|
||||
return (document.documentElement || document.body).scrollTop;
|
||||
},
|
||||
shouldUnpin: function(currentScrollY) {
|
||||
|
||||
/**
|
||||
* determine if it is appropriate to unpin
|
||||
* @param {int} currentScrollY the current y scroll position
|
||||
* @return {bool} true if should unpin, false otherwise
|
||||
*/
|
||||
shouldUnpin: function (currentScrollY) {
|
||||
var scrollingDown = currentScrollY > this.lastKnownScrollY,
|
||||
pastOffset = currentScrollY >= this.offset;
|
||||
return scrollingDown && pastOffset
|
||||
|
||||
return scrollingDown && pastOffset;
|
||||
},
|
||||
shouldPin: function(currentScrollY) {
|
||||
|
||||
/**
|
||||
* determine if it is appropriate to pin
|
||||
* @param {int} currentScrollY the current y scroll position
|
||||
* @return {bool} true if should pin, false otherwise
|
||||
*/
|
||||
shouldPin: function (currentScrollY) {
|
||||
var scrollingUp = currentScrollY < this.lastKnownScrollY,
|
||||
pastOffset = currentScrollY <= this.offset;
|
||||
return scrollingUp || pastOffset
|
||||
|
||||
return scrollingUp || pastOffset;
|
||||
},
|
||||
update: function() {
|
||||
if (!this.paused) {
|
||||
var currentScrollY = this.getScrollY(),
|
||||
lastKnownScrollY = this.lastKnownScrollY,
|
||||
isTv = layoutManager.tv;
|
||||
if (currentScrollY <= (isTv ? 120 : 10)) this.clear();
|
||||
else if (this.shouldUnpin(currentScrollY)) this.unpin();
|
||||
else if (this.shouldPin(currentScrollY)) {
|
||||
var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14;
|
||||
currentScrollY && isTv ? this.unpin() : toleranceExceeded && this.clear()
|
||||
}
|
||||
this.lastKnownScrollY = currentScrollY
|
||||
|
||||
/**
|
||||
* Handles updating the state of the widget
|
||||
*/
|
||||
update: function () {
|
||||
|
||||
if (this.paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currentScrollY = this.getScrollY();
|
||||
|
||||
var lastKnownScrollY = this.lastKnownScrollY;
|
||||
|
||||
var isTv = layoutManager.tv;
|
||||
|
||||
if (currentScrollY <= (isTv ? 120 : 10)) {
|
||||
this.clear();
|
||||
}
|
||||
else if (this.shouldUnpin(currentScrollY)) {
|
||||
this.unpin();
|
||||
}
|
||||
else if (this.shouldPin(currentScrollY)) {
|
||||
|
||||
var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14;
|
||||
|
||||
if (currentScrollY && isTv) {
|
||||
this.unpin();
|
||||
} else if (toleranceExceeded) {
|
||||
this.clear();
|
||||
}
|
||||
} else if (isTv) {
|
||||
//this.clear();
|
||||
}
|
||||
|
||||
this.lastKnownScrollY = currentScrollY;
|
||||
}
|
||||
}, Headroom.options = {
|
||||
};
|
||||
/**
|
||||
* Default options
|
||||
* @type {Object}
|
||||
*/
|
||||
Headroom.options = {
|
||||
offset: 0,
|
||||
scroller: window,
|
||||
initialClass: "headroom",
|
||||
unPinnedClass: "headroom--unpinned",
|
||||
pinnedClass: "headroom--pinned"
|
||||
}, Headroom
|
||||
initialClass: 'headroom',
|
||||
unPinnedClass: 'headroom--unpinned',
|
||||
pinnedClass: 'headroom--pinned'
|
||||
};
|
||||
|
||||
return Headroom;
|
||||
|
||||
});
|
||||
@@ -1,233 +1,543 @@
|
||||
define(["require", "apphost", "layoutManager", "focusManager", "globalize", "loading", "connectionManager", "homeSections", "dom", "events", "listViewStyle", "emby-select", "emby-checkbox"], function(require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) {
|
||||
define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loading', 'connectionManager', 'homeSections', 'dom', 'events', 'listViewStyle', 'emby-select', 'emby-checkbox'], function (require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) {
|
||||
"use strict";
|
||||
|
||||
var numConfigurableSections = 7;
|
||||
|
||||
function renderViews(page, user, result) {
|
||||
var folderHtml = "";
|
||||
folderHtml += '<div class="checkboxList">', folderHtml += result.map(function(i) {
|
||||
var currentHtml = "",
|
||||
id = "chkGroupFolder" + i.Id,
|
||||
isChecked = -1 !== user.Configuration.GroupedFolders.indexOf(i.Id),
|
||||
checkedHtml = isChecked ? ' checked="checked"' : "";
|
||||
return currentHtml += "<label>", currentHtml += '<input type="checkbox" is="emby-checkbox" class="chkGroupFolder" data-folderid="' + i.Id + '" id="' + id + '"' + checkedHtml + "/>", currentHtml += "<span>" + i.Name + "</span>", currentHtml += "</label>"
|
||||
}).join(""), folderHtml += "</div>", page.querySelector(".folderGroupList").innerHTML = folderHtml
|
||||
|
||||
var folderHtml = '';
|
||||
|
||||
folderHtml += '<div class="checkboxList">';
|
||||
folderHtml += result.map(function (i) {
|
||||
|
||||
var currentHtml = '';
|
||||
|
||||
var id = 'chkGroupFolder' + i.Id;
|
||||
|
||||
var isChecked = user.Configuration.GroupedFolders.indexOf(i.Id) !== -1;
|
||||
|
||||
var checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
|
||||
currentHtml += '<label>';
|
||||
currentHtml += '<input type="checkbox" is="emby-checkbox" class="chkGroupFolder" data-folderid="' + i.Id + '" id="' + id + '"' + checkedHtml + '/>';
|
||||
currentHtml += '<span>' + i.Name + '</span>';
|
||||
currentHtml += '</label>';
|
||||
|
||||
return currentHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
folderHtml += '</div>';
|
||||
|
||||
page.querySelector('.folderGroupList').innerHTML = folderHtml;
|
||||
}
|
||||
|
||||
function getLandingScreenOptions(type) {
|
||||
|
||||
var list = [];
|
||||
return "movies" === type ? (list.push({
|
||||
name: globalize.translate("sharedcomponents#Movies"),
|
||||
value: "movies",
|
||||
isDefault: !0
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Suggestions"),
|
||||
value: "suggestions"
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Favorites"),
|
||||
value: "favorites"
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Collections"),
|
||||
value: "collections"
|
||||
})) : "tvshows" === type ? (list.push({
|
||||
name: globalize.translate("sharedcomponents#Shows"),
|
||||
value: "shows",
|
||||
isDefault: !0
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Suggestions"),
|
||||
value: "suggestions"
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Latest"),
|
||||
value: "latest"
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Favorites"),
|
||||
value: "favorites"
|
||||
})) : "music" === type ? (list.push({
|
||||
name: globalize.translate("sharedcomponents#Suggestions"),
|
||||
value: "suggestions",
|
||||
isDefault: !0
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Albums"),
|
||||
value: "albums"
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#HeaderAlbumArtists"),
|
||||
value: "albumartists"
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Artists"),
|
||||
value: "artists"
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Playlists"),
|
||||
value: "playlists"
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Genres"),
|
||||
value: "genres"
|
||||
})) : "livetv" === type && (list.push({
|
||||
name: globalize.translate("sharedcomponents#Suggestions"),
|
||||
value: "suggestions",
|
||||
isDefault: !0
|
||||
}), list.push({
|
||||
name: globalize.translate("sharedcomponents#Guide"),
|
||||
value: "guide"
|
||||
})), list
|
||||
|
||||
if (type === 'movies') {
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Movies'),
|
||||
value: 'movies',
|
||||
isDefault: true
|
||||
});
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Suggestions'),
|
||||
value: 'suggestions'
|
||||
});
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Favorites'),
|
||||
value: 'favorites'
|
||||
});
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Collections'),
|
||||
value: 'collections'
|
||||
});
|
||||
}
|
||||
else if (type === 'tvshows') {
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Shows'),
|
||||
value: 'shows',
|
||||
isDefault: true
|
||||
});
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Suggestions'),
|
||||
value: 'suggestions'
|
||||
});
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Latest'),
|
||||
value: 'latest'
|
||||
});
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Favorites'),
|
||||
value: 'favorites'
|
||||
});
|
||||
}
|
||||
else if (type === 'music') {
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Suggestions'),
|
||||
value: 'suggestions',
|
||||
isDefault: true
|
||||
});
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Albums'),
|
||||
value: 'albums'
|
||||
});
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#HeaderAlbumArtists'),
|
||||
value: 'albumartists'
|
||||
});
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Artists'),
|
||||
value: 'artists'
|
||||
});
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Playlists'),
|
||||
value: 'playlists'
|
||||
});
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Genres'),
|
||||
value: 'genres'
|
||||
});
|
||||
}
|
||||
else if (type === 'livetv') {
|
||||
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Suggestions'),
|
||||
value: 'suggestions',
|
||||
isDefault: true
|
||||
});
|
||||
list.push({
|
||||
name: globalize.translate('sharedcomponents#Guide'),
|
||||
value: 'guide'
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function getLandingScreenOptionsHtml(type, userValue) {
|
||||
return getLandingScreenOptions(type).map(function(o) {
|
||||
var selected = userValue === o.value || o.isDefault && !userValue,
|
||||
selectedHtml = selected ? " selected" : "";
|
||||
return '<option value="' + (o.isDefault ? "" : o.value) + '"' + selectedHtml + ">" + o.name + "</option>"
|
||||
}).join("")
|
||||
|
||||
return getLandingScreenOptions(type).map(function (o) {
|
||||
|
||||
var selected = userValue === o.value || (o.isDefault && !userValue);
|
||||
var selectedHtml = selected ? ' selected' : '';
|
||||
var optionValue = o.isDefault ? '' : o.value;
|
||||
|
||||
return '<option value="' + optionValue + '"' + selectedHtml + '>' + o.name + '</option>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function renderViewOrder(context, user, result) {
|
||||
var html = "",
|
||||
index = 0;
|
||||
html += result.Items.map(function(view) {
|
||||
var currentHtml = "";
|
||||
return currentHtml += '<div class="listItem viewItem" data-viewid="' + view.Id + '">', currentHtml += '<i class="md-icon listItemIcon"></i>', currentHtml += '<div class="listItemBody">', currentHtml += "<div>", currentHtml += view.Name, currentHtml += "</div>", currentHtml += "</div>", currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemUp btnViewItemMove autoSize" title="' + globalize.translate("sharedcomponents#Up") + '"><i class="md-icon"></i></button>', currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="' + globalize.translate("sharedcomponents#Down") + '"><i class="md-icon"></i></button>', currentHtml += "</div>", index++, currentHtml
|
||||
}).join(""), context.querySelector(".viewOrderList").innerHTML = html
|
||||
|
||||
var html = '';
|
||||
|
||||
var index = 0;
|
||||
|
||||
html += result.Items.map(function (view) {
|
||||
|
||||
var currentHtml = '';
|
||||
|
||||
currentHtml += '<div class="listItem viewItem" data-viewid="' + view.Id + '">';
|
||||
|
||||
currentHtml += '<i class="md-icon listItemIcon"></i>';
|
||||
|
||||
currentHtml += '<div class="listItemBody">';
|
||||
|
||||
currentHtml += '<div>';
|
||||
currentHtml += view.Name;
|
||||
currentHtml += '</div>';
|
||||
|
||||
currentHtml += '</div>';
|
||||
|
||||
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemUp btnViewItemMove autoSize" title="' + globalize.translate('sharedcomponents#Up') + '"><i class="md-icon"></i></button>';
|
||||
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="' + globalize.translate('sharedcomponents#Down') + '"><i class="md-icon"></i></button>';
|
||||
|
||||
currentHtml += '</div>';
|
||||
|
||||
index++;
|
||||
return currentHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
context.querySelector('.viewOrderList').innerHTML = html;
|
||||
}
|
||||
|
||||
function updateHomeSectionValues(context, userSettings) {
|
||||
|
||||
for (var i = 1; i <= 7; i++) {
|
||||
var select = context.querySelector("#selectHomeSection" + i),
|
||||
defaultValue = homeSections.getDefaultSection(i - 1),
|
||||
option = select.querySelector("option[value=" + defaultValue + "]") || select.querySelector('option[value=""]'),
|
||||
userValue = userSettings.get("homesection" + (i - 1));
|
||||
option.value = "", select.value = userValue !== defaultValue && userValue ? userValue : ""
|
||||
|
||||
var select = context.querySelector('#selectHomeSection' + i);
|
||||
var defaultValue = homeSections.getDefaultSection(i - 1);
|
||||
|
||||
var option = select.querySelector('option[value=' + defaultValue + ']') || select.querySelector('option[value=""]');
|
||||
|
||||
var userValue = userSettings.get('homesection' + (i - 1));
|
||||
|
||||
option.value = '';
|
||||
|
||||
if (userValue === defaultValue || !userValue) {
|
||||
select.value = '';
|
||||
} else {
|
||||
select.value = userValue;
|
||||
}
|
||||
}
|
||||
context.querySelector(".selectTVHomeScreen").value = userSettings.get("tvhome") || ""
|
||||
|
||||
context.querySelector('.selectTVHomeScreen').value = userSettings.get('tvhome') || '';
|
||||
}
|
||||
|
||||
function getPerLibrarySettingsHtml(item, user, userSettings, apiClient) {
|
||||
var isChecked, html = "";
|
||||
if ("Channel" !== item.Type && "boxsets" !== item.CollectionType && "playlists" !== item.CollectionType || (isChecked = -1 === (user.Configuration.MyMediaExcludes || []).indexOf(item.Id), html += "<div>", html += "<label>", html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInMyMedia" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : "") + "/>", html += "<span>" + globalize.translate("sharedcomponents#DisplayInMyMedia") + "</span>", html += "</label>", html += "</div>"), -1 === ["playlists", "livetv", "boxsets", "channels"].indexOf(item.CollectionType || "") && (isChecked = -1 === user.Configuration.LatestItemsExcludes.indexOf(item.Id), html += '<label class="fldIncludeInLatest">', html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : "") + "/>", html += "<span>" + globalize.translate("sharedcomponents#DisplayInOtherHomeScreenSections") + "</span>", html += "</label>"), html && (html = '<div class="checkboxListContainer">' + html + "</div>"), "movies" === item.CollectionType || "tvshows" === item.CollectionType || "music" === item.CollectionType || "livetv" === item.CollectionType) {
|
||||
var idForLanding = "livetv" === item.CollectionType ? item.CollectionType : item.Id;
|
||||
html += '<div class="selectContainer">', html += '<select is="emby-select" class="selectLanding" data-folderid="' + idForLanding + '" label="' + globalize.translate("sharedcomponents#LabelDefaultScreen") + '">';
|
||||
var userValue = userSettings.get("landing-" + idForLanding);
|
||||
html += getLandingScreenOptionsHtml(item.CollectionType, userValue), html += "</select>", html += "</div>"
|
||||
|
||||
var html = '';
|
||||
|
||||
var isChecked;
|
||||
|
||||
if (item.Type === 'Channel' || item.CollectionType === 'boxsets' || item.CollectionType === 'playlists') {
|
||||
isChecked = (user.Configuration.MyMediaExcludes || []).indexOf(item.Id) === -1;
|
||||
html += '<div>';
|
||||
html += '<label>';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInMyMedia" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : '') + '/>';
|
||||
html += '<span>' + globalize.translate('sharedcomponents#DisplayInMyMedia') + '</span>';
|
||||
html += '</label>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
var excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels'];
|
||||
if (excludeFromLatest.indexOf(item.CollectionType || '') === -1) {
|
||||
|
||||
isChecked = user.Configuration.LatestItemsExcludes.indexOf(item.Id) === -1;
|
||||
html += '<label class="fldIncludeInLatest">';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : '') + '/>';
|
||||
html += '<span>' + globalize.translate('sharedcomponents#DisplayInOtherHomeScreenSections') + '</span>';
|
||||
html += '</label>';
|
||||
}
|
||||
|
||||
if (html) {
|
||||
var prefix = "";
|
||||
prefix += '<div class="verticalSection">', prefix += '<h2 class="sectionTitle">', prefix += item.Name, prefix += "</h2>", html = prefix + html, html += "</div>"
|
||||
|
||||
html = '<div class="checkboxListContainer">' + html + '</div>';
|
||||
}
|
||||
return html
|
||||
|
||||
if (item.CollectionType === 'movies' || item.CollectionType === 'tvshows' || item.CollectionType === 'music' || item.CollectionType === 'livetv') {
|
||||
|
||||
var idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id;
|
||||
html += '<div class="selectContainer">';
|
||||
html += '<select is="emby-select" class="selectLanding" data-folderid="' + idForLanding + '" label="' + globalize.translate('sharedcomponents#LabelDefaultScreen') + '">';
|
||||
|
||||
var userValue = userSettings.get('landing-' + idForLanding);
|
||||
|
||||
html += getLandingScreenOptionsHtml(item.CollectionType, userValue);
|
||||
|
||||
html += '</select>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
var prefix = '';
|
||||
prefix += '<div class="verticalSection">';
|
||||
|
||||
prefix += '<h2 class="sectionTitle">';
|
||||
prefix += item.Name;
|
||||
prefix += '</h2>';
|
||||
|
||||
html = prefix + html;
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderPerLibrarySettings(context, user, userViews, userSettings, apiClient) {
|
||||
for (var elem = context.querySelector(".perLibrarySettings"), html = "", i = 0, length = userViews.length; i < length; i++) html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient);
|
||||
elem.innerHTML = html
|
||||
|
||||
var elem = context.querySelector('.perLibrarySettings');
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = userViews.length; i < length; i++) {
|
||||
|
||||
html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient);
|
||||
}
|
||||
|
||||
elem.innerHTML = html;
|
||||
}
|
||||
|
||||
function loadForm(context, user, userSettings, apiClient) {
|
||||
context.querySelector(".chkHidePlayedFromLatest").checked = user.Configuration.HidePlayedInLatest || !1, updateHomeSectionValues(context, userSettings);
|
||||
var promise1 = apiClient.getUserViews({
|
||||
IncludeHidden: !0
|
||||
}, user.Id),
|
||||
promise2 = apiClient.getJSON(apiClient.getUrl("Users/" + user.Id + "/GroupingOptions"));
|
||||
Promise.all([promise1, promise2]).then(function(responses) {
|
||||
renderViewOrder(context, user, responses[0]), renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient), renderViews(context, user, responses[1]), loading.hide()
|
||||
})
|
||||
|
||||
context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false;
|
||||
|
||||
updateHomeSectionValues(context, userSettings);
|
||||
|
||||
var promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id);
|
||||
var promise2 = apiClient.getJSON(apiClient.getUrl("Users/" + user.Id + "/GroupingOptions"));
|
||||
|
||||
Promise.all([promise1, promise2]).then(function (responses) {
|
||||
|
||||
renderViewOrder(context, user, responses[0]);
|
||||
|
||||
renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient);
|
||||
|
||||
renderViews(context, user, responses[1]);
|
||||
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function getSibling(elem, type, className) {
|
||||
|
||||
var sibling = elem[type];
|
||||
|
||||
while (sibling != null) {
|
||||
if (sibling.classList.contains(className)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sibling != null) {
|
||||
if (!sibling.classList.contains(className)) {
|
||||
sibling = null;
|
||||
}
|
||||
}
|
||||
|
||||
return sibling;
|
||||
}
|
||||
|
||||
function onSectionOrderListClick(e) {
|
||||
var target = dom.parentWithClass(e.target, "btnViewItemMove");
|
||||
|
||||
var target = dom.parentWithClass(e.target, 'btnViewItemMove');
|
||||
|
||||
if (target) {
|
||||
var viewItem = dom.parentWithClass(target, "viewItem");
|
||||
var viewItem = dom.parentWithClass(target, 'viewItem');
|
||||
|
||||
if (viewItem) {
|
||||
dom.parentWithClass(viewItem, "paperList");
|
||||
if (target.classList.contains("btnViewItemDown")) {
|
||||
var ul = dom.parentWithClass(viewItem, 'paperList');
|
||||
|
||||
if (target.classList.contains('btnViewItemDown')) {
|
||||
|
||||
var next = viewItem.nextSibling;
|
||||
next && (viewItem.parentNode.removeChild(viewItem), next.parentNode.insertBefore(viewItem, next.nextSibling))
|
||||
|
||||
if (next) {
|
||||
viewItem.parentNode.removeChild(viewItem);
|
||||
next.parentNode.insertBefore(viewItem, next.nextSibling);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
var prev = viewItem.previousSibling;
|
||||
prev && (viewItem.parentNode.removeChild(viewItem), prev.parentNode.insertBefore(viewItem, prev))
|
||||
|
||||
if (prev) {
|
||||
viewItem.parentNode.removeChild(viewItem);
|
||||
prev.parentNode.insertBefore(viewItem, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCheckboxItems(selector, context, isChecked) {
|
||||
for (var inputs = context.querySelectorAll(selector), list = [], i = 0, length = inputs.length; i < length; i++) inputs[i].checked === isChecked && list.push(inputs[i]);
|
||||
return list
|
||||
|
||||
var inputs = context.querySelectorAll(selector);
|
||||
var list = [];
|
||||
|
||||
for (var i = 0, length = inputs.length; i < length; i++) {
|
||||
|
||||
if (inputs[i].checked === isChecked) {
|
||||
list.push(inputs[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
user.Configuration.HidePlayedInLatest = context.querySelector(".chkHidePlayedFromLatest").checked, user.Configuration.LatestItemsExcludes = getCheckboxItems(".chkIncludeInLatest", context, !1).map(function(i) {
|
||||
return i.getAttribute("data-folderid")
|
||||
}), user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, !1).map(function(i) {
|
||||
return i.getAttribute("data-folderid")
|
||||
}), user.Configuration.GroupedFolders = getCheckboxItems(".chkGroupFolder", context, !0).map(function(i) {
|
||||
return i.getAttribute("data-folderid")
|
||||
|
||||
user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked;
|
||||
|
||||
user.Configuration.LatestItemsExcludes = getCheckboxItems(".chkIncludeInLatest", context, false).map(function (i) {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
var i, length, viewItems = context.querySelectorAll(".viewItem"),
|
||||
orderedViews = [];
|
||||
for (i = 0, length = viewItems.length; i < length; i++) orderedViews.push(viewItems[i].getAttribute("data-viewid"));
|
||||
user.Configuration.OrderedViews = orderedViews, userSettingsInstance.set("tvhome", context.querySelector(".selectTVHomeScreen").value), userSettingsInstance.set("homesection0", context.querySelector("#selectHomeSection1").value), userSettingsInstance.set("homesection1", context.querySelector("#selectHomeSection2").value), userSettingsInstance.set("homesection2", context.querySelector("#selectHomeSection3").value), userSettingsInstance.set("homesection3", context.querySelector("#selectHomeSection4").value), userSettingsInstance.set("homesection4", context.querySelector("#selectHomeSection5").value), userSettingsInstance.set("homesection5", context.querySelector("#selectHomeSection6").value), userSettingsInstance.set("homesection6", context.querySelector("#selectHomeSection7").value);
|
||||
var selectLandings = context.querySelectorAll(".selectLanding");
|
||||
|
||||
user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, false).map(function (i) {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
user.Configuration.GroupedFolders = getCheckboxItems(".chkGroupFolder", context, true).map(function (i) {
|
||||
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
var viewItems = context.querySelectorAll('.viewItem');
|
||||
var orderedViews = [];
|
||||
var i, length;
|
||||
for (i = 0, length = viewItems.length; i < length; i++) {
|
||||
orderedViews.push(viewItems[i].getAttribute('data-viewid'));
|
||||
}
|
||||
|
||||
user.Configuration.OrderedViews = orderedViews;
|
||||
|
||||
userSettingsInstance.set('tvhome', context.querySelector('.selectTVHomeScreen').value);
|
||||
|
||||
userSettingsInstance.set('homesection0', context.querySelector('#selectHomeSection1').value);
|
||||
userSettingsInstance.set('homesection1', context.querySelector('#selectHomeSection2').value);
|
||||
userSettingsInstance.set('homesection2', context.querySelector('#selectHomeSection3').value);
|
||||
userSettingsInstance.set('homesection3', context.querySelector('#selectHomeSection4').value);
|
||||
userSettingsInstance.set('homesection4', context.querySelector('#selectHomeSection5').value);
|
||||
userSettingsInstance.set('homesection5', context.querySelector('#selectHomeSection6').value);
|
||||
userSettingsInstance.set('homesection6', context.querySelector('#selectHomeSection7').value);
|
||||
|
||||
var selectLandings = context.querySelectorAll('.selectLanding');
|
||||
for (i = 0, length = selectLandings.length; i < length; i++) {
|
||||
var selectLanding = selectLandings[i];
|
||||
userSettingsInstance.set("landing-" + selectLanding.getAttribute("data-folderid"), selectLanding.value)
|
||||
userSettingsInstance.set('landing-' + selectLanding.getAttribute('data-folderid'), selectLanding.value);
|
||||
}
|
||||
return apiClient.updateUserConfiguration(user.Id, user.Configuration)
|
||||
|
||||
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
|
||||
}
|
||||
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
loading.show(), apiClient.getUser(userId).then(function(user) {
|
||||
saveUser(context, user, userSettings, apiClient).then(function() {
|
||||
loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) {
|
||||
toast(globalize.translate("sharedcomponents#SettingsSaved"))
|
||||
}), events.trigger(instance, "saved")
|
||||
}, function() {
|
||||
loading.hide()
|
||||
})
|
||||
})
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(function (user) {
|
||||
|
||||
saveUser(context, user, userSettings, apiClient).then(function () {
|
||||
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('sharedcomponents#SettingsSaved'));
|
||||
});
|
||||
}
|
||||
|
||||
events.trigger(instance, 'saved');
|
||||
|
||||
}, function () {
|
||||
loading.hide();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
var self = this,
|
||||
apiClient = connectionManager.getApiClient(self.options.serverId),
|
||||
userId = self.options.userId,
|
||||
userSettings = self.options.userSettings;
|
||||
return userSettings.setUserInfo(userId, apiClient).then(function() {
|
||||
|
||||
var self = this;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userId = self.options.userId;
|
||||
var userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
|
||||
var enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation)
|
||||
}), e && e.preventDefault(), !1
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
|
||||
// Disable default form submission
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function onChange(e) {
|
||||
var chkIncludeInMyMedia = dom.parentWithClass(e.target, "chkIncludeInMyMedia");
|
||||
if (chkIncludeInMyMedia) {
|
||||
var section = dom.parentWithClass(chkIncludeInMyMedia, "verticalSection"),
|
||||
fldIncludeInLatest = section.querySelector(".fldIncludeInLatest");
|
||||
fldIncludeInLatest && (chkIncludeInMyMedia.checked ? fldIncludeInLatest.classList.remove("hide") : fldIncludeInLatest.classList.add("hide"))
|
||||
|
||||
var chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
|
||||
if (!chkIncludeInMyMedia) {
|
||||
return;
|
||||
}
|
||||
|
||||
var section = dom.parentWithClass(chkIncludeInMyMedia, 'verticalSection');
|
||||
var fldIncludeInLatest = section.querySelector('.fldIncludeInLatest');
|
||||
if (fldIncludeInLatest) {
|
||||
if (chkIncludeInMyMedia.checked) {
|
||||
fldIncludeInLatest.classList.remove('hide');
|
||||
} else {
|
||||
fldIncludeInLatest.classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function embed(options, self) {
|
||||
require(["text!./homescreensettings.template.html"], function(template) {
|
||||
for (var i = 1; i <= numConfigurableSections; i++) template = template.replace("{section" + i + "label}", globalize.translate("sharedcomponents#LabelHomeScreenSectionValue", i));
|
||||
options.element.innerHTML = globalize.translateDocument(template, "sharedcomponents"), options.element.querySelector(".viewOrderList").addEventListener("click", onSectionOrderListClick), options.element.querySelector("form").addEventListener("submit", onSubmit.bind(self)), options.element.addEventListener("change", onChange), options.enableSaveButton && options.element.querySelector(".btnSave").classList.remove("hide"), layoutManager.tv ? options.element.querySelector(".selectTVHomeScreenContainer").classList.remove("hide") : options.element.querySelector(".selectTVHomeScreenContainer").classList.add("hide"), self.loadData(options.autoFocus)
|
||||
})
|
||||
|
||||
require(['text!./homescreensettings.template.html'], function (template) {
|
||||
|
||||
for (var i = 1; i <= numConfigurableSections; i++) {
|
||||
template = template.replace('{section' + i + 'label}', globalize.translate('sharedcomponents#LabelHomeScreenSectionValue', i));
|
||||
}
|
||||
|
||||
options.element.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
options.element.querySelector('.viewOrderList').addEventListener('click', onSectionOrderListClick);
|
||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||
options.element.addEventListener('change', onChange);
|
||||
|
||||
if (options.enableSaveButton) {
|
||||
options.element.querySelector('.btnSave').classList.remove('hide');
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
options.element.querySelector('.selectTVHomeScreenContainer').classList.remove('hide');
|
||||
} else {
|
||||
options.element.querySelector('.selectTVHomeScreenContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
self.loadData(options.autoFocus);
|
||||
});
|
||||
}
|
||||
|
||||
function HomeScreenSettings(options) {
|
||||
this.options = options, embed(options, this)
|
||||
|
||||
this.options = options;
|
||||
|
||||
embed(options, this);
|
||||
}
|
||||
var numConfigurableSections = 7;
|
||||
return HomeScreenSettings.prototype.loadData = function(autoFocus) {
|
||||
var self = this,
|
||||
context = self.options.element;
|
||||
|
||||
HomeScreenSettings.prototype.loadData = function (autoFocus) {
|
||||
|
||||
var self = this;
|
||||
var context = self.options.element;
|
||||
|
||||
loading.show();
|
||||
var userId = self.options.userId,
|
||||
apiClient = connectionManager.getApiClient(self.options.serverId),
|
||||
userSettings = self.options.userSettings;
|
||||
apiClient.getUser(userId).then(function(user) {
|
||||
userSettings.setUserInfo(userId, apiClient).then(function() {
|
||||
self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient), autoFocus && focusManager.autoFocus(context)
|
||||
})
|
||||
})
|
||||
}, HomeScreenSettings.prototype.submit = function() {
|
||||
onSubmit.call(this)
|
||||
}, HomeScreenSettings.prototype.destroy = function() {
|
||||
this.options = null
|
||||
}, HomeScreenSettings
|
||||
|
||||
var userId = self.options.userId;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userSettings = self.options.userSettings;
|
||||
|
||||
apiClient.getUser(userId).then(function (user) {
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
|
||||
if (autoFocus) {
|
||||
focusManager.autoFocus(context);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
HomeScreenSettings.prototype.submit = function () {
|
||||
onSubmit.call(this);
|
||||
};
|
||||
|
||||
HomeScreenSettings.prototype.destroy = function () {
|
||||
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return HomeScreenSettings;
|
||||
});
|
||||
@@ -1,47 +1,88 @@
|
||||
define(["dialogHelper", "layoutManager", "globalize", "require", "events", "homescreenSettings", "paper-icon-button-light", "css!./../formdialog"], function(dialogHelper, layoutManager, globalize, require, events, HomescreenSettings) {
|
||||
"use strict";
|
||||
define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'events', 'homescreenSettings', 'paper-icon-button-light', 'css!./../formdialog'], function (dialogHelper, layoutManager, globalize, require, events, HomescreenSettings) {
|
||||
'use strict';
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(["scrollHelper"], function(scrollHelper) {
|
||||
var fn = on ? "on" : "off";
|
||||
scrollHelper.centerFocus[fn](elem, horiz)
|
||||
})
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function show(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
require(["text!./homescreensettingsdialog.template.html"], function(template) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['text!./homescreensettingsdialog.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: !0,
|
||||
scrollY: !1
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "medium-tall";
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'medium-tall';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add("formDialog");
|
||||
var html = "",
|
||||
submitted = !1;
|
||||
html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
var submitted = false;
|
||||
|
||||
html += globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
||||
}
|
||||
|
||||
var homescreenSettingsInstance = new HomescreenSettings({
|
||||
serverId: options.serverId,
|
||||
userId: options.userId,
|
||||
element: dlg.querySelector(".settingsContent"),
|
||||
element: dlg.querySelector('.settingsContent'),
|
||||
userSettings: options.userSettings,
|
||||
enableSaveButton: !1,
|
||||
enableSaveConfirmation: !1
|
||||
enableSaveButton: false,
|
||||
enableSaveConfirmation: false
|
||||
});
|
||||
dialogHelper.open(dlg), dlg.addEventListener("close", function() {
|
||||
layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted ? resolve() : reject()
|
||||
}), dlg.querySelector(".btnCancel").addEventListener("click", function(e) {
|
||||
dialogHelper.close(dlg)
|
||||
}), dlg.querySelector(".btnSave").addEventListener("click", function(e) {
|
||||
submitted = !0, homescreenSettingsInstance.submit()
|
||||
}), events.on(homescreenSettingsInstance, "saved", function() {
|
||||
submitted = !0, dialogHelper.close(dlg)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnSave').addEventListener('click', function (e) {
|
||||
|
||||
submitted = true;
|
||||
homescreenSettingsInstance.submit();
|
||||
});
|
||||
|
||||
events.on(homescreenSettingsInstance, 'saved', function () {
|
||||
submitted = true;
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: show
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,10 +1,11 @@
|
||||
.homeLibraryButton {
|
||||
.homeLibraryButton {
|
||||
min-width: 18%;
|
||||
margin: .5em !important
|
||||
margin: .5em !important;
|
||||
}
|
||||
|
||||
@media all and (max-width:50em) {
|
||||
@media all and (max-width: 50em) {
|
||||
|
||||
.homeLibraryButton {
|
||||
width: 46% !important
|
||||
width: 46% !important;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,218 +1,515 @@
|
||||
define(["events", "browser", "require", "apphost", "appSettings", "htmlMediaHelper"], function(events, browser, require, appHost, appSettings, htmlMediaHelper) {
|
||||
define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelper'], function (events, browser, require, appHost, appSettings, htmlMediaHelper) {
|
||||
"use strict";
|
||||
|
||||
function getDefaultProfile() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
require(["browserdeviceprofile"], function(profileBuilder) {
|
||||
resolve(profileBuilder({}))
|
||||
})
|
||||
})
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['browserdeviceprofile'], function (profileBuilder) {
|
||||
|
||||
resolve(profileBuilder({}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var fadeTimeout;
|
||||
function fade(instance, elem, startingVolume) {
|
||||
instance._isFadingOut = !0;
|
||||
var newVolume = Math.max(0, startingVolume - .15);
|
||||
return console.log("fading volume to " + newVolume), elem.volume = newVolume, newVolume <= 0 ? (instance._isFadingOut = !1, Promise.resolve()) : new Promise(function(resolve, reject) {
|
||||
cancelFadeTimeout(), fadeTimeout = setTimeout(function() {
|
||||
fade(instance, elem, newVolume).then(resolve, reject)
|
||||
}, 100)
|
||||
})
|
||||
|
||||
instance._isFadingOut = true;
|
||||
|
||||
// Need to record the starting volume on each pass rather than querying elem.volume
|
||||
// This is due to iOS safari not allowing volume changes and always returning the system volume value
|
||||
|
||||
var newVolume = Math.max(0, startingVolume - 0.15);
|
||||
console.log('fading volume to ' + newVolume);
|
||||
elem.volume = newVolume;
|
||||
|
||||
if (newVolume <= 0) {
|
||||
|
||||
instance._isFadingOut = false;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
cancelFadeTimeout();
|
||||
|
||||
fadeTimeout = setTimeout(function () {
|
||||
|
||||
fade(instance, elem, newVolume).then(resolve, reject);
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function cancelFadeTimeout() {
|
||||
var timeout = fadeTimeout;
|
||||
timeout && (clearTimeout(timeout), fadeTimeout = null)
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
fadeTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsFade() {
|
||||
return !browser.tv
|
||||
|
||||
if (browser.tv) {
|
||||
// Not working on tizen.
|
||||
// We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function requireHlsPlayer(callback) {
|
||||
require(["hlsjs"], function(hls) {
|
||||
window.Hls = hls, callback()
|
||||
})
|
||||
require(['hlsjs'], function (hls) {
|
||||
window.Hls = hls;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function enableHlsPlayer(url, item, mediaSource, mediaType) {
|
||||
return htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType) ? -1 !== url.indexOf(".m3u8") ? Promise.resolve() : new Promise(function(resolve, reject) {
|
||||
require(["fetchHelper"], function(fetchHelper) {
|
||||
|
||||
if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) {
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
if (url.indexOf('.m3u8') !== -1) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// issue head request to get content type
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['fetchHelper'], function (fetchHelper) {
|
||||
fetchHelper.ajax({
|
||||
url: url,
|
||||
type: "HEAD"
|
||||
}).then(function(response) {
|
||||
"application/x-mpegurl" === (response.headers.get("Content-Type") || "").toLowerCase() ? resolve() : reject()
|
||||
}, reject)
|
||||
})
|
||||
}) : Promise.reject()
|
||||
type: 'HEAD'
|
||||
}).then(function (response) {
|
||||
|
||||
var contentType = (response.headers.get('Content-Type') || '').toLowerCase();
|
||||
if (contentType === 'application/x-mpegurl') {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
|
||||
}, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function HtmlAudioPlayer() {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.name = 'Html Audio Player';
|
||||
self.type = 'mediaplayer';
|
||||
self.id = 'htmlaudioplayer';
|
||||
|
||||
// Let any players created by plugins take priority
|
||||
self.priority = 1;
|
||||
|
||||
self.play = function (options) {
|
||||
|
||||
self._started = false;
|
||||
self._timeUpdated = false;
|
||||
|
||||
self._currentTime = null;
|
||||
|
||||
var elem = createMediaElement(options);
|
||||
|
||||
return setCurrentSrc(elem, options);
|
||||
};
|
||||
|
||||
function setCurrentSrc(elem, options) {
|
||||
elem.removeEventListener("error", onError), unBindEvents(elem), bindEvents(elem);
|
||||
|
||||
elem.removeEventListener('error', onError);
|
||||
|
||||
unBindEvents(elem);
|
||||
bindEvents(elem);
|
||||
|
||||
var val = options.url;
|
||||
console.log("playing url: " + val);
|
||||
var seconds = (options.playerStartPositionTicks || 0) / 1e7;
|
||||
seconds && (val += "#t=" + seconds), htmlMediaHelper.destroyHlsPlayer(self), self._currentPlayOptions = options;
|
||||
console.log('playing url: ' + val);
|
||||
|
||||
// Convert to seconds
|
||||
var seconds = (options.playerStartPositionTicks || 0) / 10000000;
|
||||
if (seconds) {
|
||||
val += '#t=' + seconds;
|
||||
}
|
||||
|
||||
htmlMediaHelper.destroyHlsPlayer(self);
|
||||
|
||||
self._currentPlayOptions = options;
|
||||
|
||||
var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
|
||||
return crossOrigin && (elem.crossOrigin = crossOrigin), enableHlsPlayer(val, options.item, options.mediaSource, "Audio").then(function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
requireHlsPlayer(function() {
|
||||
if (crossOrigin) {
|
||||
elem.crossOrigin = crossOrigin;
|
||||
}
|
||||
|
||||
return enableHlsPlayer(val, options.item, options.mediaSource, 'Audio').then(function () {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
requireHlsPlayer(function () {
|
||||
var hls = new Hls({
|
||||
manifestLoadingTimeOut: 2e4
|
||||
manifestLoadingTimeOut: 20000
|
||||
//appendErrorMaxRetry: 6,
|
||||
//debug: true
|
||||
});
|
||||
hls.loadSource(val), hls.attachMedia(elem), htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject), self._hlsPlayer = hls, self._currentSrc = val
|
||||
})
|
||||
})
|
||||
}, function() {
|
||||
return elem.autoplay = !0, htmlMediaHelper.applySrc(elem, val, options).then(function() {
|
||||
return self._currentSrc = val, htmlMediaHelper.playWithPromise(elem, onError)
|
||||
})
|
||||
})
|
||||
hls.loadSource(val);
|
||||
hls.attachMedia(elem);
|
||||
|
||||
htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject);
|
||||
|
||||
self._hlsPlayer = hls;
|
||||
|
||||
self._currentSrc = val;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}, function () {
|
||||
|
||||
elem.autoplay = true;
|
||||
|
||||
return htmlMediaHelper.applySrc(elem, val, options).then(function () {
|
||||
|
||||
self._currentSrc = val;
|
||||
|
||||
return htmlMediaHelper.playWithPromise(elem, onError);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function bindEvents(elem) {
|
||||
elem.addEventListener("timeupdate", onTimeUpdate), elem.addEventListener("ended", onEnded), elem.addEventListener("volumechange", onVolumeChange), elem.addEventListener("pause", onPause), elem.addEventListener("playing", onPlaying), elem.addEventListener("play", onPlay)
|
||||
elem.addEventListener('timeupdate', onTimeUpdate);
|
||||
elem.addEventListener('ended', onEnded);
|
||||
elem.addEventListener('volumechange', onVolumeChange);
|
||||
elem.addEventListener('pause', onPause);
|
||||
elem.addEventListener('playing', onPlaying);
|
||||
elem.addEventListener('play', onPlay);
|
||||
}
|
||||
|
||||
function unBindEvents(elem) {
|
||||
elem.removeEventListener("timeupdate", onTimeUpdate), elem.removeEventListener("ended", onEnded), elem.removeEventListener("volumechange", onVolumeChange), elem.removeEventListener("pause", onPause), elem.removeEventListener("playing", onPlaying), elem.removeEventListener("play", onPlay)
|
||||
elem.removeEventListener('timeupdate', onTimeUpdate);
|
||||
elem.removeEventListener('ended', onEnded);
|
||||
elem.removeEventListener('volumechange', onVolumeChange);
|
||||
elem.removeEventListener('pause', onPause);
|
||||
elem.removeEventListener('playing', onPlaying);
|
||||
elem.removeEventListener('play', onPlay);
|
||||
}
|
||||
|
||||
function createMediaElement() {
|
||||
self.stop = function (destroyPlayer) {
|
||||
|
||||
cancelFadeTimeout();
|
||||
|
||||
var elem = self._mediaElement;
|
||||
return elem || (elem = document.querySelector(".mediaPlayerAudio"), elem || (elem = document.createElement("audio"), elem.classList.add("mediaPlayerAudio"), elem.classList.add("hide"), document.body.appendChild(elem)), elem.volume = htmlMediaHelper.getSavedVolume(), self._mediaElement = elem, elem)
|
||||
var src = self._currentSrc;
|
||||
|
||||
if (elem && src) {
|
||||
|
||||
if (!destroyPlayer || !supportsFade()) {
|
||||
|
||||
elem.pause();
|
||||
|
||||
htmlMediaHelper.onEndedInternal(self, elem, onError);
|
||||
|
||||
if (destroyPlayer) {
|
||||
self.destroy();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var originalVolume = elem.volume;
|
||||
|
||||
return fade(self, elem, elem.volume).then(function () {
|
||||
|
||||
elem.pause();
|
||||
elem.volume = originalVolume;
|
||||
|
||||
htmlMediaHelper.onEndedInternal(self, elem, onError);
|
||||
|
||||
if (destroyPlayer) {
|
||||
self.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
self.destroy = function () {
|
||||
unBindEvents(self._mediaElement);
|
||||
};
|
||||
|
||||
function createMediaElement() {
|
||||
|
||||
var elem = self._mediaElement;
|
||||
|
||||
if (elem) {
|
||||
return elem;
|
||||
}
|
||||
|
||||
elem = document.querySelector('.mediaPlayerAudio');
|
||||
|
||||
if (!elem) {
|
||||
elem = document.createElement('audio');
|
||||
elem.classList.add('mediaPlayerAudio');
|
||||
elem.classList.add('hide');
|
||||
|
||||
document.body.appendChild(elem);
|
||||
}
|
||||
|
||||
elem.volume = htmlMediaHelper.getSavedVolume();
|
||||
|
||||
self._mediaElement = elem;
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function onEnded() {
|
||||
htmlMediaHelper.onEndedInternal(self, this, onError)
|
||||
|
||||
htmlMediaHelper.onEndedInternal(self, this, onError);
|
||||
}
|
||||
|
||||
function onTimeUpdate() {
|
||||
|
||||
// Get the player position + the transcoding offset
|
||||
var time = this.currentTime;
|
||||
self._isFadingOut || (self._currentTime = time, events.trigger(self, "timeupdate"))
|
||||
|
||||
// Don't trigger events after user stop
|
||||
if (!self._isFadingOut) {
|
||||
self._currentTime = time;
|
||||
events.trigger(self, 'timeupdate');
|
||||
}
|
||||
}
|
||||
|
||||
function onVolumeChange() {
|
||||
self._isFadingOut || (htmlMediaHelper.saveVolume(this.volume), events.trigger(self, "volumechange"))
|
||||
|
||||
if (!self._isFadingOut) {
|
||||
htmlMediaHelper.saveVolume(this.volume);
|
||||
events.trigger(self, 'volumechange');
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaying(e) {
|
||||
self._started || (self._started = !0, this.removeAttribute("controls"), htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks)), events.trigger(self, "playing")
|
||||
|
||||
if (!self._started) {
|
||||
self._started = true;
|
||||
this.removeAttribute('controls');
|
||||
|
||||
htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks);
|
||||
}
|
||||
events.trigger(self, 'playing');
|
||||
}
|
||||
|
||||
function onPlay(e) {
|
||||
events.trigger(self, "unpause")
|
||||
|
||||
events.trigger(self, 'unpause');
|
||||
}
|
||||
|
||||
function onPause() {
|
||||
events.trigger(self, "pause")
|
||||
events.trigger(self, 'pause');
|
||||
}
|
||||
|
||||
function onError() {
|
||||
var errorCode = this.error ? this.error.code || 0 : 0,
|
||||
errorMessage = this.error ? this.error.message || "" : "";
|
||||
console.log("Media element error: " + errorCode.toString() + " " + errorMessage);
|
||||
|
||||
var errorCode = this.error ? (this.error.code || 0) : 0;
|
||||
var errorMessage = this.error ? (this.error.message || '') : '';
|
||||
console.log('Media element error: ' + errorCode.toString() + ' ' + errorMessage);
|
||||
|
||||
var type;
|
||||
|
||||
switch (errorCode) {
|
||||
case 1:
|
||||
// MEDIA_ERR_ABORTED
|
||||
// This will trigger when changing media while something is playing
|
||||
return;
|
||||
case 2:
|
||||
type = "network";
|
||||
// MEDIA_ERR_NETWORK
|
||||
type = 'network';
|
||||
break;
|
||||
case 3:
|
||||
if (self._hlsPlayer) return void htmlMediaHelper.handleHlsJsMediaError(self);
|
||||
type = "mediadecodeerror";
|
||||
// MEDIA_ERR_DECODE
|
||||
if (self._hlsPlayer) {
|
||||
htmlMediaHelper.handleHlsJsMediaError(self);
|
||||
return;
|
||||
} else {
|
||||
type = 'mediadecodeerror';
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
type = "medianotsupported";
|
||||
// MEDIA_ERR_SRC_NOT_SUPPORTED
|
||||
type = 'medianotsupported';
|
||||
break;
|
||||
default:
|
||||
return
|
||||
// seeing cases where Edge is firing error events with no error code
|
||||
// example is start playing something, then immediately change src to something else
|
||||
return;
|
||||
}
|
||||
htmlMediaHelper.onErrorInternal(self, type)
|
||||
}
|
||||
var self = this;
|
||||
self.name = "Html Audio Player", self.type = "mediaplayer", self.id = "htmlaudioplayer", self.priority = 1, self.play = function(options) {
|
||||
return self._started = !1, self._timeUpdated = !1, self._currentTime = null, setCurrentSrc(createMediaElement(), options)
|
||||
}, self.stop = function(destroyPlayer) {
|
||||
cancelFadeTimeout();
|
||||
var elem = self._mediaElement,
|
||||
src = self._currentSrc;
|
||||
if (elem && src) {
|
||||
if (!destroyPlayer || !supportsFade()) return elem.pause(), htmlMediaHelper.onEndedInternal(self, elem, onError), destroyPlayer && self.destroy(), Promise.resolve();
|
||||
var originalVolume = elem.volume;
|
||||
return fade(self, elem, elem.volume).then(function() {
|
||||
elem.pause(), elem.volume = originalVolume, htmlMediaHelper.onEndedInternal(self, elem, onError), destroyPlayer && self.destroy()
|
||||
})
|
||||
}
|
||||
return Promise.resolve()
|
||||
}, self.destroy = function() {
|
||||
unBindEvents(self._mediaElement)
|
||||
|
||||
htmlMediaHelper.onErrorInternal(self, type);
|
||||
}
|
||||
}
|
||||
var fadeTimeout;
|
||||
return HtmlAudioPlayer.prototype.currentSrc = function() {
|
||||
return this._currentSrc
|
||||
}, HtmlAudioPlayer.prototype.canPlayMediaType = function(mediaType) {
|
||||
return "audio" === (mediaType || "").toLowerCase()
|
||||
}, HtmlAudioPlayer.prototype.getDeviceProfile = function(item) {
|
||||
return appHost.getDeviceProfile ? appHost.getDeviceProfile(item) : getDefaultProfile()
|
||||
}, HtmlAudioPlayer.prototype.currentTime = function(val) {
|
||||
|
||||
HtmlAudioPlayer.prototype.currentSrc = function () {
|
||||
return this._currentSrc;
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.canPlayMediaType = function (mediaType) {
|
||||
|
||||
return (mediaType || '').toLowerCase() === 'audio';
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.getDeviceProfile = function (item) {
|
||||
|
||||
if (appHost.getDeviceProfile) {
|
||||
return appHost.getDeviceProfile(item);
|
||||
}
|
||||
|
||||
return getDefaultProfile();
|
||||
};
|
||||
|
||||
// Save this for when playback stops, because querying the time at that point might return 0
|
||||
HtmlAudioPlayer.prototype.currentTime = function (val) {
|
||||
|
||||
var mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
if (null != val) return void(mediaElement.currentTime = val / 1e3);
|
||||
if (val != null) {
|
||||
mediaElement.currentTime = val / 1000;
|
||||
return;
|
||||
}
|
||||
|
||||
var currentTime = this._currentTime;
|
||||
return currentTime ? 1e3 * currentTime : 1e3 * (mediaElement.currentTime || 0)
|
||||
if (currentTime) {
|
||||
return currentTime * 1000;
|
||||
}
|
||||
|
||||
return (mediaElement.currentTime || 0) * 1000;
|
||||
}
|
||||
}, HtmlAudioPlayer.prototype.duration = function(val) {
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.duration = function (val) {
|
||||
|
||||
var mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
var duration = mediaElement.duration;
|
||||
if (htmlMediaHelper.isValidDuration(duration)) return 1e3 * duration
|
||||
if (htmlMediaHelper.isValidDuration(duration)) {
|
||||
return duration * 1000;
|
||||
}
|
||||
}
|
||||
return null
|
||||
}, HtmlAudioPlayer.prototype.seekable = function() {
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.seekable = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
|
||||
var seekable = mediaElement.seekable;
|
||||
if (seekable && seekable.length) {
|
||||
var start = seekable.start(0),
|
||||
end = seekable.end(0);
|
||||
return htmlMediaHelper.isValidDuration(start) || (start = 0), htmlMediaHelper.isValidDuration(end) || (end = 0), end - start > 0
|
||||
|
||||
var start = seekable.start(0);
|
||||
var end = seekable.end(0);
|
||||
|
||||
if (!htmlMediaHelper.isValidDuration(start)) {
|
||||
start = 0;
|
||||
}
|
||||
if (!htmlMediaHelper.isValidDuration(end)) {
|
||||
end = 0;
|
||||
}
|
||||
|
||||
return (end - start) > 0;
|
||||
}
|
||||
return !1
|
||||
|
||||
return false;
|
||||
}
|
||||
}, HtmlAudioPlayer.prototype.getBufferedRanges = function() {
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.getBufferedRanges = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
return mediaElement ? htmlMediaHelper.getBufferedRanges(this, mediaElement) : []
|
||||
}, HtmlAudioPlayer.prototype.pause = function() {
|
||||
if (mediaElement) {
|
||||
|
||||
return htmlMediaHelper.getBufferedRanges(this, mediaElement);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.pause = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
mediaElement && mediaElement.pause()
|
||||
}, HtmlAudioPlayer.prototype.resume = function() {
|
||||
if (mediaElement) {
|
||||
mediaElement.pause();
|
||||
}
|
||||
};
|
||||
|
||||
// This is a retry after error
|
||||
HtmlAudioPlayer.prototype.resume = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
mediaElement && mediaElement.play()
|
||||
}, HtmlAudioPlayer.prototype.unpause = function() {
|
||||
if (mediaElement) {
|
||||
mediaElement.play();
|
||||
}
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.unpause = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
mediaElement && mediaElement.play()
|
||||
}, HtmlAudioPlayer.prototype.paused = function() {
|
||||
if (mediaElement) {
|
||||
mediaElement.play();
|
||||
}
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.paused = function () {
|
||||
|
||||
var mediaElement = this._mediaElement;
|
||||
return !!mediaElement && mediaElement.paused
|
||||
}, HtmlAudioPlayer.prototype.setVolume = function(val) {
|
||||
if (mediaElement) {
|
||||
return mediaElement.paused;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.setVolume = function (val) {
|
||||
var mediaElement = this._mediaElement;
|
||||
mediaElement && (mediaElement.volume = val / 100)
|
||||
}, HtmlAudioPlayer.prototype.getVolume = function() {
|
||||
if (mediaElement) {
|
||||
mediaElement.volume = val / 100;
|
||||
}
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.getVolume = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
if (mediaElement) return Math.min(Math.round(100 * mediaElement.volume), 100)
|
||||
}, HtmlAudioPlayer.prototype.volumeUp = function() {
|
||||
this.setVolume(Math.min(this.getVolume() + 2, 100))
|
||||
}, HtmlAudioPlayer.prototype.volumeDown = function() {
|
||||
this.setVolume(Math.max(this.getVolume() - 2, 0))
|
||||
}, HtmlAudioPlayer.prototype.setMute = function(mute) {
|
||||
if (mediaElement) {
|
||||
|
||||
return Math.min(Math.round(mediaElement.volume * 100), 100);
|
||||
}
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.volumeUp = function () {
|
||||
this.setVolume(Math.min(this.getVolume() + 2, 100));
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.volumeDown = function () {
|
||||
this.setVolume(Math.max(this.getVolume() - 2, 0));
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.setMute = function (mute) {
|
||||
|
||||
var mediaElement = this._mediaElement;
|
||||
mediaElement && (mediaElement.muted = mute)
|
||||
}, HtmlAudioPlayer.prototype.isMuted = function() {
|
||||
if (mediaElement) {
|
||||
mediaElement.muted = mute;
|
||||
}
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.isMuted = function () {
|
||||
var mediaElement = this._mediaElement;
|
||||
return !!mediaElement && mediaElement.muted
|
||||
}, HtmlAudioPlayer.prototype.destroy = function() {}, HtmlAudioPlayer
|
||||
if (mediaElement) {
|
||||
return mediaElement.muted;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
HtmlAudioPlayer.prototype.destroy = function () {
|
||||
|
||||
};
|
||||
|
||||
return HtmlAudioPlayer;
|
||||
});
|
||||
@@ -1,113 +1,254 @@
|
||||
define(["appSettings", "browser", "events"], function(appSettings, browser, events) {
|
||||
"use strict";
|
||||
define(['appSettings', 'browser', 'events'], function (appSettings, browser, events) {
|
||||
'use strict';
|
||||
|
||||
function getSavedVolume() {
|
||||
return appSettings.get("volume") || 1
|
||||
return appSettings.get("volume") || 1;
|
||||
}
|
||||
|
||||
function saveVolume(value) {
|
||||
value && appSettings.set("volume", value)
|
||||
if (value) {
|
||||
appSettings.set("volume", value);
|
||||
}
|
||||
}
|
||||
|
||||
function getCrossOriginValue(mediaSource) {
|
||||
return mediaSource.IsRemote ? null : "anonymous"
|
||||
|
||||
if (mediaSource.IsRemote) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return 'anonymous';
|
||||
}
|
||||
|
||||
function canPlayNativeHls() {
|
||||
var media = document.createElement("video");
|
||||
return !(!media.canPlayType("application/x-mpegURL").replace(/no/, "") && !media.canPlayType("application/vnd.apple.mpegURL").replace(/no/, ""))
|
||||
var media = document.createElement('video');
|
||||
|
||||
if (media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
|
||||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function enableHlsShakaPlayer(item, mediaSource, mediaType) {
|
||||
if (window.MediaSource && MediaSource.isTypeSupported) {
|
||||
|
||||
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
|
||||
|
||||
if (canPlayNativeHls()) {
|
||||
if (browser.edge && "Video" === mediaType) return !0;
|
||||
mediaSource.RunTimeTicks
|
||||
|
||||
if (browser.edge && mediaType === 'Video') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// simple playback should use the native support
|
||||
if (mediaSource.RunTimeTicks) {
|
||||
//if (!browser.edge) {
|
||||
//return false;
|
||||
//}
|
||||
}
|
||||
|
||||
//return false;
|
||||
}
|
||||
return !0
|
||||
|
||||
return true;
|
||||
}
|
||||
return !1
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function enableHlsJsPlayer(runTimeTicks, mediaType) {
|
||||
if (null == window.MediaSource) return !1;
|
||||
if (browser.iOS) return !1;
|
||||
if (browser.tizen || browser.web0s) return !1;
|
||||
if (canPlayNativeHls()) {
|
||||
if (browser.android && "Audio" === mediaType) return !0;
|
||||
if (browser.edge, runTimeTicks) return !1
|
||||
|
||||
if (window.MediaSource == null) {
|
||||
return false;
|
||||
}
|
||||
return !0
|
||||
|
||||
// hls.js is only in beta. needs more testing.
|
||||
if (browser.iOS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The native players on these devices support seeking live streams, no need to use hls.js here
|
||||
if (browser.tizen || browser.web0s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (canPlayNativeHls()) {
|
||||
|
||||
// Having trouble with chrome's native support and transcoded music
|
||||
if (browser.android && mediaType === 'Audio') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.edge && mediaType === 'Video') {
|
||||
//return true;
|
||||
}
|
||||
|
||||
// simple playback should use the native support
|
||||
if (runTimeTicks) {
|
||||
//if (!browser.edge) {
|
||||
return false;
|
||||
//}
|
||||
}
|
||||
|
||||
//return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var recoverDecodingErrorDate, recoverSwapAudioCodecDate;
|
||||
function handleHlsJsMediaError(instance, reject) {
|
||||
|
||||
var hlsPlayer = instance._hlsPlayer;
|
||||
if (hlsPlayer) {
|
||||
var now = Date.now();
|
||||
window.performance && window.performance.now && (now = performance.now()), !recoverDecodingErrorDate || now - recoverDecodingErrorDate > 3e3 ? (recoverDecodingErrorDate = now, console.log("try to recover media Error ..."), hlsPlayer.recoverMediaError()) : !recoverSwapAudioCodecDate || now - recoverSwapAudioCodecDate > 3e3 ? (recoverSwapAudioCodecDate = now, console.log("try to swap Audio Codec and recover media Error ..."), hlsPlayer.swapAudioCodec(), hlsPlayer.recoverMediaError()) : (console.error("cannot recover, last media error recovery failed ..."), reject ? reject() : onErrorInternal(instance, "mediadecodeerror"))
|
||||
|
||||
if (!hlsPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
var now = Date.now();
|
||||
|
||||
if (window.performance && window.performance.now) {
|
||||
now = performance.now();
|
||||
}
|
||||
|
||||
if (!recoverDecodingErrorDate || (now - recoverDecodingErrorDate) > 3000) {
|
||||
recoverDecodingErrorDate = now;
|
||||
console.log('try to recover media Error ...');
|
||||
hlsPlayer.recoverMediaError();
|
||||
} else {
|
||||
if (!recoverSwapAudioCodecDate || (now - recoverSwapAudioCodecDate) > 3000) {
|
||||
recoverSwapAudioCodecDate = now;
|
||||
console.log('try to swap Audio Codec and recover media Error ...');
|
||||
hlsPlayer.swapAudioCodec();
|
||||
hlsPlayer.recoverMediaError();
|
||||
} else {
|
||||
console.error('cannot recover, last media error recovery failed ...');
|
||||
|
||||
if (reject) {
|
||||
reject();
|
||||
} else {
|
||||
onErrorInternal(instance, 'mediadecodeerror');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onErrorInternal(instance, type) {
|
||||
instance.destroyCustomTrack && instance.destroyCustomTrack(instance._mediaElement), events.trigger(instance, "error", [{
|
||||
type: type
|
||||
}])
|
||||
|
||||
// Needed for video
|
||||
if (instance.destroyCustomTrack) {
|
||||
instance.destroyCustomTrack(instance._mediaElement);
|
||||
}
|
||||
|
||||
events.trigger(instance, 'error', [
|
||||
{
|
||||
type: type
|
||||
}]);
|
||||
}
|
||||
|
||||
function isValidDuration(duration) {
|
||||
return !(!duration || isNaN(duration) || duration === Number.POSITIVE_INFINITY || duration === Number.NEGATIVE_INFINITY)
|
||||
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function setCurrentTimeIfNeeded(element, seconds, allowance) {
|
||||
Math.abs((element.currentTime || 0) - seconds) >= allowance && (element.currentTime = seconds)
|
||||
function setCurrentTimeIfNeeded(element, seconds) {
|
||||
|
||||
if (Math.abs(element.currentTime || 0, seconds) <= 1) {
|
||||
element.currentTime = seconds;
|
||||
}
|
||||
}
|
||||
|
||||
function seekOnPlaybackStart(instance, element, ticks) {
|
||||
var seconds = (ticks || 0) / 1e7;
|
||||
|
||||
var seconds = (ticks || 0) / 10000000;
|
||||
|
||||
if (seconds) {
|
||||
(instance.currentSrc() || "").toLowerCase();
|
||||
setCurrentTimeIfNeeded(element, seconds, 5), setTimeout(function() {
|
||||
setCurrentTimeIfNeeded(element, seconds, 10)
|
||||
}, 2500)
|
||||
var src = (instance.currentSrc() || '').toLowerCase();
|
||||
|
||||
// Appending #t=xxx to the query string doesn't seem to work with HLS
|
||||
// For plain video files, not all browsers support it either
|
||||
var delay = browser.safari ? 2500 : 0;
|
||||
if (delay) {
|
||||
setTimeout(function () {
|
||||
setCurrentTimeIfNeeded(element, seconds);
|
||||
}, delay);
|
||||
} else {
|
||||
setCurrentTimeIfNeeded(element, seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applySrc(elem, src, options) {
|
||||
return window.Windows && options.mediaSource && options.mediaSource.IsLocal ? Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function(file) {
|
||||
var playlist = new Windows.Media.Playback.MediaPlaybackList,
|
||||
source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file),
|
||||
startTime = (options.playerStartPositionTicks || 0) / 1e4;
|
||||
return playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime)), elem.src = URL.createObjectURL(playlist, {
|
||||
oneTimeOnly: !0
|
||||
}), Promise.resolve()
|
||||
}) : (elem.src = src, Promise.resolve())
|
||||
|
||||
if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
|
||||
|
||||
return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) {
|
||||
|
||||
var playlist = new Windows.Media.Playback.MediaPlaybackList();
|
||||
|
||||
var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file);
|
||||
var startTime = (options.playerStartPositionTicks || 0) / 10000;
|
||||
playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime));
|
||||
elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true });
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
elem.src = src;
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function onSuccessfulPlay(elem, onErrorFn) {
|
||||
elem.addEventListener("error", onErrorFn)
|
||||
|
||||
elem.addEventListener('error', onErrorFn);
|
||||
}
|
||||
|
||||
function playWithPromise(elem, onErrorFn) {
|
||||
|
||||
try {
|
||||
var promise = elem.play();
|
||||
return promise && promise.then ? promise.catch(function(e) {
|
||||
var errorName = (e.name || "").toLowerCase();
|
||||
return "notallowederror" === errorName || "aborterror" === errorName ? (onSuccessfulPlay(elem, onErrorFn), Promise.resolve()) : Promise.reject()
|
||||
}) : (onSuccessfulPlay(elem, onErrorFn), Promise.resolve())
|
||||
if (promise && promise.then) {
|
||||
// Chrome now returns a promise
|
||||
return promise.catch(function (e) {
|
||||
|
||||
var errorName = (e.name || '').toLowerCase();
|
||||
// safari uses aborterror
|
||||
if (errorName === 'notallowederror' ||
|
||||
errorName === 'aborterror') {
|
||||
// swallow this error because the user can still click the play button on the video element
|
||||
onSuccessfulPlay(elem, onErrorFn);
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject();
|
||||
});
|
||||
} else {
|
||||
onSuccessfulPlay(elem, onErrorFn);
|
||||
return Promise.resolve();
|
||||
}
|
||||
} catch (err) {
|
||||
return console.log("error calling video.play: " + err), Promise.reject()
|
||||
console.log('error calling video.play: ' + err);
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
function destroyCastPlayer(instance) {
|
||||
|
||||
var player = instance._castPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
player.unload()
|
||||
player.unload();
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
console.log(err);
|
||||
}
|
||||
instance._castPlayer = null
|
||||
|
||||
instance._castPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +256,12 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
|
||||
var player = instance._shakaPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
player.destroy()
|
||||
player.destroy();
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
console.log(err);
|
||||
}
|
||||
instance._shakaPlayer = null
|
||||
|
||||
instance._shakaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,11 +269,12 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
|
||||
var player = instance._hlsPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
player.destroy()
|
||||
player.destroy();
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
console.log(err);
|
||||
}
|
||||
instance._hlsPlayer = null
|
||||
|
||||
instance._hlsPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,63 +282,170 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
|
||||
var player = instance._flvPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
player.unload(), player.detachMediaElement(), player.destroy()
|
||||
player.unload();
|
||||
player.detachMediaElement();
|
||||
player.destroy();
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
console.log(err);
|
||||
}
|
||||
instance._flvPlayer = null
|
||||
|
||||
instance._flvPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function() {
|
||||
playWithPromise(elem, onErrorFn).then(resolve, function() {
|
||||
reject && (reject(), reject = null)
|
||||
})
|
||||
}), hls.on(Hls.Events.ERROR, function(event, data) {
|
||||
switch (console.log("HLS Error: Type: " + data.type + " Details: " + (data.details || "") + " Fatal: " + (data.fatal || !1)), data.type) {
|
||||
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||
playWithPromise(elem, onErrorFn).then(resolve, function () {
|
||||
|
||||
if (reject) {
|
||||
reject();
|
||||
reject = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
hls.on(Hls.Events.ERROR, function (event, data) {
|
||||
|
||||
console.log('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false));
|
||||
|
||||
switch (data.type) {
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
if (data.response && data.response.code && data.response.code >= 400) return console.log("hls.js response error code: " + data.response.code), hls.destroy(), void(reject ? (reject("servererror"), reject = null) : onErrorInternal(instance, "servererror"))
|
||||
}
|
||||
if (data.fatal) switch (data.type) {
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
data.response && 0 === data.response.code ? (console.log("hls.js response error code: " + data.response.code), hls.destroy(), reject ? (reject("network"), reject = null) : onErrorInternal(instance, "network")) : (console.log("fatal network error encountered, try to recover"), hls.startLoad());
|
||||
break;
|
||||
case Hls.ErrorTypes.MEDIA_ERROR:
|
||||
console.log("fatal media error encountered, try to recover");
|
||||
var currentReject = reject;
|
||||
reject = null, handleHlsJsMediaError(instance, currentReject);
|
||||
// try to recover network error
|
||||
if (data.response && data.response.code && data.response.code >= 400) {
|
||||
|
||||
console.log('hls.js response error code: ' + data.response.code);
|
||||
|
||||
// Trigger failure differently depending on whether this is prior to start of playback, or after
|
||||
hls.destroy();
|
||||
|
||||
if (reject) {
|
||||
reject('servererror');
|
||||
reject = null;
|
||||
} else {
|
||||
onErrorInternal(instance, 'servererror');
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
console.log("Cannot recover from hls error - destroy and trigger error"), hls.destroy(), reject ? (reject(), reject = null) : onErrorInternal(instance, "mediadecodeerror")
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
if (data.fatal) {
|
||||
switch (data.type) {
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
|
||||
if (data.response && data.response.code === 0) {
|
||||
|
||||
// This could be a CORS error related to access control response headers
|
||||
|
||||
console.log('hls.js response error code: ' + data.response.code);
|
||||
|
||||
// Trigger failure differently depending on whether this is prior to start of playback, or after
|
||||
hls.destroy();
|
||||
|
||||
if (reject) {
|
||||
reject('network');
|
||||
reject = null;
|
||||
} else {
|
||||
onErrorInternal(instance, 'network');
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
console.log("fatal network error encountered, try to recover");
|
||||
hls.startLoad();
|
||||
}
|
||||
|
||||
break;
|
||||
case Hls.ErrorTypes.MEDIA_ERROR:
|
||||
console.log("fatal media error encountered, try to recover");
|
||||
var currentReject = reject;
|
||||
reject = null;
|
||||
handleHlsJsMediaError(instance, currentReject);
|
||||
break;
|
||||
default:
|
||||
|
||||
console.log('Cannot recover from hls error - destroy and trigger error');
|
||||
// cannot recover
|
||||
// Trigger failure differently depending on whether this is prior to start of playback, or after
|
||||
hls.destroy();
|
||||
|
||||
if (reject) {
|
||||
reject();
|
||||
reject = null;
|
||||
} else {
|
||||
onErrorInternal(instance, 'mediadecodeerror');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onEndedInternal(instance, elem, onErrorFn) {
|
||||
elem.removeEventListener("error", onErrorFn), elem.src = "", elem.innerHTML = "", elem.removeAttribute("src"), destroyHlsPlayer(instance), destroyFlvPlayer(instance), destroyShakaPlayer(instance), destroyCastPlayer(instance);
|
||||
|
||||
elem.removeEventListener('error', onErrorFn);
|
||||
|
||||
elem.src = '';
|
||||
elem.innerHTML = '';
|
||||
elem.removeAttribute("src");
|
||||
|
||||
destroyHlsPlayer(instance);
|
||||
destroyFlvPlayer(instance);
|
||||
destroyShakaPlayer(instance);
|
||||
destroyCastPlayer(instance);
|
||||
|
||||
var stopInfo = {
|
||||
src: instance._currentSrc
|
||||
};
|
||||
events.trigger(instance, "stopped", [stopInfo]), instance._currentTime = null, instance._currentSrc = null, instance._currentPlayOptions = null
|
||||
|
||||
events.trigger(instance, 'stopped', [stopInfo]);
|
||||
|
||||
instance._currentTime = null;
|
||||
instance._currentSrc = null;
|
||||
instance._currentPlayOptions = null;
|
||||
}
|
||||
|
||||
function getBufferedRanges(instance, elem) {
|
||||
var offset, ranges = [],
|
||||
seekable = elem.buffered || [],
|
||||
currentPlayOptions = instance._currentPlayOptions;
|
||||
currentPlayOptions && (offset = currentPlayOptions.transcodingOffsetTicks), offset = offset || 0;
|
||||
for (var i = 0, length = seekable.length; i < length; i++) {
|
||||
var start = seekable.start(i),
|
||||
end = seekable.end(i);
|
||||
isValidDuration(start) || (start = 0), isValidDuration(end) ? ranges.push({
|
||||
start: 1e7 * start + offset,
|
||||
end: 1e7 * end + offset
|
||||
}) : end = 0
|
||||
|
||||
var ranges = [];
|
||||
var seekable = elem.buffered || [];
|
||||
|
||||
var offset;
|
||||
var currentPlayOptions = instance._currentPlayOptions;
|
||||
if (currentPlayOptions) {
|
||||
offset = currentPlayOptions.transcodingOffsetTicks;
|
||||
}
|
||||
return ranges
|
||||
|
||||
offset = offset || 0;
|
||||
|
||||
for (var i = 0, length = seekable.length; i < length; i++) {
|
||||
|
||||
var start = seekable.start(i);
|
||||
var end = seekable.end(i);
|
||||
|
||||
if (!isValidDuration(start)) {
|
||||
start = 0;
|
||||
}
|
||||
if (!isValidDuration(end)) {
|
||||
end = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
ranges.push({
|
||||
start: (start * 10000000) + offset,
|
||||
end: (end * 10000000) + offset
|
||||
});
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
var recoverDecodingErrorDate, recoverSwapAudioCodecDate;
|
||||
|
||||
return {
|
||||
getSavedVolume: getSavedVolume,
|
||||
saveVolume: saveVolume,
|
||||
@@ -214,5 +464,5 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
|
||||
onEndedInternal: onEndedInternal,
|
||||
getCrossOriginValue: getCrossOriginValue,
|
||||
getBufferedRanges: getBufferedRanges
|
||||
}
|
||||
};
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,47 +4,43 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.videoPlayerContainer:not(.videoPlayerContainer-withBackdrop) {
|
||||
background: #000 !important
|
||||
}
|
||||
.videoPlayerContainer:not(.videoPlayerContainer-withBackdrop) {
|
||||
background: #000 !important;
|
||||
}
|
||||
|
||||
.videoPlayerContainer-withBackdrop {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-webkit-background-size: cover;
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
background-color: #000
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.videoPlayerContainer-onTop {
|
||||
z-index: 1000
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.htmlvideoplayer {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
width: 100%;
|
||||
height: 100%
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.htmlvideoplayer::cue {
|
||||
background-color: transparent;
|
||||
text-shadow: .14em .14em .14em rgba(0, 0, 0, 1);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: inherit
|
||||
}
|
||||
.htmlvideoplayer::cue {
|
||||
background-color: transparent;
|
||||
text-shadow: .14em .14em .14em rgba(0, 0, 0, 1);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.htmlvideoplayer-moveupsubtitles::-webkit-media-text-track-display {
|
||||
margin-top: -2em
|
||||
/*Style the text itself*/
|
||||
margin-top: -2em;
|
||||
}
|
||||
|
||||
.videoSubtitles {
|
||||
@@ -54,41 +50,25 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
color: #fff;
|
||||
font-size: 170%
|
||||
font-size: 170%;
|
||||
}
|
||||
|
||||
.videoSubtitlesInner {
|
||||
max-width: 70%;
|
||||
background-color: rgba(0, 0, 0, .8);
|
||||
background-color: rgba(0,0,0,.8);
|
||||
padding: .25em;
|
||||
margin: auto;
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
@-webkit-keyframes htmlvideoplayer-zoomin {
|
||||
from {
|
||||
-webkit-transform: scale3d(.2, .2, .2);
|
||||
transform: scale3d(.2, .2, .2);
|
||||
opacity: .6
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
opacity: initial
|
||||
}
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@keyframes htmlvideoplayer-zoomin {
|
||||
from {
|
||||
-webkit-transform: scale3d(.2, .2, .2);
|
||||
transform: scale3d(.2, .2, .2);
|
||||
opacity: .6
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
opacity: initial
|
||||
opacity: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,126 +1,416 @@
|
||||
define(["loading", "apphost", "dialogHelper", "connectionManager", "imageLoader", "browser", "layoutManager", "scrollHelper", "globalize", "require", "emby-checkbox", "emby-button", "paper-icon-button-light", "emby-linkbutton", "formDialogStyle", "cardStyle"], function(loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) {
|
||||
"use strict";
|
||||
define(['loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader', 'browser', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'emby-checkbox', 'emby-button', 'paper-icon-button-light', 'emby-linkbutton', 'formDialogStyle', 'cardStyle'], function (loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) {
|
||||
'use strict';
|
||||
|
||||
var currentItemId;
|
||||
var currentItemType;
|
||||
var currentResolve;
|
||||
var currentReject;
|
||||
var hasChanges = false;
|
||||
|
||||
// These images can be large and we're seeing memory problems in safari
|
||||
var browsableImagePageSize = browser.slow ? 6 : 30;
|
||||
|
||||
var browsableImageStartIndex = 0;
|
||||
var browsableImageType = 'Primary';
|
||||
var selectedProvider;
|
||||
|
||||
function getBaseRemoteOptions() {
|
||||
|
||||
var options = {};
|
||||
return options.itemId = currentItemId, options
|
||||
|
||||
options.itemId = currentItemId;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function reloadBrowsableImages(page, apiClient) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var options = getBaseRemoteOptions();
|
||||
options.type = browsableImageType, options.startIndex = browsableImageStartIndex, options.limit = browsableImagePageSize, options.IncludeAllLanguages = page.querySelector("#chkAllLanguages").checked;
|
||||
var provider = selectedProvider || "";
|
||||
provider && (options.ProviderName = provider), apiClient.getAvailableRemoteImages(options).then(function(result) {
|
||||
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit), page.querySelector("#selectBrowsableImageType").value = browsableImageType;
|
||||
var providersHtml = result.Providers.map(function(p) {
|
||||
return '<option value="' + p + '">' + p + "</option>"
|
||||
}),
|
||||
selectImageProvider = page.querySelector("#selectImageProvider");
|
||||
selectImageProvider.innerHTML = '<option value="">' + globalize.translate("sharedcomponents#All") + "</option>" + providersHtml, selectImageProvider.value = provider, loading.hide()
|
||||
})
|
||||
|
||||
options.type = browsableImageType;
|
||||
options.startIndex = browsableImageStartIndex;
|
||||
options.limit = browsableImagePageSize;
|
||||
options.IncludeAllLanguages = page.querySelector('#chkAllLanguages').checked;
|
||||
|
||||
var provider = selectedProvider || '';
|
||||
|
||||
if (provider) {
|
||||
options.ProviderName = provider;
|
||||
}
|
||||
|
||||
apiClient.getAvailableRemoteImages(options).then(function (result) {
|
||||
|
||||
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit);
|
||||
|
||||
page.querySelector('#selectBrowsableImageType').value = browsableImageType;
|
||||
|
||||
var providersHtml = result.Providers.map(function (p) {
|
||||
return '<option value="' + p + '">' + p + '</option>';
|
||||
});
|
||||
|
||||
var selectImageProvider = page.querySelector('#selectImageProvider');
|
||||
selectImageProvider.innerHTML = '<option value="">' + globalize.translate('sharedcomponents#All') + '</option>' + providersHtml;
|
||||
selectImageProvider.value = provider;
|
||||
|
||||
loading.hide();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function renderRemoteImages(page, apiClient, imagesResult, imageType, startIndex, limit) {
|
||||
page.querySelector(".availableImagesPaging").innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
|
||||
for (var html = "", i = 0, length = imagesResult.Images.length; i < length; i++) html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
|
||||
var availableImagesList = page.querySelector(".availableImagesList");
|
||||
availableImagesList.innerHTML = html, imageLoader.lazyChildren(availableImagesList);
|
||||
var btnNextPage = page.querySelector(".btnNextPage"),
|
||||
btnPreviousPage = page.querySelector(".btnPreviousPage");
|
||||
btnNextPage && btnNextPage.addEventListener("click", function() {
|
||||
browsableImageStartIndex += browsableImagePageSize, reloadBrowsableImages(page, apiClient)
|
||||
}), btnPreviousPage && btnPreviousPage.addEventListener("click", function() {
|
||||
browsableImageStartIndex -= browsableImagePageSize, reloadBrowsableImages(page, apiClient)
|
||||
})
|
||||
|
||||
page.querySelector('.availableImagesPaging').innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
|
||||
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = imagesResult.Images.length; i < length; i++) {
|
||||
|
||||
html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
|
||||
}
|
||||
|
||||
var availableImagesList = page.querySelector('.availableImagesList');
|
||||
availableImagesList.innerHTML = html;
|
||||
imageLoader.lazyChildren(availableImagesList);
|
||||
|
||||
var btnNextPage = page.querySelector('.btnNextPage');
|
||||
var btnPreviousPage = page.querySelector('.btnPreviousPage');
|
||||
|
||||
if (btnNextPage) {
|
||||
btnNextPage.addEventListener('click', function () {
|
||||
browsableImageStartIndex += browsableImagePageSize;
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
if (btnPreviousPage) {
|
||||
btnPreviousPage.addEventListener('click', function () {
|
||||
browsableImageStartIndex -= browsableImagePageSize;
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getPagingHtml(startIndex, limit, totalRecordCount) {
|
||||
var html = "",
|
||||
recordsEnd = Math.min(startIndex + limit, totalRecordCount),
|
||||
showControls = totalRecordCount > limit;
|
||||
return html += '<div class="listPaging">', html += '<span style="margin-right: 10px;">', html += (totalRecordCount ? startIndex + 1 : 0) + "-" + recordsEnd + " of " + totalRecordCount, html += "</span>", showControls && (html += '<div data-role="controlgroup" data-type="horizontal" style="display:inline-block;">', html += '<button is="paper-icon-button-light" title="' + globalize.translate("sharedcomponents#Previous") + '" class="btnPreviousPage autoSize" ' + (startIndex ? "" : "disabled") + '><i class="md-icon"></i></button>', html += '<button is="paper-icon-button-light" title="' + globalize.translate("sharedcomponents#Next") + '" class="btnNextPage autoSize" ' + (startIndex + limit >= totalRecordCount ? "disabled" : "") + '><i class="md-icon">arrow_forward</i></button>', html += "</div>"), html += "</div>"
|
||||
|
||||
var html = '';
|
||||
|
||||
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
|
||||
// 20 is the minimum page size
|
||||
var showControls = totalRecordCount > limit;
|
||||
|
||||
html += '<div class="listPaging">';
|
||||
|
||||
html += '<span style="margin-right: 10px;">';
|
||||
|
||||
var startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
|
||||
html += startAtDisplay + '-' + recordsEnd + ' of ' + totalRecordCount;
|
||||
|
||||
html += '</span>';
|
||||
|
||||
if (showControls) {
|
||||
html += '<div data-role="controlgroup" data-type="horizontal" style="display:inline-block;">';
|
||||
|
||||
html += '<button is="paper-icon-button-light" title="' + globalize.translate('sharedcomponents#Previous') + '" class="btnPreviousPage autoSize" ' + (startIndex ? '' : 'disabled') + '><i class="md-icon"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" title="' + globalize.translate('sharedcomponents#Next') + '" class="btnNextPage autoSize" ' + (startIndex + limit >= totalRecordCount ? 'disabled' : '') + '><i class="md-icon">arrow_forward</i></button>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function parentWithClass(elem, className) {
|
||||
for (; !elem.classList || !elem.classList.contains(className);)
|
||||
if (!(elem = elem.parentNode)) return null;
|
||||
return elem
|
||||
|
||||
while (!elem.classList || !elem.classList.contains(className)) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function downloadRemoteImage(page, apiClient, url, type, provider) {
|
||||
|
||||
var options = getBaseRemoteOptions();
|
||||
options.Type = type, options.ImageUrl = url, options.ProviderName = provider, loading.show(), apiClient.downloadRemoteImage(options).then(function() {
|
||||
hasChanges = !0;
|
||||
var dlg = parentWithClass(page, "dialog");
|
||||
dialogHelper.close(dlg)
|
||||
})
|
||||
|
||||
options.Type = type;
|
||||
options.ImageUrl = url;
|
||||
options.ProviderName = provider;
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.downloadRemoteImage(options).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
var dlg = parentWithClass(page, 'dialog');
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
||||
function getDisplayUrl(url, apiClient) {
|
||||
return apiClient.getUrl("Images/Remote", {
|
||||
imageUrl: url
|
||||
})
|
||||
return apiClient.getUrl("Images/Remote", { imageUrl: url });
|
||||
}
|
||||
|
||||
function getRemoteImageHtml(image, imageType, apiClient) {
|
||||
var tagName = layoutManager.tv ? "button" : "div",
|
||||
enableFooterButtons = !layoutManager.tv,
|
||||
html = "",
|
||||
cssClass = "card scalableCard imageEditorCard",
|
||||
cardBoxCssClass = "cardBox visualCardBox",
|
||||
shape = "backdrop";
|
||||
return shape = "Backdrop" === imageType || "Art" === imageType || "Thumb" === imageType || "Logo" === imageType ? "backdrop" : "Banner" === imageType ? "banner" : "Disc" === imageType ? "square" : "Episode" === currentItemType ? "backdrop" : "MusicAlbum" === currentItemType || "MusicArtist" === currentItemType ? "square" : "portrait", cssClass += " " + shape + "Card " + shape + "Card-scalable", "button" === tagName ? (cssClass += " btnImageCard", layoutManager.tv && !browser.slow && (cardBoxCssClass += " cardBox-focustransform"), layoutManager.tv && (cardBoxCssClass += " card-focuscontent cardBox-withfocuscontent"), html += '<button type="button" class="' + cssClass + '"') : html += '<div class="' + cssClass + '"', html += ' data-imageprovider="' + image.ProviderName + '" data-imageurl="' + image.Url + '" data-imagetype="' + image.Type + '"', html += ">", html += '<div class="' + cardBoxCssClass + '">', html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">', html += '<div class="cardPadder-' + shape + '"></div>', html += '<div class="cardContent">', layoutManager.tv || !appHost.supports("externallinks") ? html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></div>' : html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></a>', html += "</div>", html += "</div>", html += '<div class="cardFooter visualCardBox-cardFooter">', html += '<div class="cardText cardTextCentered">' + image.ProviderName + "</div>", (image.Width || image.Height || image.Language) && (html += '<div class="cardText cardText-secondary cardTextCentered">', image.Width && image.Height ? (html += image.Width + " x " + image.Height, image.Language && (html += " • " + image.Language)) : image.Language && (html += image.Language), html += "</div>"), null != image.CommunityRating && (html += '<div class="cardText cardText-secondary cardTextCentered">', "Likes" === image.RatingType ? html += image.CommunityRating + (1 === image.CommunityRating ? " like" : " likes") : image.CommunityRating ? (html += image.CommunityRating.toFixed(1), image.VoteCount && (html += " • " + image.VoteCount + (1 === image.VoteCount ? " vote" : " votes"))) : html += "Unrated", html += "</div>"), enableFooterButtons && (html += '<div class="cardText cardTextCentered">', html += '<button is="paper-icon-button-light" class="btnDownloadRemoteImage autoSize" raised" title="' + globalize.translate("sharedcomponents#Download") + '"><i class="md-icon"></i></button>', html += "</div>"), html += "</div>", html += "</div>", html += "</" + tagName + ">"
|
||||
|
||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
||||
var enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
var html = '';
|
||||
|
||||
var cssClass = "card scalableCard imageEditorCard";
|
||||
var cardBoxCssClass = 'cardBox visualCardBox';
|
||||
|
||||
var shape = 'backdrop';
|
||||
if (imageType === "Backdrop" || imageType === "Art" || imageType === "Thumb" || imageType === "Logo") {
|
||||
shape = 'backdrop';
|
||||
}
|
||||
else if (imageType === "Banner") {
|
||||
shape = 'banner';
|
||||
}
|
||||
else if (imageType === "Disc") {
|
||||
shape = 'square';
|
||||
}
|
||||
else {
|
||||
|
||||
if (currentItemType === "Episode") {
|
||||
shape = 'backdrop';
|
||||
}
|
||||
else if (currentItemType === "MusicAlbum" || currentItemType === "MusicArtist") {
|
||||
shape = 'square';
|
||||
}
|
||||
else {
|
||||
shape = 'portrait';
|
||||
}
|
||||
}
|
||||
|
||||
cssClass += ' ' + shape + 'Card ' + shape + 'Card-scalable';
|
||||
if (tagName === 'button') {
|
||||
cssClass += ' btnImageCard';
|
||||
|
||||
if (layoutManager.tv && !browser.slow) {
|
||||
cardBoxCssClass += ' cardBox-focustransform';
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
cardBoxCssClass += ' card-focuscontent cardBox-withfocuscontent';
|
||||
}
|
||||
|
||||
html += '<button type="button" class="' + cssClass + '"';
|
||||
} else {
|
||||
html += '<div class="' + cssClass + '"';
|
||||
}
|
||||
|
||||
html += ' data-imageprovider="' + image.ProviderName + '" data-imageurl="' + image.Url + '" data-imagetype="' + image.Type + '"';
|
||||
|
||||
html += '>';
|
||||
|
||||
html += '<div class="' + cardBoxCssClass + '">';
|
||||
html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">';
|
||||
html += '<div class="cardPadder-' + shape + '"></div>';
|
||||
html += '<div class="cardContent">';
|
||||
|
||||
if (layoutManager.tv || !appHost.supports('externallinks')) {
|
||||
html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></div>';
|
||||
}
|
||||
else {
|
||||
html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></a>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
// begin footer
|
||||
html += '<div class="cardFooter visualCardBox-cardFooter">';
|
||||
|
||||
html += '<div class="cardText cardTextCentered">' + image.ProviderName + '</div>';
|
||||
|
||||
if (image.Width || image.Height || image.Language) {
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
|
||||
if (image.Width && image.Height) {
|
||||
html += image.Width + ' x ' + image.Height;
|
||||
|
||||
if (image.Language) {
|
||||
|
||||
html += ' • ' + image.Language;
|
||||
}
|
||||
} else {
|
||||
if (image.Language) {
|
||||
|
||||
html += image.Language;
|
||||
}
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
if (image.CommunityRating != null) {
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
|
||||
if (image.RatingType === "Likes") {
|
||||
html += image.CommunityRating + (image.CommunityRating === 1 ? " like" : " likes");
|
||||
} else {
|
||||
|
||||
if (image.CommunityRating) {
|
||||
html += image.CommunityRating.toFixed(1);
|
||||
|
||||
if (image.VoteCount) {
|
||||
html += ' • ' + image.VoteCount + (image.VoteCount === 1 ? " vote" : " votes");
|
||||
}
|
||||
} else {
|
||||
html += "Unrated";
|
||||
}
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
if (enableFooterButtons) {
|
||||
html += '<div class="cardText cardTextCentered">';
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="btnDownloadRemoteImage autoSize" raised" title="' + globalize.translate('sharedcomponents#Download') + '"><i class="md-icon"></i></button>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
// end footer
|
||||
|
||||
html += '</div>';
|
||||
//html += '</div>';
|
||||
|
||||
html += '</' + tagName + '>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function initEditor(page, apiClient) {
|
||||
page.querySelector("#selectBrowsableImageType").addEventListener("change", function() {
|
||||
browsableImageType = this.value, browsableImageStartIndex = 0, selectedProvider = null, reloadBrowsableImages(page, apiClient)
|
||||
}), page.querySelector("#selectImageProvider").addEventListener("change", function() {
|
||||
browsableImageStartIndex = 0, selectedProvider = this.value, reloadBrowsableImages(page, apiClient)
|
||||
}), page.querySelector("#chkAllLanguages").addEventListener("change", function() {
|
||||
browsableImageStartIndex = 0, reloadBrowsableImages(page, apiClient)
|
||||
}), page.addEventListener("click", function(e) {
|
||||
var btnDownloadRemoteImage = parentWithClass(e.target, "btnDownloadRemoteImage");
|
||||
|
||||
page.querySelector('#selectBrowsableImageType').addEventListener('change', function () {
|
||||
browsableImageType = this.value;
|
||||
browsableImageStartIndex = 0;
|
||||
selectedProvider = null;
|
||||
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
|
||||
page.querySelector('#selectImageProvider').addEventListener('change', function () {
|
||||
|
||||
browsableImageStartIndex = 0;
|
||||
selectedProvider = this.value;
|
||||
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
|
||||
page.querySelector('#chkAllLanguages').addEventListener('change', function () {
|
||||
|
||||
browsableImageStartIndex = 0;
|
||||
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
|
||||
page.addEventListener('click', function (e) {
|
||||
|
||||
var btnDownloadRemoteImage = parentWithClass(e.target, 'btnDownloadRemoteImage');
|
||||
if (btnDownloadRemoteImage) {
|
||||
var card = parentWithClass(btnDownloadRemoteImage, "card");
|
||||
return void downloadRemoteImage(page, apiClient, card.getAttribute("data-imageurl"), card.getAttribute("data-imagetype"), card.getAttribute("data-imageprovider"))
|
||||
var card = parentWithClass(btnDownloadRemoteImage, 'card');
|
||||
downloadRemoteImage(page, apiClient, card.getAttribute('data-imageurl'), card.getAttribute('data-imagetype'), card.getAttribute('data-imageprovider'));
|
||||
return;
|
||||
}
|
||||
var btnImageCard = parentWithClass(e.target, "btnImageCard");
|
||||
btnImageCard && downloadRemoteImage(page, apiClient, btnImageCard.getAttribute("data-imageurl"), btnImageCard.getAttribute("data-imagetype"), btnImageCard.getAttribute("data-imageprovider"))
|
||||
})
|
||||
|
||||
var btnImageCard = parentWithClass(e.target, 'btnImageCard');
|
||||
if (btnImageCard) {
|
||||
downloadRemoteImage(page, apiClient, btnImageCard.getAttribute('data-imageurl'), btnImageCard.getAttribute('data-imagetype'), btnImageCard.getAttribute('data-imageprovider'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(itemId, serverId, itemType) {
|
||||
loading.show(), require(["text!./imagedownloader.template.html"], function(template) {
|
||||
|
||||
loading.show();
|
||||
|
||||
require(['text!./imagedownloader.template.html'], function (template) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
currentItemId = itemId, currentItemType = itemType;
|
||||
|
||||
currentItemId = itemId;
|
||||
currentItemType = itemType;
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: !0
|
||||
removeOnClose: true
|
||||
};
|
||||
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "fullscreen-border";
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'fullscreen-border';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), layoutManager.tv && scrollHelper.centerFocus.on(dlg, !1), dlg.addEventListener("close", onDialogClosed), dialogHelper.open(dlg);
|
||||
var editorContent = dlg.querySelector(".formDialogContent");
|
||||
initEditor(editorContent, apiClient), dlg.querySelector(".btnCancel").addEventListener("click", function() {
|
||||
dialogHelper.close(dlg)
|
||||
}), reloadBrowsableImages(editorContent, apiClient)
|
||||
})
|
||||
|
||||
dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg, false);
|
||||
}
|
||||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
var editorContent = dlg.querySelector('.formDialogContent');
|
||||
initEditor(editorContent, apiClient);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
reloadBrowsableImages(editorContent, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
|
||||
var dlg = this;
|
||||
layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), hasChanges ? currentResolve() : currentReject()
|
||||
}
|
||||
var currentItemId, currentItemType, currentResolve, currentReject, selectedProvider, hasChanges = !1,
|
||||
browsableImagePageSize = browser.slow ? 6 : 30,
|
||||
browsableImageStartIndex = 0,
|
||||
browsableImageType = "Primary";
|
||||
return {
|
||||
show: function(itemId, serverId, itemType, imageType) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
currentResolve = resolve, currentReject = reject, hasChanges = !1, browsableImageStartIndex = 0, browsableImageType = imageType || "Primary", selectedProvider = null, showEditor(itemId, serverId, itemType)
|
||||
})
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
|
||||
loading.hide();
|
||||
if (hasChanges) {
|
||||
currentResolve();
|
||||
} else {
|
||||
currentReject();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (itemId, serverId, itemType, imageType) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
hasChanges = false;
|
||||
browsableImageStartIndex = 0;
|
||||
browsableImageType = imageType || 'Primary';
|
||||
selectedProvider = null;
|
||||
|
||||
showEditor(itemId, serverId, itemType);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,13 +1,9 @@
|
||||
.imageEditor-buttons {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
.imageEditor-buttons {
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
margin: 1em 0
|
||||
margin: 1em 0 1em;
|
||||
}
|
||||
|
||||
.first-imageEditor-buttons {
|
||||
margin-top: 2em
|
||||
margin-top: 2em;
|
||||
}
|
||||
@@ -1,220 +1,513 @@
|
||||
define(["dialogHelper", "connectionManager", "loading", "dom", "layoutManager", "focusManager", "globalize", "scrollHelper", "imageLoader", "require", "browser", "apphost", "cardStyle", "formDialogStyle", "emby-button", "paper-icon-button-light", "css!./imageeditor"], function(dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) {
|
||||
"use strict";
|
||||
define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', 'focusManager', 'globalize', 'scrollHelper', 'imageLoader', 'require', 'browser', 'apphost', 'cardStyle', 'formDialogStyle', 'emby-button', 'paper-icon-button-light', 'css!./imageeditor'], function (dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) {
|
||||
'use strict';
|
||||
|
||||
var currentItem;
|
||||
var hasChanges = false;
|
||||
|
||||
function getBaseRemoteOptions() {
|
||||
|
||||
var options = {};
|
||||
return options.itemId = currentItem.Id, options
|
||||
|
||||
options.itemId = currentItem.Id;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function reload(page, item, focusContext) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var apiClient;
|
||||
item ? (apiClient = connectionManager.getApiClient(item.ServerId), reloadItem(page, item, apiClient, focusContext)) : (apiClient = connectionManager.getApiClient(currentItem.ServerId), apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function(item) {
|
||||
reloadItem(page, item, apiClient, focusContext)
|
||||
}))
|
||||
|
||||
if (item) {
|
||||
apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
reloadItem(page, item, apiClient, focusContext);
|
||||
}
|
||||
else {
|
||||
|
||||
apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function (item) {
|
||||
reloadItem(page, item, apiClient, focusContext);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addListeners(container, className, eventName, fn) {
|
||||
container.addEventListener(eventName, function(e) {
|
||||
|
||||
container.addEventListener(eventName, function (e) {
|
||||
var elem = dom.parentWithClass(e.target, className);
|
||||
elem && fn.call(elem, e)
|
||||
})
|
||||
if (elem) {
|
||||
fn.call(elem, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function reloadItem(page, item, apiClient, focusContext) {
|
||||
currentItem = item, apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function(providers) {
|
||||
for (var btnBrowseAllImages = page.querySelectorAll(".btnBrowseAllImages"), i = 0, length = btnBrowseAllImages.length; i < length; i++) providers.length ? btnBrowseAllImages[i].classList.remove("hide") : btnBrowseAllImages[i].classList.add("hide");
|
||||
apiClient.getItemImageInfos(currentItem.Id).then(function(imageInfos) {
|
||||
renderStandardImages(page, apiClient, item, imageInfos, providers), renderBackdrops(page, apiClient, item, imageInfos, providers), renderScreenshots(page, apiClient, item, imageInfos, providers), loading.hide(), layoutManager.tv && focusManager.autoFocus(focusContext || page)
|
||||
})
|
||||
})
|
||||
|
||||
currentItem = item;
|
||||
|
||||
apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) {
|
||||
|
||||
var btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages');
|
||||
for (var i = 0, length = btnBrowseAllImages.length; i < length; i++) {
|
||||
|
||||
if (providers.length) {
|
||||
btnBrowseAllImages[i].classList.remove('hide');
|
||||
} else {
|
||||
btnBrowseAllImages[i].classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
apiClient.getItemImageInfos(currentItem.Id).then(function (imageInfos) {
|
||||
|
||||
renderStandardImages(page, apiClient, item, imageInfos, providers);
|
||||
renderBackdrops(page, apiClient, item, imageInfos, providers);
|
||||
renderScreenshots(page, apiClient, item, imageInfos, providers);
|
||||
loading.hide();
|
||||
|
||||
if (layoutManager.tv) {
|
||||
focusManager.autoFocus((focusContext || page));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getImageUrl(item, apiClient, type, index, options) {
|
||||
return options = options || {}, options.type = type, options.index = index, options.tag = "Backdrop" === type ? item.BackdropImageTags[index] : "Screenshot" === type ? item.ScreenshotImageTags[index] : "Primary" === type ? item.PrimaryImageTag || item.ImageTags[type] : item.ImageTags[type], apiClient.getScaledImageUrl(item.Id || item.ItemId, options)
|
||||
|
||||
options = options || {};
|
||||
options.type = type;
|
||||
options.index = index;
|
||||
|
||||
if (type === 'Backdrop') {
|
||||
options.tag = item.BackdropImageTags[index];
|
||||
} else if (type === 'Screenshot') {
|
||||
options.tag = item.ScreenshotImageTags[index];
|
||||
} else if (type === 'Primary') {
|
||||
options.tag = item.PrimaryImageTag || item.ImageTags[type];
|
||||
} else {
|
||||
options.tag = item.ImageTags[type];
|
||||
}
|
||||
|
||||
// For search hints
|
||||
return apiClient.getScaledImageUrl(item.Id || item.ItemId, options);
|
||||
}
|
||||
|
||||
function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
|
||||
var html = "",
|
||||
cssClass = "card scalableCard imageEditorCard",
|
||||
cardBoxCssClass = "cardBox visualCardBox";
|
||||
return cssClass += " backdropCard backdropCard-scalable", "button" === tagName ? (cssClass += " btnImageCard", layoutManager.tv && !browser.slow && (cardBoxCssClass += " cardBox-focustransform"), layoutManager.tv && (cardBoxCssClass += " card-focuscontent cardBox-withfocuscontent"), html += '<button type="button" class="' + cssClass + '"') : html += '<div class="' + cssClass + '"', html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + index + '" data-numimages="' + numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + imageProviders.length + '"', html += ">", html += '<div class="' + cardBoxCssClass + '">', html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">', html += '<div class="cardPadder-backdrop"></div>', html += '<div class="cardContent">', html += '<div class="cardImageContainer" style="background-image:url(\'' + getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, {
|
||||
maxWidth: imageSize
|
||||
}) + "');background-position:center bottom;\"></div>", html += "</div>", html += "</div>", html += '<div class="cardFooter visualCardBox-cardFooter">', html += '<h3 class="cardText cardTextCentered" style="margin:0;">' + globalize.translate("sharedcomponents#" + image.ImageType) + "</h3>", html += '<div class="cardText cardText-secondary cardTextCentered">', image.Width && image.Height ? html += image.Width + " X " + image.Height : html += " ", html += "</div>", enableFooterButtons && (html += '<div class="cardText cardTextCentered">', "Backdrop" === image.ImageType || "Screenshot" === image.ImageType ? (html += index > 0 ? '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate("sharedcomponents#MoveLeft") + '"><i class="md-icon">chevron_left</i></button>' : '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate("sharedcomponents#MoveLeft") + '"><i class="md-icon">chevron_left</i></button>', html += index < numImages - 1 ? '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex + 1) + '" title="' + globalize.translate("sharedcomponents#MoveRight") + '"><i class="md-icon">chevron_right</i></button>' : '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate("sharedcomponents#MoveRight") + '"><i class="md-icon">chevron_right</i></button>') : imageProviders.length && (html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" class="btnSearchImages autoSize" title="' + globalize.translate("sharedcomponents#Search") + '"><i class="md-icon">search</i></button>'), html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" data-index="' + (null != image.ImageIndex ? image.ImageIndex : "null") + '" class="btnDeleteImage autoSize" title="' + globalize.translate("sharedcomponents#Delete") + '"><i class="md-icon">delete</i></button>', html += "</div>"), html += "</div>", html += "</div>", html += "</" + tagName + ">"
|
||||
|
||||
var html = '';
|
||||
|
||||
var cssClass = "card scalableCard imageEditorCard";
|
||||
var cardBoxCssClass = 'cardBox visualCardBox';
|
||||
|
||||
cssClass += " backdropCard backdropCard-scalable";
|
||||
|
||||
if (tagName === 'button') {
|
||||
cssClass += ' btnImageCard';
|
||||
|
||||
if (layoutManager.tv && !browser.slow) {
|
||||
cardBoxCssClass += ' cardBox-focustransform';
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
cardBoxCssClass += ' card-focuscontent cardBox-withfocuscontent';
|
||||
}
|
||||
|
||||
html += '<button type="button" class="' + cssClass + '"';
|
||||
} else {
|
||||
html += '<div class="' + cssClass + '"';
|
||||
}
|
||||
|
||||
html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + index + '" data-numimages="' + numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + imageProviders.length + '"';
|
||||
|
||||
html += '>';
|
||||
|
||||
html += '<div class="' + cardBoxCssClass + '">';
|
||||
html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">';
|
||||
html += '<div class="cardPadder-backdrop"></div>';
|
||||
|
||||
html += '<div class="cardContent">';
|
||||
|
||||
var imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
|
||||
|
||||
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center bottom;"></div>';
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="cardFooter visualCardBox-cardFooter">';
|
||||
|
||||
html += '<h3 class="cardText cardTextCentered" style="margin:0;">' + globalize.translate('sharedcomponents#' + image.ImageType) + '</h3>';
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
if (image.Width && image.Height) {
|
||||
html += image.Width + ' X ' + image.Height;
|
||||
} else {
|
||||
html += ' ';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
if (enableFooterButtons) {
|
||||
html += '<div class="cardText cardTextCentered">';
|
||||
|
||||
if (image.ImageType === "Backdrop" || image.ImageType === "Screenshot") {
|
||||
|
||||
if (index > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate('sharedcomponents#MoveLeft') + '"><i class="md-icon">chevron_left</i></button>';
|
||||
} else {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('sharedcomponents#MoveLeft') + '"><i class="md-icon">chevron_left</i></button>';
|
||||
}
|
||||
|
||||
if (index < numImages - 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex + 1) + '" title="' + globalize.translate('sharedcomponents#MoveRight') + '"><i class="md-icon">chevron_right</i></button>';
|
||||
} else {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('sharedcomponents#MoveRight') + '"><i class="md-icon">chevron_right</i></button>';
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (imageProviders.length) {
|
||||
html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" class="btnSearchImages autoSize" title="' + globalize.translate('sharedcomponents#Search') + '"><i class="md-icon">search</i></button>';
|
||||
}
|
||||
}
|
||||
|
||||
html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" data-index="' + (image.ImageIndex != null ? image.ImageIndex : "null") + '" class="btnDeleteImage autoSize" title="' + globalize.translate('sharedcomponents#Delete') + '"><i class="md-icon">delete</i></button>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</' + tagName + '>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function deleteImage(context, itemId, type, index, apiClient, enableConfirmation) {
|
||||
var afterConfirm = function() {
|
||||
apiClient.deleteItemImage(itemId, type, index).then(function() {
|
||||
hasChanges = !0, reload(context)
|
||||
})
|
||||
|
||||
var afterConfirm = function () {
|
||||
apiClient.deleteItemImage(itemId, type, index).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(context);
|
||||
|
||||
});
|
||||
};
|
||||
if (!enableConfirmation) return void afterConfirm();
|
||||
require(["confirm"], function(confirm) {
|
||||
|
||||
if (!enableConfirmation) {
|
||||
afterConfirm();
|
||||
return;
|
||||
}
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm({
|
||||
text: globalize.translate("sharedcomponents#ConfirmDeleteImage"),
|
||||
confirmText: globalize.translate("sharedcomponents#Delete"),
|
||||
primary: "cancel"
|
||||
}).then(afterConfirm)
|
||||
})
|
||||
|
||||
text: globalize.translate('sharedcomponents#ConfirmDeleteImage'),
|
||||
confirmText: globalize.translate('sharedcomponents#Delete'),
|
||||
primary: 'cancel'
|
||||
|
||||
}).then(afterConfirm);
|
||||
});
|
||||
}
|
||||
|
||||
function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) {
|
||||
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function() {
|
||||
hasChanges = !0, reload(context, null, focusContext)
|
||||
}, function() {
|
||||
require(["alert"], function(alert) {
|
||||
alert(globalize.translate("sharedcomponents#DefaultErrorMessage"))
|
||||
})
|
||||
})
|
||||
|
||||
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(context, null, focusContext);
|
||||
}, function () {
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
alert(globalize.translate('sharedcomponents#DefaultErrorMessage'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderImages(page, item, apiClient, images, imageProviders, elem) {
|
||||
var html = "",
|
||||
imageSize = 300,
|
||||
windowSize = dom.getWindowSize();
|
||||
windowSize.innerWidth >= 1280 && (imageSize = Math.round(windowSize.innerWidth / 4));
|
||||
for (var tagName = layoutManager.tv ? "button" : "div", enableFooterButtons = !layoutManager.tv, i = 0, length = images.length; i < length; i++) {
|
||||
html += getCardHtml(images[i], i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons)
|
||||
|
||||
var html = '';
|
||||
|
||||
var imageSize = 300;
|
||||
var windowSize = dom.getWindowSize();
|
||||
if (windowSize.innerWidth >= 1280) {
|
||||
imageSize = Math.round(windowSize.innerWidth / 4);
|
||||
}
|
||||
elem.innerHTML = html, imageLoader.lazyChildren(elem)
|
||||
|
||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
||||
var enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
for (var i = 0, length = images.length; i < length; i++) {
|
||||
|
||||
var image = images[i];
|
||||
|
||||
html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons);
|
||||
}
|
||||
|
||||
elem.innerHTML = html;
|
||||
imageLoader.lazyChildren(elem);
|
||||
}
|
||||
|
||||
function renderStandardImages(page, apiClient, item, imageInfos, imageProviders) {
|
||||
renderImages(page, item, apiClient, imageInfos.filter(function(i) {
|
||||
return "Screenshot" !== i.ImageType && "Backdrop" !== i.ImageType && "Chapter" !== i.ImageType
|
||||
}), imageProviders, page.querySelector("#images"))
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
return i.ImageType !== "Screenshot" && i.ImageType !== "Backdrop" && i.ImageType !== "Chapter";
|
||||
});
|
||||
|
||||
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#images'));
|
||||
}
|
||||
|
||||
function renderBackdrops(page, apiClient, item, imageInfos, imageProviders) {
|
||||
var images = imageInfos.filter(function(i) {
|
||||
return "Backdrop" === i.ImageType
|
||||
}).sort(function(a, b) {
|
||||
return a.ImageIndex - b.ImageIndex
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
return i.ImageType === "Backdrop";
|
||||
|
||||
}).sort(function (a, b) {
|
||||
return a.ImageIndex - b.ImageIndex;
|
||||
});
|
||||
images.length ? (page.querySelector("#backdropsContainer", page).classList.remove("hide"), renderImages(page, item, apiClient, images, imageProviders, page.querySelector("#backdrops"))) : page.querySelector("#backdropsContainer", page).classList.add("hide")
|
||||
|
||||
if (images.length) {
|
||||
page.querySelector('#backdropsContainer', page).classList.remove('hide');
|
||||
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#backdrops'));
|
||||
} else {
|
||||
page.querySelector('#backdropsContainer', page).classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function renderScreenshots(page, apiClient, item, imageInfos, imageProviders) {
|
||||
var images = imageInfos.filter(function(i) {
|
||||
return "Screenshot" === i.ImageType
|
||||
}).sort(function(a, b) {
|
||||
return a.ImageIndex - b.ImageIndex
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
return i.ImageType === "Screenshot";
|
||||
|
||||
}).sort(function (a, b) {
|
||||
return a.ImageIndex - b.ImageIndex;
|
||||
});
|
||||
images.length ? (page.querySelector("#screenshotsContainer", page).classList.remove("hide"), renderImages(page, item, apiClient, images, imageProviders, page.querySelector("#screenshots"))) : page.querySelector("#screenshotsContainer", page).classList.add("hide")
|
||||
|
||||
if (images.length) {
|
||||
page.querySelector('#screenshotsContainer', page).classList.remove('hide');
|
||||
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#screenshots'));
|
||||
} else {
|
||||
page.querySelector('#screenshotsContainer', page).classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function showImageDownloader(page, imageType) {
|
||||
require(["imageDownloader"], function(ImageDownloader) {
|
||||
ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function() {
|
||||
hasChanges = !0, reload(page)
|
||||
})
|
||||
})
|
||||
|
||||
require(['imageDownloader'], function (ImageDownloader) {
|
||||
|
||||
ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(page);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function showActionSheet(context, imageCard) {
|
||||
var itemId = imageCard.getAttribute("data-id"),
|
||||
serverId = imageCard.getAttribute("data-serverid"),
|
||||
apiClient = connectionManager.getApiClient(serverId),
|
||||
type = imageCard.getAttribute("data-imagetype"),
|
||||
index = parseInt(imageCard.getAttribute("data-index")),
|
||||
providerCount = parseInt(imageCard.getAttribute("data-providers")),
|
||||
numImages = parseInt(imageCard.getAttribute("data-numimages"));
|
||||
require(["actionsheet"], function(actionSheet) {
|
||||
|
||||
var itemId = imageCard.getAttribute('data-id');
|
||||
var serverId = imageCard.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
var type = imageCard.getAttribute('data-imagetype');
|
||||
var index = parseInt(imageCard.getAttribute('data-index'));
|
||||
var providerCount = parseInt(imageCard.getAttribute('data-providers'));
|
||||
var numImages = parseInt(imageCard.getAttribute('data-numimages'));
|
||||
|
||||
require(['actionsheet'], function (actionSheet) {
|
||||
|
||||
var commands = [];
|
||||
|
||||
commands.push({
|
||||
name: globalize.translate("sharedcomponents#Delete"),
|
||||
id: "delete"
|
||||
}), "Backdrop" !== type && "Screenshot" !== type || (index > 0 && commands.push({
|
||||
name: globalize.translate("sharedcomponents#MoveLeft"),
|
||||
id: "moveleft"
|
||||
}), index < numImages - 1 && commands.push({
|
||||
name: globalize.translate("sharedcomponents#MoveRight"),
|
||||
id: "moveright"
|
||||
})), providerCount && commands.push({
|
||||
name: globalize.translate("sharedcomponents#Search"),
|
||||
id: "search"
|
||||
}), actionSheet.show({
|
||||
name: globalize.translate('sharedcomponents#Delete'),
|
||||
id: 'delete'
|
||||
});
|
||||
|
||||
if (type === 'Backdrop' || type === 'Screenshot') {
|
||||
if (index > 0) {
|
||||
commands.push({
|
||||
name: globalize.translate('sharedcomponents#MoveLeft'),
|
||||
id: 'moveleft'
|
||||
});
|
||||
}
|
||||
|
||||
if (index < numImages - 1) {
|
||||
commands.push({
|
||||
name: globalize.translate('sharedcomponents#MoveRight'),
|
||||
id: 'moveright'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (providerCount) {
|
||||
commands.push({
|
||||
name: globalize.translate('sharedcomponents#Search'),
|
||||
id: 'search'
|
||||
});
|
||||
}
|
||||
|
||||
actionSheet.show({
|
||||
|
||||
items: commands,
|
||||
positionTo: imageCard
|
||||
}).then(function(id) {
|
||||
|
||||
}).then(function (id) {
|
||||
|
||||
switch (id) {
|
||||
case "delete":
|
||||
deleteImage(context, itemId, type, index, apiClient, !1);
|
||||
|
||||
case 'delete':
|
||||
deleteImage(context, itemId, type, index, apiClient, false);
|
||||
break;
|
||||
case "search":
|
||||
case 'search':
|
||||
showImageDownloader(context, type);
|
||||
break;
|
||||
case "moveleft":
|
||||
moveImage(context, apiClient, itemId, type, index, index - 1, dom.parentWithClass(imageCard, "itemsContainer"));
|
||||
case 'moveleft':
|
||||
moveImage(context, apiClient, itemId, type, index, index - 1, dom.parentWithClass(imageCard, 'itemsContainer'));
|
||||
break;
|
||||
case 'moveright':
|
||||
moveImage(context, apiClient, itemId, type, index, index + 1, dom.parentWithClass(imageCard, 'itemsContainer'));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case "moveright":
|
||||
moveImage(context, apiClient, itemId, type, index, index + 1, dom.parentWithClass(imageCard, "itemsContainer"))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initEditor(context, options) {
|
||||
for (var uploadButtons = context.querySelectorAll(".btnOpenUploadMenu"), isFileInputSupported = appHost.supports("fileinput"), i = 0, length = uploadButtons.length; i < length; i++) isFileInputSupported ? uploadButtons[i].classList.remove("hide") : uploadButtons[i].classList.add("hide");
|
||||
addListeners(context, "btnOpenUploadMenu", "click", function() {
|
||||
var imageType = this.getAttribute("data-imagetype");
|
||||
require(["imageUploader"], function(imageUploader) {
|
||||
|
||||
var uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
|
||||
var isFileInputSupported = appHost.supports('fileinput');
|
||||
for (var i = 0, length = uploadButtons.length; i < length; i++) {
|
||||
if (isFileInputSupported) {
|
||||
uploadButtons[i].classList.remove('hide');
|
||||
} else {
|
||||
uploadButtons[i].classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
addListeners(context, 'btnOpenUploadMenu', 'click', function () {
|
||||
var imageType = this.getAttribute('data-imagetype');
|
||||
|
||||
require(['imageUploader'], function (imageUploader) {
|
||||
|
||||
imageUploader.show({
|
||||
|
||||
theme: options.theme,
|
||||
imageType: imageType,
|
||||
itemId: currentItem.Id,
|
||||
serverId: currentItem.ServerId
|
||||
}).then(function(hasChanged) {
|
||||
hasChanged && (hasChanges = !0, reload(context))
|
||||
})
|
||||
})
|
||||
}), addListeners(context, "btnSearchImages", "click", function() {
|
||||
showImageDownloader(context, this.getAttribute("data-imagetype"))
|
||||
}), addListeners(context, "btnBrowseAllImages", "click", function() {
|
||||
showImageDownloader(context, this.getAttribute("data-imagetype") || "Primary")
|
||||
}), addListeners(context, "btnImageCard", "click", function() {
|
||||
showActionSheet(context, this)
|
||||
}), addListeners(context, "btnDeleteImage", "click", function() {
|
||||
var type = this.getAttribute("data-imagetype"),
|
||||
index = this.getAttribute("data-index");
|
||||
index = "null" === index ? null : parseInt(index);
|
||||
|
||||
}).then(function (hasChanged) {
|
||||
|
||||
if (hasChanged) {
|
||||
hasChanges = true;
|
||||
reload(context);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
addListeners(context, 'btnSearchImages', 'click', function () {
|
||||
showImageDownloader(context, this.getAttribute('data-imagetype'));
|
||||
});
|
||||
|
||||
addListeners(context, 'btnBrowseAllImages', 'click', function () {
|
||||
showImageDownloader(context, this.getAttribute('data-imagetype') || 'Primary');
|
||||
});
|
||||
|
||||
addListeners(context, 'btnImageCard', 'click', function () {
|
||||
showActionSheet(context, this);
|
||||
});
|
||||
|
||||
addListeners(context, 'btnDeleteImage', 'click', function () {
|
||||
var type = this.getAttribute('data-imagetype');
|
||||
var index = this.getAttribute('data-index');
|
||||
index = index === "null" ? null : parseInt(index);
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
deleteImage(context, currentItem.Id, type, index, apiClient, !0)
|
||||
}), addListeners(context, "btnMoveImage", "click", function() {
|
||||
var type = this.getAttribute("data-imagetype"),
|
||||
index = this.getAttribute("data-index"),
|
||||
newIndex = this.getAttribute("data-newindex"),
|
||||
apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, "itemsContainer"))
|
||||
})
|
||||
deleteImage(context, currentItem.Id, type, index, apiClient, true);
|
||||
});
|
||||
|
||||
addListeners(context, 'btnMoveImage', 'click', function () {
|
||||
var type = this.getAttribute('data-imagetype');
|
||||
var index = this.getAttribute('data-index');
|
||||
var newIndex = this.getAttribute('data-newindex');
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, 'itemsContainer'));
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(options, resolve, reject) {
|
||||
var itemId = options.itemId,
|
||||
serverId = options.serverId;
|
||||
loading.show(), require(["text!./imageeditor.template.html"], function(template) {
|
||||
|
||||
var itemId = options.itemId;
|
||||
var serverId = options.serverId;
|
||||
|
||||
loading.show();
|
||||
|
||||
require(['text!./imageeditor.template.html'], function (template) {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) {
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: !0
|
||||
removeOnClose: true
|
||||
};
|
||||
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "fullscreen-border";
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'fullscreen-border';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), layoutManager.tv && scrollHelper.centerFocus.on(dlg, !1), initEditor(dlg, options), dlg.addEventListener("close", function() {
|
||||
layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), hasChanges ? resolve() : reject()
|
||||
}), dialogHelper.open(dlg), reload(dlg, item), dlg.querySelector(".btnCancel").addEventListener("click", function() {
|
||||
dialogHelper.close(dlg)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg, false);
|
||||
}
|
||||
|
||||
initEditor(dlg, options);
|
||||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
|
||||
loading.hide();
|
||||
|
||||
if (hasChanges) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
reload(dlg, item);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
var currentItem, hasChanges = !1;
|
||||
|
||||
return {
|
||||
show: function(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
hasChanges = !1, showEditor(options, resolve, reject)
|
||||
})
|
||||
show: function (options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
showEditor(options, resolve, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,18 +1,38 @@
|
||||
define(["dom"], function(dom) {
|
||||
"use strict";
|
||||
define(['dom'], function (dom) {
|
||||
'use strict';
|
||||
|
||||
function loadImage(elem, url) {
|
||||
return elem ? "IMG" !== elem.tagName ? (elem.style.backgroundImage = "url('" + url + "')", Promise.resolve()) : loadImageIntoImg(elem, url) : Promise.reject("elem cannot be null")
|
||||
|
||||
if (!elem) {
|
||||
return Promise.reject('elem cannot be null');
|
||||
}
|
||||
|
||||
if (elem.tagName !== "IMG") {
|
||||
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
return Promise.resolve();
|
||||
|
||||
//return loadImageIntoImg(document.createElement('img'), url).then(function () {
|
||||
// elem.style.backgroundImage = "url('" + url + "')";
|
||||
// return Promise.resolve();
|
||||
//});
|
||||
|
||||
}
|
||||
return loadImageIntoImg(elem, url);
|
||||
}
|
||||
|
||||
function loadImageIntoImg(elem, url) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
dom.addEventListener(elem, "load", resolve, {
|
||||
once: !0
|
||||
}), elem.setAttribute("src", url)
|
||||
})
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
dom.addEventListener(elem, 'load', resolve, {
|
||||
once: true
|
||||
});
|
||||
elem.setAttribute("src", url);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
loadImage: loadImage
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -1,82 +1,255 @@
|
||||
define(["lazyLoader", "imageFetcher", "layoutManager", "browser", "appSettings", "require", "css!./style"], function(lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) {
|
||||
"use strict";
|
||||
define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', 'require', 'css!./style'], function (lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) {
|
||||
'use strict';
|
||||
|
||||
var requestIdleCallback = window.requestIdleCallback || function (fn) {
|
||||
fn();
|
||||
};
|
||||
|
||||
var self = {};
|
||||
|
||||
// seeing slow performance with firefox
|
||||
var enableFade = false;
|
||||
|
||||
function fillImage(elem, source, enableEffects) {
|
||||
if (!elem) throw new Error("elem cannot be null");
|
||||
source || (source = elem.getAttribute("data-src")), source && fillImageElement(elem, source, enableEffects)
|
||||
|
||||
if (!elem) {
|
||||
throw new Error('elem cannot be null');
|
||||
}
|
||||
|
||||
if (!source) {
|
||||
source = elem.getAttribute('data-src');
|
||||
}
|
||||
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
fillImageElement(elem, source, enableEffects);
|
||||
}
|
||||
|
||||
function fillImageElement(elem, source, enableEffects) {
|
||||
imageFetcher.loadImage(elem, source).then(function() {
|
||||
enableFade && !1 !== enableEffects && fadeIn(elem), elem.removeAttribute("data-src")
|
||||
})
|
||||
imageFetcher.loadImage(elem, source).then(function () {
|
||||
|
||||
var fillingVibrant = false;//fillVibrant(elem, source);
|
||||
|
||||
if (enableFade && enableEffects !== false && !fillingVibrant) {
|
||||
fadeIn(elem);
|
||||
}
|
||||
|
||||
elem.removeAttribute("data-src");
|
||||
});
|
||||
}
|
||||
|
||||
function fillVibrant(img, url, canvas, canvasContext) {
|
||||
|
||||
var vibrantElement = img.getAttribute('data-vibrant');
|
||||
if (!vibrantElement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window.Vibrant) {
|
||||
fillVibrantOnLoaded(img, url, vibrantElement, canvas, canvasContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
require(['vibrant'], function () {
|
||||
fillVibrantOnLoaded(img, url, vibrantElement, canvas, canvasContext);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function fillVibrantOnLoaded(img, url, vibrantElement) {
|
||||
|
||||
vibrantElement = document.getElementById(vibrantElement);
|
||||
if (!vibrantElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
requestIdleCallback(function () {
|
||||
|
||||
//var now = new Date().getTime();
|
||||
getVibrantInfoFromElement(img, url).then(function (vibrantInfo) {
|
||||
|
||||
var swatch = vibrantInfo.split('|');
|
||||
//console.log('vibrant took ' + (new Date().getTime() - now) + 'ms');
|
||||
if (swatch.length) {
|
||||
|
||||
var index = 0;
|
||||
var style = vibrantElement.style;
|
||||
style.backgroundColor = swatch[index];
|
||||
style.color = swatch[index + 1];
|
||||
|
||||
var classList = vibrantElement.classList;
|
||||
|
||||
if (classList.contains('cardFooter')) {
|
||||
classList.add('cardFooter-vibrant');
|
||||
} else {
|
||||
classList.add('vibrant');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
/*
|
||||
* Results into:
|
||||
* Vibrant #7a4426
|
||||
* Muted #7b9eae
|
||||
* DarkVibrant #348945
|
||||
* DarkMuted #141414
|
||||
* LightVibrant #f3ccb4
|
||||
*/
|
||||
}
|
||||
|
||||
function getVibrantInfoFromElement(elem, url) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
require(["vibrant"], function() {
|
||||
if ("IMG" === elem.tagName) return void resolve(getVibrantInfo(elem, url));
|
||||
var img = new Image;
|
||||
img.onload = function() {
|
||||
resolve(getVibrantInfo(img, url))
|
||||
}, img.src = url
|
||||
})
|
||||
})
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['vibrant'], function () {
|
||||
|
||||
if (elem.tagName === 'IMG') {
|
||||
resolve(getVibrantInfo(elem, url));
|
||||
return;
|
||||
}
|
||||
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
resolve(getVibrantInfo(img, url));
|
||||
};
|
||||
img.src = url;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getSettingsKey(url) {
|
||||
var parts = url.split("://");
|
||||
url = parts[parts.length - 1], url = url.substring(url.indexOf("/") + 1), url = url.split("?")[0];
|
||||
return "vibrant31" + url
|
||||
|
||||
var parts = url.split('://');
|
||||
url = parts[parts.length - 1];
|
||||
|
||||
url = url.substring(url.indexOf('/') + 1);
|
||||
|
||||
url = url.split('?')[0];
|
||||
|
||||
var cacheKey = 'vibrant31';
|
||||
//cacheKey = 'vibrant' + new Date().getTime();
|
||||
return cacheKey + url;
|
||||
}
|
||||
|
||||
function getCachedVibrantInfo(url) {
|
||||
return appSettings.get(getSettingsKey(url))
|
||||
|
||||
return appSettings.get(getSettingsKey(url));
|
||||
}
|
||||
|
||||
function getVibrantInfo(img, url) {
|
||||
|
||||
var value = getCachedVibrantInfo(url);
|
||||
if (value) return value;
|
||||
var vibrant = new Vibrant(img),
|
||||
swatches = vibrant.swatches();
|
||||
return value = "", value += getSwatchString(swatches.DarkVibrant), appSettings.set(getSettingsKey(url), value), value
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
var vibrant = new Vibrant(img);
|
||||
var swatches = vibrant.swatches();
|
||||
|
||||
value = '';
|
||||
var swatch = swatches.DarkVibrant;
|
||||
value += getSwatchString(swatch);
|
||||
|
||||
appSettings.set(getSettingsKey(url), value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function getSwatchString(swatch) {
|
||||
return swatch ? swatch.getHex() + "|" + swatch.getBodyTextColor() + "|" + swatch.getTitleTextColor() : "||"
|
||||
|
||||
if (swatch) {
|
||||
return swatch.getHex() + '|' + swatch.getBodyTextColor() + '|' + swatch.getTitleTextColor();
|
||||
}
|
||||
return '||';
|
||||
}
|
||||
|
||||
function fadeIn(elem) {
|
||||
elem.classList.add("lazy-image-fadein")
|
||||
|
||||
var cssClass = 'lazy-image-fadein';
|
||||
|
||||
elem.classList.add(cssClass);
|
||||
}
|
||||
|
||||
function lazyChildren(elem) {
|
||||
lazyLoader.lazyChildren(elem, fillImage)
|
||||
|
||||
lazyLoader.lazyChildren(elem, fillImage);
|
||||
}
|
||||
|
||||
function getPrimaryImageAspectRatio(items) {
|
||||
for (var values = [], i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var values = [];
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var ratio = items[i].PrimaryImageAspectRatio || 0;
|
||||
ratio && (values[values.length] = ratio)
|
||||
|
||||
if (!ratio) {
|
||||
continue;
|
||||
}
|
||||
|
||||
values[values.length] = ratio;
|
||||
}
|
||||
if (!values.length) return null;
|
||||
values.sort(function(a, b) {
|
||||
return a - b
|
||||
});
|
||||
var result, half = Math.floor(values.length / 2);
|
||||
result = values.length % 2 ? values[half] : (values[half - 1] + values[half]) / 2;
|
||||
if (Math.abs(2 / 3 - result) <= .15) return 2 / 3;
|
||||
if (Math.abs(16 / 9 - result) <= .2) return 16 / 9;
|
||||
if (Math.abs(1 - result) <= .15) return 1;
|
||||
return Math.abs(4 / 3 - result) <= .15 ? 4 / 3 : result
|
||||
|
||||
if (!values.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Use the median
|
||||
values.sort(function (a, b) { return a - b; });
|
||||
|
||||
var half = Math.floor(values.length / 2);
|
||||
|
||||
var result;
|
||||
|
||||
if (values.length % 2) {
|
||||
result = values[half];
|
||||
}
|
||||
else {
|
||||
result = (values[half - 1] + values[half]) / 2.0;
|
||||
}
|
||||
|
||||
// If really close to 2:3 (poster image), just return 2:3
|
||||
var aspect2x3 = 2 / 3;
|
||||
if (Math.abs(aspect2x3 - result) <= 0.15) {
|
||||
return aspect2x3;
|
||||
}
|
||||
|
||||
// If really close to 16:9 (episode image), just return 16:9
|
||||
var aspect16x9 = 16 / 9;
|
||||
if (Math.abs(aspect16x9 - result) <= 0.2) {
|
||||
return aspect16x9;
|
||||
}
|
||||
|
||||
// If really close to 1 (square image), just return 1
|
||||
if (Math.abs(1 - result) <= 0.15) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If really close to 4:3 (poster image), just return 2:3
|
||||
var aspect4x3 = 4 / 3;
|
||||
if (Math.abs(aspect4x3 - result) <= 0.15) {
|
||||
return aspect4x3;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function fillImages(elems) {
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
fillImage(elems[0])
|
||||
var elem = elems[0];
|
||||
fillImage(elem);
|
||||
}
|
||||
}
|
||||
var self = (window.requestIdleCallback, {}),
|
||||
enableFade = !1;
|
||||
return self.fillImages = fillImages, self.lazyImage = fillImage, self.lazyChildren = lazyChildren, self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio, self.getCachedVibrantInfo = getCachedVibrantInfo, self.getVibrantInfoFromElement = getVibrantInfoFromElement, self
|
||||
|
||||
self.fillImages = fillImages;
|
||||
self.lazyImage = fillImage;
|
||||
self.lazyChildren = lazyChildren;
|
||||
self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio;
|
||||
self.getCachedVibrantInfo = getCachedVibrantInfo;
|
||||
self.getVibrantInfoFromElement = getVibrantInfoFromElement;
|
||||
|
||||
return self;
|
||||
});
|
||||
@@ -1,61 +1,47 @@
|
||||
.lazy-image-fadein {
|
||||
-webkit-animation: lazy-image-fadein 330ms ease-in normal both;
|
||||
animation: lazy-image-fadein 330ms ease-in normal both
|
||||
animation: lazy-image-fadein 330ms ease-in normal both;
|
||||
}
|
||||
|
||||
.lazy-image-fadein-fast {
|
||||
-webkit-animation: lazy-image-fadein 160ms ease-in normal both;
|
||||
animation: lazy-image-fadein 160ms ease-in normal both
|
||||
}
|
||||
|
||||
@-webkit-keyframes lazy-image-fadein {
|
||||
from {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1
|
||||
}
|
||||
animation: lazy-image-fadein 160ms ease-in normal both;
|
||||
}
|
||||
|
||||
@keyframes lazy-image-fadein {
|
||||
from {
|
||||
opacity: 0
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.lazy-image-fadein {
|
||||
opacity: 0;
|
||||
-webkit-animation-duration: .8s;
|
||||
-moz-animation-duration: .8s;
|
||||
-o-animation-duration: .8s;
|
||||
animation-duration: .8s;
|
||||
-webkit-animation-name: popInAnimation;
|
||||
-moz-animation-name: popInAnimation;
|
||||
-o-animation-name: popInAnimation;
|
||||
animation-name: popInAnimation;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
-moz-animation-fill-mode: forwards;
|
||||
-o-animation-fill-mode: forwards;
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation-timing-function: cubic-bezier(0, 0, .5, 1);
|
||||
animation-timing-function: cubic-bezier(0, 0, .5, 1)
|
||||
}
|
||||
|
||||
@-webkit-keyframes popInAnimation {
|
||||
0% {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1
|
||||
}
|
||||
-webkit-animation-timing-function: cubic-bezier(0,0,.5,1);
|
||||
-moz-animation-timing-function: cubic-bezier(0,0,.5,1);
|
||||
-o-animation-timing-function: cubic-bezier(0,0,.5,1);
|
||||
animation-timing-function: cubic-bezier(0,0,.5,1);
|
||||
}
|
||||
|
||||
@keyframes popInAnimation {
|
||||
0% {
|
||||
opacity: 0
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -1,80 +1,177 @@
|
||||
define(["dialogHelper", "connectionManager", "dom", "loading", "scrollHelper", "layoutManager", "globalize", "require", "emby-button", "emby-select", "formDialogStyle", "css!./style"], function(dialogHelper, connectionManager, dom, loading, scrollHelper, layoutManager, globalize, require) {
|
||||
"use strict";
|
||||
define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', 'layoutManager', 'globalize', 'require', 'emby-button', 'emby-select', 'formDialogStyle', 'css!./style'], function (dialogHelper, connectionManager, dom, loading, scrollHelper, layoutManager, globalize, require) {
|
||||
'use strict';
|
||||
|
||||
var currentItemId;
|
||||
var currentServerId;
|
||||
var currentFile;
|
||||
var hasChanges = false;
|
||||
|
||||
function onFileReaderError(evt) {
|
||||
switch (loading.hide(), evt.target.error.code) {
|
||||
|
||||
loading.hide();
|
||||
|
||||
switch (evt.target.error.code) {
|
||||
case evt.target.error.NOT_FOUND_ERR:
|
||||
require(["toast"], function(toast) {
|
||||
toast(globalize.translate("sharedcomponents#MessageFileReadError"))
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('sharedcomponents#MessageFileReadError'));
|
||||
});
|
||||
break;
|
||||
case evt.target.error.ABORT_ERR:
|
||||
break;
|
||||
break; // noop
|
||||
default:
|
||||
require(["toast"], function(toast) {
|
||||
toast(globalize.translate("sharedcomponents#MessageFileReadError"))
|
||||
})
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('sharedcomponents#MessageFileReadError'));
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function setFiles(page, files) {
|
||||
|
||||
var file = files[0];
|
||||
if (!file || !file.type.match("image.*")) return page.querySelector("#imageOutput").innerHTML = "", page.querySelector("#fldUpload").classList.add("hide"), void(currentFile = null);
|
||||
|
||||
if (!file || !file.type.match('image.*')) {
|
||||
page.querySelector('#imageOutput').innerHTML = '';
|
||||
page.querySelector('#fldUpload').classList.add('hide');
|
||||
currentFile = null;
|
||||
return;
|
||||
}
|
||||
|
||||
currentFile = file;
|
||||
var reader = new FileReader;
|
||||
reader.onerror = onFileReaderError, reader.onloadstart = function() {
|
||||
page.querySelector("#fldUpload").classList.add("hide")
|
||||
}, reader.onabort = function() {
|
||||
loading.hide(), console.log("File read cancelled")
|
||||
}, reader.onload = function(theFile) {
|
||||
return function(e) {
|
||||
var html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join("");
|
||||
page.querySelector("#imageOutput").innerHTML = html, page.querySelector("#fldUpload").classList.remove("hide")
|
||||
}
|
||||
}(file), reader.readAsDataURL(file)
|
||||
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onerror = onFileReaderError;
|
||||
reader.onloadstart = function () {
|
||||
page.querySelector('#fldUpload').classList.add('hide');
|
||||
};
|
||||
reader.onabort = function () {
|
||||
loading.hide();
|
||||
console.log('File read cancelled');
|
||||
};
|
||||
|
||||
// Closure to capture the file information.
|
||||
reader.onload = (function (theFile) {
|
||||
return function (e) {
|
||||
|
||||
// Render thumbnail.
|
||||
var html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
|
||||
|
||||
page.querySelector('#imageOutput').innerHTML = html;
|
||||
page.querySelector('#fldUpload').classList.remove('hide');
|
||||
};
|
||||
})(file);
|
||||
|
||||
// Read in the image file as a data URL.
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
var file = currentFile;
|
||||
if (!file) return !1;
|
||||
if ("image/png" !== file.type && "image/jpeg" !== file.type && "image/jpeg" !== file.type) return !1;
|
||||
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.type !== "image/png" && file.type !== "image/jpeg" && file.type !== "image/jpeg") {
|
||||
return false;
|
||||
}
|
||||
|
||||
loading.show();
|
||||
var dlg = dom.parentWithClass(this, "dialog"),
|
||||
imageType = dlg.querySelector("#selectImageType").value;
|
||||
return connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(function() {
|
||||
dlg.querySelector("#uploadImage").value = "", loading.hide(), hasChanges = !0, dialogHelper.close(dlg)
|
||||
}), e.preventDefault(), !1
|
||||
|
||||
var dlg = dom.parentWithClass(this, 'dialog');
|
||||
|
||||
var imageType = dlg.querySelector('#selectImageType').value;
|
||||
|
||||
connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(function () {
|
||||
|
||||
dlg.querySelector('#uploadImage').value = '';
|
||||
|
||||
loading.hide();
|
||||
hasChanges = true;
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function initEditor(page) {
|
||||
page.querySelector("form").addEventListener("submit", onSubmit), page.querySelector("#uploadImage").addEventListener("change", function() {
|
||||
setFiles(page, this.files)
|
||||
}), page.querySelector(".btnBrowse").addEventListener("click", function() {
|
||||
page.querySelector("#uploadImage").click()
|
||||
})
|
||||
|
||||
page.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
page.querySelector('#uploadImage').addEventListener("change", function () {
|
||||
setFiles(page, this.files);
|
||||
});
|
||||
|
||||
page.querySelector('.btnBrowse').addEventListener("click", function () {
|
||||
page.querySelector('#uploadImage').click();
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(options, resolve, reject) {
|
||||
options = options || {}, require(["text!./imageuploader.template.html"], function(template) {
|
||||
currentItemId = options.itemId, currentServerId = options.serverId;
|
||||
|
||||
options = options || {};
|
||||
|
||||
require(['text!./imageuploader.template.html'], function (template) {
|
||||
|
||||
currentItemId = options.itemId;
|
||||
currentServerId = options.serverId;
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: !0
|
||||
removeOnClose: true
|
||||
};
|
||||
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "fullscreen-border";
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'fullscreen-border';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), layoutManager.tv && scrollHelper.centerFocus.on(dlg, !1), dlg.addEventListener("close", function() {
|
||||
layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), resolve(hasChanges)
|
||||
}), dialogHelper.open(dlg), initEditor(dlg), dlg.querySelector("#selectImageType").value = options.imageType || "Primary", dlg.querySelector(".btnCancel").addEventListener("click", function() {
|
||||
dialogHelper.close(dlg)
|
||||
})
|
||||
})
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg, false);
|
||||
}
|
||||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
|
||||
loading.hide();
|
||||
resolve(hasChanges);
|
||||
});
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
initEditor(dlg);
|
||||
|
||||
dlg.querySelector('#selectImageType').value = options.imageType || 'Primary';
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
var currentItemId, currentServerId, currentFile, hasChanges = !1;
|
||||
|
||||
return {
|
||||
show: function(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
hasChanges = !1, showEditor(options, resolve, reject)
|
||||
})
|
||||
show: function (options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
showEditor(options, resolve, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,17 +1,11 @@
|
||||
.imageEditor-dropZone {
|
||||
.imageEditor-dropZone {
|
||||
border: .2em dashed currentcolor;
|
||||
-webkit-border-radius: .25em;
|
||||
border-radius: .25em;
|
||||
/* padding: 1.6em; */
|
||||
text-align: center;
|
||||
position: relative;
|
||||
height: 12em;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -1,125 +1,96 @@
|
||||
.itemProgressBar {
|
||||
background: #333;
|
||||
background: rgba(51, 51, 51, .8);
|
||||
background: rgba(51,51,51,.8);
|
||||
position: relative;
|
||||
height: .28em
|
||||
height: .28em;
|
||||
}
|
||||
|
||||
.itemProgressBarForeground {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
-webkit-border-radius: 100em;
|
||||
border-radius: 100em;
|
||||
display: -webkit-flex;
|
||||
display: -webkit-box;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
font-weight: 500;
|
||||
width: 2em;
|
||||
height: 2em
|
||||
}
|
||||
|
||||
.countIndicator,
|
||||
.playedIndicator {
|
||||
-webkit-border-radius: 100em;
|
||||
display: -webkit-flex;
|
||||
display: -webkit-box;
|
||||
-webkit-box-align: center;
|
||||
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2)
|
||||
height: 2em;
|
||||
}
|
||||
|
||||
.timerIndicator {
|
||||
color: #CB272A
|
||||
color: #CB272A;
|
||||
}
|
||||
|
||||
.timerIndicator-inactive {
|
||||
color: #888
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.indicator+.indicator {
|
||||
margin-left: .25em
|
||||
.indicator + .indicator {
|
||||
margin-left: .25em;
|
||||
}
|
||||
|
||||
.indicatorIcon {
|
||||
width: auto;
|
||||
height: auto;
|
||||
font-size: 1.6em
|
||||
font-size: 1.6em;
|
||||
}
|
||||
|
||||
.countIndicator {
|
||||
border-radius: 100em;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2);
|
||||
font-size: 88%
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
||||
font-size: 88%;
|
||||
}
|
||||
|
||||
.playedIndicator {
|
||||
border-radius: 100em;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2);
|
||||
font-size: 80%
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.videoIndicator {
|
||||
background: #444;
|
||||
-webkit-border-radius: 100em;
|
||||
border-radius: 100em;
|
||||
display: -webkit-flex;
|
||||
display: -webkit-box;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2);
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2);
|
||||
font-size: 88%
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
||||
font-size: 88%;
|
||||
}
|
||||
|
||||
.syncIndicator {
|
||||
-webkit-border-radius: 100em;
|
||||
border-radius: 100em
|
||||
border-radius: 100em;
|
||||
}
|
||||
|
||||
.emptySyncIndicator {
|
||||
background: #ccc;
|
||||
color: #333
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.missingIndicator,
|
||||
.unairedIndicator {
|
||||
background: #c33;
|
||||
.missingIndicator, .unairedIndicator {
|
||||
background: #cc3333;
|
||||
padding: .25em .5em;
|
||||
-webkit-border-radius: 100em;
|
||||
border-radius: 100em;
|
||||
color: #fff;
|
||||
font-size: 84%;
|
||||
font-weight: 500;
|
||||
margin: 0 .25em
|
||||
margin: 0 .25em;
|
||||
}
|
||||
@@ -1,112 +1,274 @@
|
||||
define(["datetime", "itemHelper", "css!./indicators.css", "material-icons"], function(datetime, itemHelper) {
|
||||
"use strict";
|
||||
define(['datetime', 'itemHelper', 'css!./indicators.css', 'material-icons'], function (datetime, itemHelper) {
|
||||
'use strict';
|
||||
|
||||
function enableProgressIndicator(item) {
|
||||
return "Video" === item.MediaType && "TvChannel" !== item.Type || ("AudioBook" === item.Type || "AudioPodcast" === item.Type)
|
||||
|
||||
if (item.MediaType === 'Video') {
|
||||
if (item.Type !== 'TvChannel') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'AudioBook' || item.Type === 'AudioPodcast') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getProgressHtml(pct, options) {
|
||||
var containerClass = "itemProgressBar";
|
||||
return options && options.containerClass && (containerClass += " " + options.containerClass), '<div class="' + containerClass + '"><div class="itemProgressBarForeground" style="width:' + pct + '%;"></div></div>'
|
||||
|
||||
var containerClass = 'itemProgressBar';
|
||||
|
||||
if (options) {
|
||||
if (options.containerClass) {
|
||||
containerClass += ' ' + options.containerClass;
|
||||
}
|
||||
}
|
||||
|
||||
return '<div class="' + containerClass + '"><div class="itemProgressBarForeground" style="width:' + pct + '%;"></div></div>';
|
||||
}
|
||||
|
||||
function getAutoTimeProgressHtml(pct, options, isRecording, start, end) {
|
||||
var containerClass = "itemProgressBar";
|
||||
options && options.containerClass && (containerClass += " " + options.containerClass);
|
||||
var foregroundClass = "itemProgressBarForeground";
|
||||
return isRecording && (foregroundClass += " itemProgressBarForeground-recording"), '<div is="emby-progressbar" data-automode="time" data-starttime="' + start + '" data-endtime="' + end + '" class="' + containerClass + '"><div class="' + foregroundClass + '" style="width:' + pct + '%;"></div></div>'
|
||||
|
||||
var containerClass = 'itemProgressBar';
|
||||
|
||||
if (options) {
|
||||
if (options.containerClass) {
|
||||
containerClass += ' ' + options.containerClass;
|
||||
}
|
||||
}
|
||||
|
||||
var foregroundClass = 'itemProgressBarForeground';
|
||||
|
||||
if (isRecording) {
|
||||
foregroundClass += ' itemProgressBarForeground-recording';
|
||||
}
|
||||
|
||||
return '<div is="emby-progressbar" data-automode="time" data-starttime="' + start + '" data-endtime="' + end + '" class="' + containerClass + '"><div class="' + foregroundClass + '" style="width:' + pct + '%;"></div></div>';
|
||||
}
|
||||
|
||||
function getProgressBarHtml(item, options) {
|
||||
|
||||
var pct;
|
||||
if (enableProgressIndicator(item) && "Recording" !== item.Type) {
|
||||
var userData = options ? options.userData || item.UserData : item.UserData;
|
||||
if (userData && (pct = userData.PlayedPercentage) && pct < 100) return getProgressHtml(pct, options)
|
||||
}
|
||||
if (("Program" === item.Type || "Timer" === item.Type || "Recording" === item.Type) && item.StartDate && item.EndDate) {
|
||||
var startDate = 0,
|
||||
endDate = 1;
|
||||
try {
|
||||
startDate = datetime.parseISO8601Date(item.StartDate).getTime()
|
||||
} catch (err) {}
|
||||
try {
|
||||
endDate = datetime.parseISO8601Date(item.EndDate).getTime()
|
||||
} catch (err) {}
|
||||
if ((pct = ((new Date).getTime() - startDate) / (endDate - startDate) * 100) > 0 && pct < 100) {
|
||||
return getAutoTimeProgressHtml(pct, options, "Timer" === item.Type || "Recording" === item.Type || item.TimerId, startDate, endDate)
|
||||
|
||||
if (enableProgressIndicator(item) && item.Type !== "Recording") {
|
||||
|
||||
var userData = options ? (options.userData || item.UserData) : item.UserData;
|
||||
if (userData) {
|
||||
pct = userData.PlayedPercentage;
|
||||
|
||||
if (pct && pct < 100) {
|
||||
|
||||
return getProgressHtml(pct, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
||||
if ((item.Type === 'Program' || item.Type === 'Timer' || item.Type === 'Recording') && item.StartDate && item.EndDate) {
|
||||
|
||||
var startDate = 0;
|
||||
var endDate = 1;
|
||||
|
||||
try {
|
||||
|
||||
startDate = datetime.parseISO8601Date(item.StartDate).getTime();
|
||||
|
||||
} catch (err) {
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
endDate = datetime.parseISO8601Date(item.EndDate).getTime();
|
||||
|
||||
} catch (err) {
|
||||
}
|
||||
|
||||
var now = new Date().getTime();
|
||||
var total = endDate - startDate;
|
||||
pct = 100 * ((now - startDate) / total);
|
||||
|
||||
if (pct > 0 && pct < 100) {
|
||||
|
||||
var isRecording = item.Type === 'Timer' || item.Type === 'Recording' || item.TimerId;
|
||||
|
||||
return getAutoTimeProgressHtml(pct, options, isRecording, startDate, endDate);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function enablePlayedIndicator(item) {
|
||||
return itemHelper.canMarkPlayed(item)
|
||||
|
||||
return itemHelper.canMarkPlayed(item);
|
||||
}
|
||||
|
||||
function getPlayedIndicator(item) {
|
||||
|
||||
if (enablePlayedIndicator(item)) {
|
||||
|
||||
var userData = item.UserData || {};
|
||||
if (userData.UnplayedItemCount) return '<div class="countIndicator indicator">' + userData.UnplayedItemCount + "</div>";
|
||||
if (userData.PlayedPercentage && userData.PlayedPercentage >= 100 || userData.Played) return '<div class="playedIndicator indicator"><i class="md-icon indicatorIcon"></i></div>'
|
||||
|
||||
if (userData.UnplayedItemCount) {
|
||||
return '<div class="countIndicator indicator">' + userData.UnplayedItemCount + '</div>';
|
||||
}
|
||||
|
||||
if (userData.PlayedPercentage && userData.PlayedPercentage >= 100 || (userData.Played)) {
|
||||
return '<div class="playedIndicator indicator"><i class="md-icon indicatorIcon"></i></div>';
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function getCountIndicatorHtml(count) {
|
||||
return '<div class="countIndicator indicator">' + count + "</div>"
|
||||
|
||||
return '<div class="countIndicator indicator">' + count + '</div>';
|
||||
}
|
||||
|
||||
function getChildCountIndicatorHtml(item, options) {
|
||||
|
||||
var minCount = 0;
|
||||
return options && (minCount = options.minCount || minCount), item.ChildCount && item.ChildCount > minCount ? getCountIndicatorHtml(item.ChildCount) : ""
|
||||
|
||||
if (options) {
|
||||
minCount = options.minCount || minCount;
|
||||
}
|
||||
|
||||
if (item.ChildCount && item.ChildCount > minCount) {
|
||||
return getCountIndicatorHtml(item.ChildCount);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function getTimerIndicator(item) {
|
||||
|
||||
var status;
|
||||
if ("SeriesTimer" === item.Type) return '<i class="md-icon timerIndicator indicatorIcon"></i>';
|
||||
if (item.TimerId || item.SeriesTimerId) status = item.Status || "Cancelled";
|
||||
else {
|
||||
if ("Timer" !== item.Type) return "";
|
||||
status = item.Status
|
||||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return '<i class="md-icon timerIndicator indicatorIcon"></i>';
|
||||
}
|
||||
return item.SeriesTimerId ? "Cancelled" !== status ? '<i class="md-icon timerIndicator indicatorIcon"></i>' : '<i class="md-icon timerIndicator timerIndicator-inactive indicatorIcon"></i>' : '<i class="md-icon timerIndicator indicatorIcon"></i>'
|
||||
else if (item.TimerId || item.SeriesTimerId) {
|
||||
|
||||
status = item.Status || 'Cancelled';
|
||||
}
|
||||
else if (item.Type === 'Timer') {
|
||||
|
||||
status = item.Status;
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (item.SeriesTimerId) {
|
||||
|
||||
if (status !== 'Cancelled') {
|
||||
return '<i class="md-icon timerIndicator indicatorIcon"></i>';
|
||||
}
|
||||
|
||||
return '<i class="md-icon timerIndicator timerIndicator-inactive indicatorIcon"></i>';
|
||||
}
|
||||
|
||||
return '<i class="md-icon timerIndicator indicatorIcon"></i>';
|
||||
}
|
||||
|
||||
function getSyncIndicator(item) {
|
||||
return 100 === item.SyncPercent ? '<div class="syncIndicator indicator fullSyncIndicator"><i class="md-icon indicatorIcon"></i></div>' : null != item.SyncPercent ? '<div class="syncIndicator indicator emptySyncIndicator"><i class="md-icon indicatorIcon"></i></div>' : ""
|
||||
|
||||
if (item.SyncPercent === 100) {
|
||||
return '<div class="syncIndicator indicator fullSyncIndicator"><i class="md-icon indicatorIcon"></i></div>';
|
||||
} else if (item.SyncPercent != null) {
|
||||
return '<div class="syncIndicator indicator emptySyncIndicator"><i class="md-icon indicatorIcon"></i></div>';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function getTypeIndicator(item) {
|
||||
return "Video" === item.Type ? '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon"></i></div>' : "Folder" === item.Type || "PhotoAlbum" === item.Type ? '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon"></i></div>' : "Photo" === item.Type ? '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon"></i></div>' : ""
|
||||
|
||||
if (item.Type === 'Video') {
|
||||
|
||||
return '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon"></i></div>';
|
||||
}
|
||||
if (item.Type === 'Folder' || item.Type === 'PhotoAlbum') {
|
||||
|
||||
return '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon"></i></div>';
|
||||
}
|
||||
if (item.Type === 'Photo') {
|
||||
|
||||
return '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon"></i></div>';
|
||||
//return '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon"></i></div>';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function getMissingIndicator(item) {
|
||||
if ("Episode" === item.Type && "Virtual" === item.LocationType) {
|
||||
if (item.PremiereDate) try {
|
||||
if (datetime.parseISO8601Date(item.PremiereDate).getTime() > (new Date).getTime()) return '<div class="unairedIndicator">Unaired</div>'
|
||||
} catch (err) {}
|
||||
return '<div class="missingIndicator">Missing</div>'
|
||||
|
||||
if (item.Type === 'Episode' && item.LocationType === 'Virtual') {
|
||||
|
||||
if (item.PremiereDate) {
|
||||
try {
|
||||
|
||||
var premiereDate = datetime.parseISO8601Date(item.PremiereDate).getTime();
|
||||
|
||||
if (premiereDate > new Date().getTime()) {
|
||||
return '<div class="unairedIndicator">Unaired</div>';
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
|
||||
return '<div class="missingIndicator">Missing</div>';
|
||||
}
|
||||
return ""
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function onAutoTimeProgress() {
|
||||
var start = parseInt(this.getAttribute("data-starttime")),
|
||||
end = parseInt(this.getAttribute("data-endtime")),
|
||||
now = (new Date).getTime(),
|
||||
total = end - start,
|
||||
pct = (now - start) / total * 100;
|
||||
pct = Math.min(100, pct), pct = Math.max(0, pct), this.querySelector(".itemProgressBarForeground").style.width = pct + "%"
|
||||
}
|
||||
var ProgressBarPrototype = Object.create(HTMLDivElement.prototype);
|
||||
return ProgressBarPrototype.attachedCallback = function() {
|
||||
this.timeInterval && clearInterval(this.timeInterval), "time" === this.getAttribute("data-automode") && (this.timeInterval = setInterval(onAutoTimeProgress.bind(this), 6e4))
|
||||
}, ProgressBarPrototype.detachedCallback = function() {
|
||||
this.timeInterval && (clearInterval(this.timeInterval), this.timeInterval = null)
|
||||
}, document.registerElement("emby-progressbar", {
|
||||
|
||||
function onAutoTimeProgress() {
|
||||
|
||||
var start = parseInt(this.getAttribute('data-starttime'));
|
||||
var end = parseInt(this.getAttribute('data-endtime'));
|
||||
|
||||
var now = new Date().getTime();
|
||||
var total = end - start;
|
||||
var pct = 100 * ((now - start) / total);
|
||||
|
||||
pct = Math.min(100, pct);
|
||||
pct = Math.max(0, pct);
|
||||
|
||||
var itemProgressBarForeground = this.querySelector('.itemProgressBarForeground');
|
||||
itemProgressBarForeground.style.width = pct + '%';
|
||||
}
|
||||
|
||||
ProgressBarPrototype.attachedCallback = function () {
|
||||
|
||||
if (this.timeInterval) {
|
||||
clearInterval(this.timeInterval);
|
||||
}
|
||||
|
||||
if (this.getAttribute('data-automode') === 'time') {
|
||||
this.timeInterval = setInterval(onAutoTimeProgress.bind(this), 60000);
|
||||
}
|
||||
};
|
||||
|
||||
ProgressBarPrototype.detachedCallback = function () {
|
||||
|
||||
if (this.timeInterval) {
|
||||
clearInterval(this.timeInterval);
|
||||
this.timeInterval = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-progressbar', {
|
||||
prototype: ProgressBarPrototype,
|
||||
extends: "div"
|
||||
}), {
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
return {
|
||||
getProgressBarHtml: getProgressBarHtml,
|
||||
getPlayedIndicatorHtml: getPlayedIndicator,
|
||||
getChildCountIndicatorHtml: getChildCountIndicatorHtml,
|
||||
@@ -116,5 +278,5 @@ define(["datetime", "itemHelper", "css!./indicators.css", "material-icons"], fun
|
||||
getSyncIndicator: getSyncIndicator,
|
||||
getTypeIndicator: getTypeIndicator,
|
||||
getMissingIndicator: getMissingIndicator
|
||||
}
|
||||
};
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user