Unminify using 1.5.323

Repo with tag: https://github.com/MediaBrowser/emby-webcomponents/tree/1.5.323
This commit is contained in:
Vasily 2019-01-10 15:39:37 +03:00
parent 4678528d00
commit de6ac33ec1
289 changed files with 78483 additions and 54701 deletions

View file

@ -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;
}

View file

@ -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">&#xE5C4;</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">&#xE5C4;</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
}
};
});

View file

@ -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();
});
};
});

View file

@ -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();
};
});

View file

@ -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;
});

View file

@ -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">&#xE256;</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">&#xE14A;</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">&#xE256;</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">&#xE14A;</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;
});

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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;
});

View file

@ -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();
});

View file

@ -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
}
};
});

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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
}
};
});

View file

@ -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: "&#xE7FD;"
}), cardBuilder.buildCards(items, options)
cardLayout: false,
centerText: true,
showTitle: true,
cardFooterAside: 'none',
showPersonRoleOrType: true,
cardCssClass: 'personCard',
defaultCardImageIcon: '&#xE7FD;'
});
cardBuilder.buildCards(items, options);
}
return {
buildPeopleCards: buildPeopleCards
}
};
});

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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">&#xE5C4;</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">&#xE88E;</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">&#xE5C4;</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">&#xE88E;</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;
});

View file

@ -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();
});
};
});

View file

@ -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();
}
};
});

View file

@ -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;
}
}
};
});

View file

@ -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
}
};
});

View file

@ -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);
});
});
};
});

View file

@ -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;
}

View file

@ -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;
}
}
};
});

View file

@ -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;
});

View file

@ -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>

View file

@ -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
}
};
});

View file

@ -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;
}

View file

@ -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;
});

View file

@ -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'
});
});

View file

@ -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;
}
}

View file

@ -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") || "&#xE5CA;",
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') || '&#xE5CA;';
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'
});
});

View file

@ -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;
}

View file

@ -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'
});
});

View file

@ -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
}
};
});

View file

@ -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;
}

View file

@ -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'
});
});

View file

@ -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'
});
});

View file

@ -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'
});
});

View file

@ -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;
}

View file

@ -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;
});

View file

@ -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;
}

View file

@ -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'
});
});

View file

@ -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;
}

View file

@ -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 ? "&#xE5CB;" : "&#xE5CC;";
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' ? '&#xE5CB;' : '&#xE5CC;';
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'
});
});

View file

@ -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'
});
});

View file

@ -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;
}

View file

@ -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">&#xE313;</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">&#xE313;</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'
});
});

View file

@ -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;
}

View file

@ -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'
});
});

View file

@ -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;
}

View file

@ -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'
});
});

View file

@ -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;
}

View file

@ -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'
});
});

View file

@ -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;
}

View file

@ -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'
});
});

View file

@ -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
}
};
});

View file

@ -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;
}));
}
}
};
});

View file

@ -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();
}
}
};
});

View file

@ -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">&#xE5C4;</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">&#xE5C4;</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;
});

View file

@ -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;
}

File diff suppressed because one or more lines are too long

View file

@ -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
}
};
});

View file

@ -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%;
}

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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
});
});

View file

@ -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;
});

View file

@ -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
}
};
});

View file

@ -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
}
};
});

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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%);
}

View file

@ -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;
});

View file

@ -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">&#xE2C8;</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">&#xE316;</i></button>', currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="' + globalize.translate("sharedcomponents#Down") + '"><i class="md-icon">&#xE313;</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">&#xE2C8;</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">&#xE316;</i></button>';
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="' + globalize.translate('sharedcomponents#Down') + '"><i class="md-icon">&#xE313;</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;
});

View file

@ -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
}
};
});

View file

@ -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

View file

@ -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;
});

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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">&#xE5C4;</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">&#xE5C4;</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">&#xE2C0;</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">&#xE2C0;</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);
});
}
};
});

View file

@ -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;
}

View file

@ -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 += "&nbsp;", 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 += '&nbsp;';
}
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);
});
}
}
};
});

View file

@ -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
}
};
});

View file

@ -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;
});

View file

@ -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;
}
}

View file

@ -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);
});
}
}
};
});

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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">&#xE5CA;</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">&#xE5CA;</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">&#xE062;</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">&#xE062;</i>';
}
return item.SeriesTimerId ? "Cancelled" !== status ? '<i class="md-icon timerIndicator indicatorIcon">&#xE062;</i>' : '<i class="md-icon timerIndicator timerIndicator-inactive indicatorIcon">&#xE062;</i>' : '<i class="md-icon timerIndicator indicatorIcon">&#xE061;</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">&#xE062;</i>';
}
return '<i class="md-icon timerIndicator timerIndicator-inactive indicatorIcon">&#xE062;</i>';
}
return '<i class="md-icon timerIndicator indicatorIcon">&#xE061;</i>';
}
function getSyncIndicator(item) {
return 100 === item.SyncPercent ? '<div class="syncIndicator indicator fullSyncIndicator"><i class="md-icon indicatorIcon">&#xE2C4;</i></div>' : null != item.SyncPercent ? '<div class="syncIndicator indicator emptySyncIndicator"><i class="md-icon indicatorIcon">&#xE2C4;</i></div>' : ""
if (item.SyncPercent === 100) {
return '<div class="syncIndicator indicator fullSyncIndicator"><i class="md-icon indicatorIcon">&#xE2C4;</i></div>';
} else if (item.SyncPercent != null) {
return '<div class="syncIndicator indicator emptySyncIndicator"><i class="md-icon indicatorIcon">&#xE2C4;</i></div>';
}
return '';
}
function getTypeIndicator(item) {
return "Video" === item.Type ? '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon">&#xE04B;</i></div>' : "Folder" === item.Type || "PhotoAlbum" === item.Type ? '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon">&#xE2C7;</i></div>' : "Photo" === item.Type ? '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon">&#xE410;</i></div>' : ""
if (item.Type === 'Video') {
return '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon">&#xE04B;</i></div>';
}
if (item.Type === 'Folder' || item.Type === 'PhotoAlbum') {
return '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon">&#xE2C7;</i></div>';
}
if (item.Type === 'Photo') {
return '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon">&#xE410;</i></div>';
//return '<div class="indicator videoIndicator"><i class="md-icon indicatorIcon">&#xE412;</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