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

Merge pull request #1 from cvium/deuglify_webcomponents

Change webcomponents to non-minified version
This commit is contained in:
Joshua M. Boniface 2019-01-11 23:21:24 -05:00 committed by GitHub
commit 1a3b3bfa71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
224 changed files with 47151 additions and 23563 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 { .actionSheet {
display: flex; display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
padding: 0; padding: 0;
border: none; border: none;
max-height: 84%; max-height: 84%;
-webkit-border-radius: .1em !important; border-radius: .1em !important;
border-radius: .1em !important
} }
.actionsheet-not-fullscreen { .actionsheet-not-fullscreen {
max-width: 90%; max-width: 90%;
max-height: 90% max-height: 90%;
} }
.actionsheet-fullscreen { .actionsheet-fullscreen {
max-height: none; max-height: none;
-webkit-border-radius: 0 !important; border-radius: 0 !important;
border-radius: 0 !important
} }
.actionSheetContent-centered { .actionSheetContent-centered {
text-align: center; text-align: center;
-webkit-box-align: center; align-items: center;
-webkit-align-items: center;
align-items: center
} }
.actionSheetContent { .actionSheetContent {
margin: 0 !important; margin: 0 !important;
padding: .4em 0 !important; padding: .4em 0 !important;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
display: flex; display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1; flex-grow: 1;
overflow: hidden overflow: hidden;
} }
.actionSheetMenuItem { .actionSheetMenuItem {
font-weight: inherit; font-weight: inherit;
-webkit-box-shadow: none;
box-shadow: none; box-shadow: none;
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
.actionSheetMenuItem:focus { .actionSheetMenuItem:focus {
-webkit-transform: none !important; transform: none !important;
transform: none !important }
}
.actionsheetListItemBody { .actionsheetListItemBody {
padding: .4em 1em .4em .6em !important padding: .4em 1em .4em .6em !important;
} }
.actionSheetItemText { .actionSheetItemText {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis; text-overflow: ellipsis;
vertical-align: middle; vertical-align: middle;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1; flex-grow: 1;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-pack: start; justify-content: flex-start;
-webkit-justify-content: flex-start;
justify-content: flex-start
} }
.actionSheetItemAsideText { .actionSheetItemAsideText {
opacity: .7; opacity: .7;
font-size: 90%; font-size: 90%;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end; justify-content: flex-end;
-webkit-flex-shrink: 0;
flex-shrink: 0; flex-shrink: 0;
margin-left: 5em; margin-left: 5em;
margin-right: .5em margin-right: .5em;
} }
.actionSheetScroller { .actionSheetScroller {
/* Override default style being applied by polymer */
margin-bottom: 0 !important; margin-bottom: 0 !important;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
width: 100% width: 100%;
} }
.actionSheetScroller-tv { .actionSheetScroller-tv {
max-height: 64%; max-height: 64%;
max-width: 60%; max-width: 60%;
width: auto width: auto;
} }
.actionsheetDivider { .actionsheetDivider {
height: .07em; height: .07em;
margin: .25em 0; margin: .25em 0;
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
.actionSheetTitle { .actionSheetTitle {
margin: .6em 0 .7em !important; margin: .6em 0 .7em !important;
padding: 0 .9em; padding: 0 .9em;
-webkit-box-flex: 0; flex-grow: 0;
-webkit-flex-grow: 0;
flex-grow: 0
} }
.actionSheetText { .actionSheetText {
padding: 0 1em; padding: 0 1em;
-webkit-box-flex: 0; flex-grow: 0;
-webkit-flex-grow: 0;
flex-grow: 0
} }
.actionsheetMenuItemIcon { .actionsheetMenuItemIcon {
margin: 0 .85em 0 .45em !important; margin: 0 .85em 0 .45em !important;
padding: 0 !important padding: 0 !important;
} }
.actionsheet-xlargeFont { .actionsheet-xlargeFont {
font-size: 112% !important font-size: 112%!important;
} }
.btnCloseActionSheet { .btnCloseActionSheet {
position: fixed; position: fixed;
top: .75em; 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) { define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-button', 'css!./actionsheet', 'material-icons', 'scrollStyles', 'listViewStyle'], function (dialogHelper, layoutManager, globalize, browser, dom) {
"use strict"; 'use strict';
function getOffsets(elems) { function getOffsets(elems) {
var doc = document,
results = []; var doc = document;
if (!doc) return results; var results = [];
for (var box, elem, i = 0, length = elems.length; i < length; i++) elem = elems[i], box = elem.getBoundingClientRect ? elem.getBoundingClientRect() : {
top: 0, if (!doc) {
left: 0 return results;
}, results[i] = { }
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, top: box.top,
left: box.left, left: box.left,
width: box.width, width: box.width,
height: box.height height: box.height
}; };
return results }
return results;
} }
function getPosition(options, dlg) { function getPosition(options, dlg) {
var windowSize = dom.getWindowSize(),
windowHeight = windowSize.innerHeight, var windowSize = dom.getWindowSize();
windowWidth = windowSize.innerWidth; var windowHeight = windowSize.innerHeight;
if (windowWidth < 600 || windowHeight < 600) return null; var windowWidth = windowSize.innerWidth;
if (windowWidth < 600 || windowHeight < 600) {
return null;
}
var pos = getOffsets([options.positionTo])[0]; 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, if (options.positionY !== 'top') {
width = dlg.offsetWidth || 160; pos.top += (pos.height || 0) / 2;
pos.top -= height / 2, pos.left -= width / 2; }
var overflowX = pos.left + width - windowWidth,
overflowY = pos.top + height - windowHeight; pos.left += (pos.width || 0) / 2;
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
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) { function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
var fn = on ? "on" : "off"; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz) scrollHelper.centerFocus[fn](elem, horiz);
}) });
} }
function show(options) { function show(options) {
var isFullscreen, dialogOptions = {
removeOnClose: !0, // items
// positionTo
// showCancel
// title
var dialogOptions = {
removeOnClose: true,
enableHistory: options.enableHistory, 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 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 dlg = dialogHelper.createDialog(dialogOptions); 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 = "", if (isFullscreen) {
scrollClassName = layoutManager.tv ? "scrollY smoothScrollY hiddenScrollY" : "scrollY", dlg.classList.add('actionsheet-fullscreen');
style = ""; } 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) { if (options.items.length > 20) {
style += "min-width:" + (dom.getWindowSize().innerWidth >= 300 ? 240 : 200) + "px;" var minWidth = dom.getWindowSize().innerWidth >= 300 ? 240 : 200;
style += "min-width:" + minWidth + "px;";
} }
var i, length, option, itemIcon, renderIcon = !1,
icons = []; var i, length, option;
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 || ""); var renderIcon = false;
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 icons = [];
var center = options.title && !renderIcon; var itemIcon;
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>"); for (i = 0, length = options.items.length; i < length; i++) {
var scrollerClassName = "actionSheetScroller";
layoutManager.tv && (scrollerClassName += " actionSheetScroller-tv focuscontainer-x focuscontainer-y"), html += '<div class="' + scrollerClassName + " " + scrollClassName + '" style="' + style + '">'; option = options.items[i];
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++) itemIcon = option.icon || (option.selected ? 'check' : null);
if (option = options.items[i], option.divider) html += '<div class="actionsheetDivider"></div>';
else { if (itemIcon) {
var autoFocus = option.selected && layoutManager.tv ? " autoFocus" : "", renderIcon = true;
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>" icons.push(itemIcon || '');
} 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)
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);
}); });
var selectedId, timeout;
return options.timeout && (timeout = setTimeout(function() {
dialogHelper.close(dlg)
}, options.timeout)), 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")
})
} }
// 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');
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 { return {
show: show show: show
} };
}); });

View file

@ -1,18 +1,34 @@
define(["dialog", "globalize"], function(dialog, globalize) { define(['dialog', 'globalize'], function (dialog, globalize) {
"use strict"; 'use strict';
return function(text, title) {
return function (text, title) {
var options; var options;
options = "string" == typeof text ? { if (typeof text === 'string') {
options = {
title: title, title: title,
text: text text: text
} : text; };
var items = []; } else {
return items.push({ options = text;
name: globalize.translate("sharedcomponents#ButtonGotIt"),
id: "ok",
type: "submit"
}), options.buttons = items, dialog(options).then(function(result) {
return "ok" === result ? Promise.resolve() : Promise.reject()
})
} }
var items = [];
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() { define([], function () {
"use strict"; 'use strict';
function replaceAll(str, find, replace) { function replaceAll(str, find, replace) {
return str.split(find).join(replace)
return str.split(find).join(replace);
} }
return function(options) {
"string" == typeof options && (options = { return function (options) {
if (typeof options === 'string') {
options = {
text: options text: options
}); };
var text = replaceAll(options.text || "", "<br/>", "\n");
return alert(text), Promise.resolve()
} }
var text = replaceAll(options.text || '', '<br/>', '\n');
alert(text);
return Promise.resolve();
};
}); });

View file

@ -1,59 +1,130 @@
define(["dom", "focusManager"], function(dom, focusManager) { define(['dom', 'focusManager'], function (dom, focusManager) {
"use strict"; 'use strict';
var inputDisplayElement;
var currentDisplayText = '';
var currentDisplayTextContainer;
function onKeyDown(e) { function onKeyDown(e) {
if (!e.ctrlKey && !e.shiftKey && !e.altKey) {
var key = e.key, if (e.ctrlKey) {
chr = key ? alphanumeric(key) : null; return;
chr && (chr = chr.toString().toUpperCase(), 1 === chr.length && (currentDisplayTextContainer = this.options.itemsContainer, onAlphanumericKeyPress(e, chr))) }
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) { function alphanumeric(value) {
var letterNumber = /^[0-9a-zA-Z]+$/; var letterNumber = /^[0-9a-zA-Z]+$/;
return value.match(letterNumber) return value.match(letterNumber);
} }
function ensureInputDisplayElement() { 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() { function clearAlphaNumericShortcutTimeout() {
alpanumericShortcutTimeout && (clearTimeout(alpanumericShortcutTimeout), alpanumericShortcutTimeout = null) if (alpanumericShortcutTimeout) {
clearTimeout(alpanumericShortcutTimeout);
alpanumericShortcutTimeout = null;
}
} }
function resetAlphaNumericShortcutTimeout() { function resetAlphaNumericShortcutTimeout() {
clearAlphaNumericShortcutTimeout(), alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2e3) clearAlphaNumericShortcutTimeout();
alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2000);
} }
function onAlphanumericKeyPress(e, chr) { 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() { function onAlphanumericShortcutTimeout() {
var value = currentDisplayText, var value = currentDisplayText;
container = currentDisplayTextContainer; var container = currentDisplayTextContainer;
currentDisplayText = "", currentDisplayTextContainer = null, inputDisplayElement.innerHTML = "", inputDisplayElement.classList.add("hide"), clearAlphaNumericShortcutTimeout(), selectByShortcutValue(container, value)
currentDisplayText = '';
currentDisplayTextContainer = null;
inputDisplayElement.innerHTML = '';
inputDisplayElement.classList.add('hide');
clearAlphaNumericShortcutTimeout();
selectByShortcutValue(container, value);
} }
function selectByShortcutValue(container, value) { function selectByShortcutValue(container, value) {
value = value.toUpperCase(); value = value.toUpperCase();
var focusElem; 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) { function AlphaNumericShortcuts(options) {
this.options = options; this.options = options;
var keyDownHandler = onKeyDown.bind(this); var keyDownHandler = onKeyDown.bind(this);
dom.addEventListener(window, "keydown", keyDownHandler, {
passive: !0 dom.addEventListener(window, 'keydown', keyDownHandler, {
}), this.keyDownHandler = keyDownHandler passive: true
});
this.keyDownHandler = keyDownHandler;
} }
var inputDisplayElement, currentDisplayTextContainer, alpanumericShortcutTimeout, currentDisplayText = "";
return AlphaNumericShortcuts.prototype.destroy = function() { AlphaNumericShortcuts.prototype.destroy = function () {
var keyDownHandler = this.keyDownHandler; var keyDownHandler = this.keyDownHandler;
keyDownHandler && (dom.removeEventListener(window, "keydown", keyDownHandler, {
passive: !0 if (keyDownHandler) {
}), this.keyDownHandler = null), this.options = null dom.removeEventListener(window, 'keydown', keyDownHandler, {
}, AlphaNumericShortcuts 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) { define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-button-light', 'material-icons'], function (focusManager, layoutManager, dom) {
"use strict"; 'use strict';
var selectedButtonClass = 'alphaPickerButton-selected';
function focus() { function focus() {
var scope = this, var scope = this;
selected = scope.querySelector("." + selectedButtonClass); var selected = scope.querySelector('.' + selectedButtonClass);
selected ? focusManager.focus(selected) : focusManager.autoFocus(scope, !0)
if (selected) {
focusManager.focus(selected);
} else {
focusManager.autoFocus(scope, true);
}
} }
function getAlphaPickerButtonClassName(vertical) { 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) { 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) { 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) { function render(element, options) {
element.classList.add("alphaPicker"), layoutManager.tv && element.classList.add("alphaPicker-tv");
var vertical = element.classList.contains("alphaPicker-vertical"); element.classList.add('alphaPicker');
vertical || element.classList.add("focuscontainer-x");
var letters, html = "", if (layoutManager.tv) {
alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical), element.classList.add('alphaPicker-tv');
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
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) { 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() { function onItemFocusTimeout() {
itemFocusTimeout = null, self.value(itemFocusValue) itemFocusTimeout = null;
self.value(itemFocusValue);
} }
var alphaFocusedElement;
var alphaFocusTimeout;
function onAlphaFocusTimeout() { function onAlphaFocusTimeout() {
if (alphaFocusTimeout = null, document.activeElement === alphaFocusedElement) {
var value = alphaFocusedElement.getAttribute("data-value"); alphaFocusTimeout = null;
self.value(value, !0)
if (document.activeElement === alphaFocusedElement) {
var value = alphaFocusedElement.getAttribute('data-value');
self.value(value, true);
} }
} }
function onAlphaPickerInKeyboardModeClick(e) { function onAlphaPickerInKeyboardModeClick(e) {
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton");
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) { if (alphaPickerButton) {
var value = alphaPickerButton.getAttribute("data-value"); var value = alphaPickerButton.getAttribute('data-value');
element.dispatchEvent(new CustomEvent("alphavalueclicked", { element.dispatchEvent(new CustomEvent("alphavalueclicked", {
cancelable: !1, cancelable: false,
detail: { detail: {
value: value value: value
} }
})) }));
} }
} }
function onAlphaPickerClick(e) { function onAlphaPickerClick(e) {
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton");
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) { if (alphaPickerButton) {
var value = alphaPickerButton.getAttribute("data-value"); var value = alphaPickerButton.getAttribute('data-value');
(this._currentValue || "").toUpperCase() === value.toUpperCase() ? self.value(null, !0) : self.value(value, !0) if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
self.value(null, true);
} else {
self.value(value, true);
}
} }
} }
function onAlphaPickerFocusIn(e) { function onAlphaPickerFocusIn(e) {
alphaFocusTimeout && (clearTimeout(alphaFocusTimeout), alphaFocusTimeout = null);
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton"); if (alphaFocusTimeout) {
alphaPickerButton && (alphaFocusedElement = alphaPickerButton, alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600)) clearTimeout(alphaFocusTimeout);
alphaFocusTimeout = null;
}
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
alphaFocusedElement = alphaPickerButton;
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
}
} }
function onItemsFocusIn(e) { function onItemsFocusIn(e) {
var item = dom.parentWithClass(e.target, itemClass); var item = dom.parentWithClass(e.target, itemClass);
if (item) { if (item) {
var prefix = item.getAttribute("data-prefix"); var prefix = item.getAttribute('data-prefix');
prefix && prefix.length && (itemFocusValue = prefix[0], itemFocusTimeout && clearTimeout(itemFocusTimeout), itemFocusTimeout = setTimeout(onItemFocusTimeout, 100)) 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) { self.enabled = function (enabled) {
var btn, selected, element = this.options.element;
if (void 0 !== value) if (enabled) {
if (null != value) {
if (value = value.toUpperCase(), this._currentValue = value, "keyboard" !== this.options.mode) { if (itemsContainer) {
selected = element.querySelector("." + selectedButtonClass); itemsContainer.addEventListener('focus', onItemsFocusIn, true);
}
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));
}
};
render(element, options);
this.enabled(true);
this.visible(true);
}
AlphaPicker.prototype.value = function (value, applyValue) {
var element = this.options.element;
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 { try {
btn = element.querySelector(".alphaPickerButton[data-value='" + value + "']") btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']');
} catch (err) { } catch (err) {
console.log("Error in querySelector: " + err) console.log('Error in querySelector: ' + err);
} }
btn && btn !== selected && btn.classList.add(selectedButtonClass), selected && selected !== btn && selected.classList.remove(selectedButtonClass)
if (btn && btn !== selected) {
btn.classList.add(selectedButtonClass);
} }
} else this._currentValue = value, (selected = element.querySelector("." + selectedButtonClass)) && selected.classList.remove(selectedButtonClass); if (selected && selected !== btn) {
return applyValue && element.dispatchEvent(new CustomEvent("alphavaluechanged", { selected.classList.remove(selectedButtonClass);
cancelable: !1, }
}
} else {
this._currentValue = value;
selected = element.querySelector('.' + selectedButtonClass);
if (selected) {
selected.classList.remove(selectedButtonClass);
}
}
}
if (applyValue) {
element.dispatchEvent(new CustomEvent("alphavaluechanged", {
cancelable: false,
detail: { detail: {
value: value value: value
} }
})), this._currentValue }));
}, AlphaPicker.prototype.on = function(name, fn) { }
this.options.element.addEventListener(name, fn)
}, AlphaPicker.prototype.off = function(name, fn) { return this._currentValue;
this.options.element.removeEventListener(name, fn) };
}, AlphaPicker.prototype.visible = function(visible) {
this.options.element.style.visibility = visible ? "visible" : "hidden" AlphaPicker.prototype.on = function (name, fn) {
}, 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() {
var element = this.options.element; var element = this.options.element;
focusManager.autoFocus(element, !0) element.addEventListener(name, fn);
}, AlphaPicker.prototype.destroy = function() { };
AlphaPicker.prototype.off = function (name, fn) {
var element = this.options.element; var element = this.options.element;
this.enabled(!1), element.classList.remove("focuscontainer-x"), this.options = null element.removeEventListener(name, fn);
}, AlphaPicker };
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 { .alphaPicker {
text-align: center; text-align: center;
display: flex; display: flex;
-webkit-box-orient: vertical;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
-webkit-align-self: center; align-self: center;
align-self: center
} }
.alphaPicker-vertical { .alphaPicker-vertical {
line-height: 1 line-height: 1;
} }
.alphaPicker-fixed { .alphaPicker-fixed {
position: fixed; position: fixed;
bottom: 5.5em; bottom: 5.5em;
z-index: 999999 z-index: 999999;
} }
.alphaPickerRow { .alphaPickerRow {
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
-webkit-box-orient: horizontal; flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row
} }
.alphaPickerRow-vertical { .alphaPickerRow-vertical {
-webkit-box-orient: vertical; flex-direction: column;
-webkit-flex-direction: column;
flex-direction: column
} }
.alphaPickerButton { .alphaPickerButton {
border: 0 !important; border: 0 !important;
cursor: pointer; cursor: pointer;
outline: 0 !important; outline: none !important;
vertical-align: middle; vertical-align: middle;
font-family: inherit; font-family: inherit;
font-size: inherit; font-size: inherit;
@ -61,103 +37,103 @@
margin: 0; margin: 0;
padding: .1em .4em; padding: .1em .4em;
width: auto; width: auto;
-webkit-border-radius: .1em;
border-radius: .1em; border-radius: .1em;
font-weight: 400; font-weight: normal;
-webkit-flex-shrink: 0;
flex-shrink: 0; flex-shrink: 0;
-webkit-box-flex: 1; flex-grow: 1;
-webkit-flex-grow: 1;
flex-grow: 1
} }
@media all and (max-height:50em) { @media all and (max-height: 50em) {
.alphaPicker-fixed { .alphaPicker-fixed {
bottom: 5em bottom: 5em;
} }
.alphaPickerButton-vertical { .alphaPickerButton-vertical {
padding-top: 1px !important; 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 { .alphaPicker-vertical {
font-size: 94% font-size: 94%;
} }
} }
@media all and (max-height:44em) { @media all and (max-height: 44em) {
.alphaPicker-vertical { .alphaPicker-vertical {
font-size: 90% font-size: 90%;
} }
.alphaPickerButton-vertical { .alphaPickerButton-vertical {
padding-top: 0 !important; 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 { .alphaPicker-vertical {
font-size: 82% font-size: 82%;
} }
} }
@media all and (max-height:32em) { @media all and (max-height: 32em) {
.alphaPicker-vertical { .alphaPicker-vertical {
font-size: 74% font-size: 74%;
} }
} }
.alphaPicker-vertical.alphaPicker-tv { .alphaPicker-vertical.alphaPicker-tv {
font-size: 86% font-size: 86%;
} }
.alphaPickerButton-tv.alphaPickerButton-vertical { .alphaPickerButton-tv.alphaPickerButton-vertical {
padding: 0 padding: 0;
} }
.alphaPickerButton-vertical { .alphaPickerButton-vertical {
/* Assign a fixed width to ensure they have the same dimensions and avoid throwing off directional navigation */
width: 1.5em; width: 1.5em;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
text-align: center text-align: center;
} }
.alphaPickerButtonIcon { .alphaPickerButtonIcon {
font-size: 100% !important font-size: 100% !important;
} }
.alphaPicker-fixed.alphaPicker-tv { .alphaPicker-fixed.alphaPicker-tv {
bottom: 1% bottom: 1%;
} }
.alphaPicker-fixed-left { .alphaPicker-fixed-left {
left: .4em left: .4em;
} }
.alphaPicker-fixed-right { .alphaPicker-fixed-right {
right: .4em right: .4em;
} }
@media all and (min-width:62.5em) { @media all and (min-width: 62.5em) {
.alphaPicker-fixed-left { .alphaPicker-fixed-left {
left: 1em left: 1em;
} }
.alphaPicker-fixed-right { .alphaPicker-fixed-right {
right: 1em right: 1em;
} }
} }
@media all and (max-height:31.25em) { @media all and (max-height: 31.25em) {
.alphaPicker-fixed { .alphaPicker-fixed {
display: none !important display: none !important;
} }
} }

View file

@ -1,16 +1,13 @@
.appfooter { .appfooter {
position: fixed; position: fixed;
left: 0; left: 0;
right: 0; right: 0;
z-index: 1; z-index: 1;
bottom: 0; bottom: 0;
-webkit-transition: -webkit-transform 180ms linear;
-o-transition: transform 180ms linear;
transition: transform 180ms linear; transition: transform 180ms linear;
contain: layout style contain: layout style;
} }
.appfooter.headroom--unpinned { .appfooter.headroom--unpinned {
-webkit-transform: translateY(100%) !important; transform: translateY(100%)!important;
transform: translateY(100%) !important }
}

View file

@ -1,20 +1,46 @@
define(["browser", "css!./appfooter"], function(browser) { define(['browser', 'css!./appfooter'], function (browser) {
"use strict"; 'use strict';
function render(options) { 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) { function appFooter(options) {
var self = this; var self = this;
self.element = render(options), self.add = function(elem) {
self.element.appendChild(elem) self.element = render(options);
}, self.insert = function(elem) {
"string" == typeof elem ? self.element.insertAdjacentHTML("afterbegin", elem) : self.element.insertBefore(elem, self.element.firstChild) 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.prototype.destroy = function () {
}, appFooter var self = this;
self.element = null;
};
return appFooter;
}); });

View file

@ -1,39 +1,156 @@
define(["appStorage", "events"], function(appStorage, events) { define(['appStorage', 'events'], function (appStorage, events) {
"use strict"; 'use strict';
function getKey(name, userId) { function getKey(name, userId) {
return userId && (name = userId + "-" + name), name
if (userId) {
name = userId + '-' + name;
} }
function AppSettings() {} return name;
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) { function AppSettings() {
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; AppSettings.prototype.enableAutoLogin = function (val) {
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) { if (val != null) {
void 0 !== val && this.set("maxStaticMusicBitrate", val); this.set('enableAutoLogin', val.toString());
var defaultValue = 32e4; }
return parseInt(this.get("maxStaticMusicBitrate") || defaultValue.toString()) || defaultValue
}, AppSettings.prototype.maxChromecastBitrate = function(val) { return this.get('enableAutoLogin') !== 'false';
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.enableAutomaticBitrateDetection = function (isInNetwork, mediaType, val) {
}, AppSettings.prototype.syncPath = function(val) {
return null != val && this.set("syncPath", val), this.get("syncPath") var key = 'enableautobitratebitrate-' + mediaType + '-' + isInNetwork;
}, AppSettings.prototype.cameraUploadServers = function(val) {
return null != val && this.set("cameraUploadServers", val.join(",")), val = this.get("cameraUploadServers"), val ? val.split(",") : [] if (val != null) {
}, AppSettings.prototype.runAtStartup = function(val) {
return null != val && this.set("runatstartup", val.toString()), "true" === this.get("runatstartup") if (isInNetwork && mediaType === 'Audio') {
}, AppSettings.prototype.set = function(name, value, userId) { 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); 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) { appStorage.setItem(getKey(name, userId), value);
return appStorage.getItem(getKey(name, userId))
}, AppSettings.prototype.enableSystemExternalPlayers = function(val) { if (currentValue !== value) {
return null != val && this.set("enableSystemExternalPlayers", val.toString()), "true" === this.get("enableSystemExternalPlayers") events.trigger(this, 'change', [name]);
}, new AppSettings }
};
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) { define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./style'], function (browser, connectionManager, playbackManager, dom) {
"use strict"; 'use strict';
function enableAnimation(elem) { function enableAnimation(elem) {
return !browser.slow
if (browser.slow) {
return false;
}
return true;
} }
function enableRotation() { function enableRotation() {
return !browser.tv && !browser.firefox
if (browser.tv) {
return false;
} }
function Backdrop() {} // Causes high cpu usage
if (browser.firefox) {
return false;
}
return true;
}
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() { 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) { function clearBackdrop(clearAll) {
clearRotation(), currentLoadingBackdrop && (currentLoadingBackdrop.destroy(), currentLoadingBackdrop = null), getBackdropContainer().innerHTML = "", clearAll && (hasExternalBackdrop = !1), internalBackdrop(!1)
clearRotation();
if (currentLoadingBackdrop) {
currentLoadingBackdrop.destroy();
currentLoadingBackdrop = null;
} }
var elem = getBackdropContainer();
elem.innerHTML = '';
if (clearAll) {
hasExternalBackdrop = false;
}
internalBackdrop(false);
}
var backgroundContainer;
function getBackgroundContainer() { function getBackgroundContainer() {
return backgroundContainer || (backgroundContainer = document.querySelector(".backgroundContainer")), backgroundContainer if (!backgroundContainer) {
backgroundContainer = document.querySelector('.backgroundContainer');
}
return backgroundContainer;
} }
function setBackgroundContainerBackgroundEnabled() { function setBackgroundContainerBackgroundEnabled() {
hasInternalBackdrop || hasExternalBackdrop ? getBackgroundContainer().classList.add("withBackdrop") : getBackgroundContainer().classList.remove("withBackdrop")
if (hasInternalBackdrop || hasExternalBackdrop) {
getBackgroundContainer().classList.add('withBackdrop');
} else {
getBackgroundContainer().classList.remove('withBackdrop');
}
} }
var hasInternalBackdrop;
function internalBackdrop(enabled) { function internalBackdrop(enabled) {
hasInternalBackdrop = enabled, setBackgroundContainerBackgroundEnabled() hasInternalBackdrop = enabled;
setBackgroundContainerBackgroundEnabled();
} }
var hasExternalBackdrop;
function externalBackdrop(enabled) { function externalBackdrop(enabled) {
hasExternalBackdrop = enabled, setBackgroundContainerBackgroundEnabled() hasExternalBackdrop = enabled;
setBackgroundContainerBackgroundEnabled();
} }
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
var currentLoadingBackdrop;
function setBackdropImage(url) { function setBackdropImage(url) {
currentLoadingBackdrop && (currentLoadingBackdrop.destroy(), currentLoadingBackdrop = null);
var elem = getBackdropContainer(), if (currentLoadingBackdrop) {
existingBackdropImage = elem.querySelector(".displayingBackdropImage"); currentLoadingBackdrop.destroy();
if (existingBackdropImage && existingBackdropImage.getAttribute("data-url") === url) { currentLoadingBackdrop = null;
if (existingBackdropImage.getAttribute("data-url") === url) return;
existingBackdropImage.classList.remove("displayingBackdropImage")
}
var instance = new Backdrop;
instance.load(url, elem, existingBackdropImage), currentLoadingBackdrop = instance
} }
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() { function getBackdropMaxWidth() {
var width = dom.getWindowSize().innerWidth; 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) { function getItemImageUrls(item, imageOptions) {
imageOptions = imageOptions || {}; imageOptions = imageOptions || {};
var apiClient = connectionManager.getApiClient(item.ServerId); var apiClient = connectionManager.getApiClient(item.ServerId);
return item.BackdropImageTags && item.BackdropImageTags.length > 0 ? item.BackdropImageTags.map(function(imgTag, 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, { return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
type: "Backdrop", type: "Backdrop",
tag: imgTag, tag: imgTag,
maxWidth: getBackdropMaxWidth(), maxWidth: getBackdropMaxWidth(),
index: index index: index
})) }));
}) : item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length ? item.ParentBackdropImageTags.map(function(imgTag, index) { });
}
if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
return item.ParentBackdropImageTags.map(function (imgTag, index) {
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, { return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
type: "Backdrop", type: "Backdrop",
tag: imgTag, tag: imgTag,
maxWidth: getBackdropMaxWidth(), maxWidth: getBackdropMaxWidth(),
index: index index: index
})) }));
}) : [] });
}
return [];
} }
function getImageUrls(items, imageOptions) { function getImageUrls(items, imageOptions) {
for (var list = [], onImg = function(img) {
list.push(img) var list = [];
}, i = 0, length = items.length; i < length; i++) {
getItemImageUrls(items[i], imageOptions).forEach(onImg) 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) { function arraysEqual(a, b) {
if (a === b) return !0; if (a === b) {
if (null == a || null == b) return !1; return true;
if (a.length !== b.length) return !1; }
for (var i = 0; i < a.length; ++i) if (a == null || b == null) {
if (a[i] !== b[i]) return !1; return false;
return !0 }
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) { function setBackdrops(items, imageOptions, enableImageRotation) {
var images = getImageUrls(items, imageOptions); var images = getImageUrls(items, imageOptions);
images.length ? startRotation(images, enableImageRotation) : clearBackdrop()
if (images.length) {
startRotation(images, enableImageRotation);
} else {
clearBackdrop();
}
} }
function startRotation(images, enableImageRotation) { 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() { function onRotationInterval() {
if (!playbackManager.isPlayingLocally(["Video"])) {
var newIndex = currentRotationIndex + 1; if (playbackManager.isPlayingLocally(['Video'])) {
newIndex >= currentRotatingImages.length && (newIndex = 0), currentRotationIndex = newIndex, setBackdropImage(currentRotatingImages[newIndex]) return;
} }
var newIndex = currentRotationIndex + 1;
if (newIndex >= currentRotatingImages.length) {
newIndex = 0;
}
currentRotationIndex = newIndex;
setBackdropImage(currentRotatingImages[newIndex]);
} }
function clearRotation() { function clearRotation() {
var interval = rotationInterval; var interval = rotationInterval;
interval && clearInterval(interval), rotationInterval = null, currentRotatingImages = [], currentRotationIndex = -1 if (interval) {
clearInterval(interval);
}
rotationInterval = null;
currentRotatingImages = [];
currentRotationIndex = -1;
} }
function setBackdrop(url, imageOptions) { function setBackdrop(url, imageOptions) {
url && "string" != typeof url && (url = getImageUrls([url], imageOptions)[0]), url ? (clearRotation(), setBackdropImage(url)) : clearBackdrop()
if (url) {
if (typeof url !== 'string') {
url = getImageUrls([url], imageOptions)[0];
} }
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)
} }
}, img.src = url
}, Backdrop.prototype.cancelAnimation = function() { if (url) {
var elem = this.currentAnimatingElement; clearRotation();
elem && (elem.classList.remove("backdropImageFadeIn"), this.currentAnimatingElement = null)
}, Backdrop.prototype.destroy = function() { setBackdropImage(url);
this.isDestroyed = !0, this.cancelAnimation()
}; } else {
var backdropContainer, backgroundContainer, hasInternalBackdrop, hasExternalBackdrop, currentLoadingBackdrop, rotationInterval, standardWidths = [480, 720, 1280, 1440, 1920], clearBackdrop();
currentRotatingImages = [], }
currentRotationIndex = -1; }
return { return {
setBackdrops: setBackdrops, setBackdrops: setBackdrops,
setBackdrop: setBackdrop, setBackdrop: setBackdrop,
clear: clearBackdrop, clear: clearBackdrop,
externalBackdrop: externalBackdrop externalBackdrop: externalBackdrop
} };
}); });

View file

@ -1,41 +1,29 @@
.backdropContainer { .backdropContainer {
contain: layout style size contain: layout style size;
} }
.backdropImage { .backdropImage {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center center; background-position: center center;
-webkit-background-size: cover;
background-size: cover; background-size: cover;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
contain: layout style contain: layout style;
} }
.backdropImageFadeIn { .backdropImageFadeIn {
-webkit-animation: backdrop-fadein .8s ease-in normal both; animation: backdrop-fadein 800ms ease-in normal both;
animation: backdrop-fadein .8s ease-in normal both
}
@-webkit-keyframes backdrop-fadein {
from {
opacity: 0
}
to {
opacity: 1
}
} }
@keyframes backdrop-fadein { @keyframes backdrop-fadein {
from { from {
opacity: 0 opacity: 0;
} }
to { to {
opacity: 1 opacity: 1;
} }
} }

View file

@ -1,69 +1,310 @@
define([], function() { define([], function () {
"use strict"; 'use strict';
function supportsCssAnimation(allowPrefix) { function isTv() {
if (allowPrefix) {
if (!0 === _supportsCssAnimationWithPrefix || !1 === _supportsCssAnimationWithPrefix) return _supportsCssAnimationWithPrefix // This is going to be really difficult to get right
} else if (!0 === _supportsCssAnimation || !1 === _supportsCssAnimation) return _supportsCssAnimation; var userAgent = navigator.userAgent.toLowerCase();
var animation = !1,
domPrefixes = ["Webkit", "O", "Moz"], if (userAgent.indexOf('tv') !== -1) {
pfx = "", return true;
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
} }
var _supportsCssAnimation, _supportsCssAnimationWithPrefix, userAgent = navigator.userAgent,
matched = function(ua) { 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;
}
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;
}
}
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;
}
} else {
if (_supportsCssAnimation === true || _supportsCssAnimation === false) {
return _supportsCssAnimation;
}
}
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(); 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), var match = /(edge)[ \/]([\w.]+)/.exec(ua) ||
platform_match = /(ipad)/.exec(ua) || /(iphone)/.exec(ua) || /(windows)/.exec(ua) || /(android)/.exec(ua) || [], /(opera)[ \/]([\w.]+)/.exec(ua) ||
browser = match[1] || ""; /(opr)[ \/]([\w.]+)/.exec(ua) ||
"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"); /(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; var version;
versionMatch && versionMatch.length > 2 && (version = versionMatch[2]), version = version || match[2] || "0"; if (versionMatch && versionMatch.length > 2) {
var versionMajor = parseInt(version.split(".")[0]); version = versionMatch[2];
return isNaN(versionMajor) && (versionMajor = 0), { }
version = version || match[2] || "0";
var versionMajor = parseInt(version.split('.')[0]);
if (isNaN(versionMajor)) {
versionMajor = 0;
}
return {
browser: browser, browser: browser,
version: version, version: version,
platform: platform_match[0] || "", platform: platform_match[0] || "",
versionMajor: versionMajor 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;
} }
}(userAgent),
browser = {}; if (matched.platform) {
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), browser[matched.platform] = true;
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
} }
}("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))) if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf("webkit") !== -1) {
}(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() { browser.safari = true;
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)]
} }
}(), browser.iOSVersion = browser.iOSVersion[0] + browser.iOSVersion[1] / 10), browser.chromecast = browser.chrome && -1 !== userAgent.toLowerCase().indexOf("crkey"), browser
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) { define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) {
"use strict"; 'use strict';
function buildChapterCardsHtml(item, chapters, options) { function buildChapterCardsHtml(item, chapters, options) {
var className = "card itemAction chapterCard";
layoutManager.tv && (browser.animate || browser.edge) && (className += " card-focusscale"); var className = 'card itemAction chapterCard';
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [],
videoStream = mediaStreams.filter(function(i) { if (layoutManager.tv && (browser.animate || browser.edge)) {
return "Video" === i.Type className += ' card-focusscale';
})[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>")
} }
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) { function getImgUrl(item, chapter, index, maxWidth, apiClient) {
return chapter.ImageTag ? apiClient.getScaledImageUrl(item.Id, {
if (chapter.ImageTag) {
return apiClient.getScaledImageUrl(item.Id, {
maxWidth: maxWidth, maxWidth: maxWidth,
tag: chapter.ImageTag, tag: chapter.ImageTag,
type: "Chapter", type: "Chapter",
index: index index: index
}) : null });
}
return null;
} }
function buildChapterCard(item, apiClient, chapter, index, options, className, shape) { 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"; var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient);
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 cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
cardImageContainer = imgUrl ? '<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">' : '<div class="' + cardImageContainerClass + '">'; if (options.coverImage) {
imgUrl || (cardImageContainer += '<i class="md-icon cardImageIcon">local_movies</i>'); cardImageContainerClass += ' coveredImage';
var nameHtml = ""; }
nameHtml += '<div class="cardText">' + chapter.Name + "</div>", nameHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + "</div>"; 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 cardBoxCssClass = "cardBox", var cardImageContainer = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
cardScalableClass = "cardScalable";
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) { if (layoutManager.tv) {
var enableFocusTransfrom = !browser.slow && !browser.edge; 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) { function buildChapterCards(item, chapters, options) {
if (options.parentContainer) { if (options.parentContainer) {
if (!document.body.contains(options.parentContainer)) return; // Abort if the container has been disposed
if (!chapters.length) return void options.parentContainer.classList.add("hide"); if (!document.body.contains(options.parentContainer)) {
options.parentContainer.classList.remove("hide") return;
} }
if (chapters.length) {
options.parentContainer.classList.remove('hide');
} else {
options.parentContainer.classList.add('hide');
return;
}
}
var html = buildChapterCardsHtml(item, chapters, options); var html = buildChapterCardsHtml(item, chapters, options);
options.itemsContainer.innerHTML = html, imageLoader.lazyChildren(options.itemsContainer)
options.itemsContainer.innerHTML = html;
imageLoader.lazyChildren(options.itemsContainer);
} }
return { return {
buildChapterCards: buildChapterCards buildChapterCards: buildChapterCards
} };
}); });

View file

@ -1,18 +1,22 @@
define(["cardBuilder"], function(cardBuilder) { define(['cardBuilder'], function (cardBuilder) {
"use strict"; 'use strict';
function buildPeopleCards(items, options) { function buildPeopleCards(items, options) {
options = Object.assign(options || {}, { options = Object.assign(options || {}, {
cardLayout: !1, cardLayout: false,
centerText: !0, centerText: true,
showTitle: !0, showTitle: true,
cardFooterAside: "none", cardFooterAside: 'none',
showPersonRoleOrType: !0, showPersonRoleOrType: true,
cardCssClass: "personCard", cardCssClass: 'personCard',
defaultCardImageIcon: "&#xE7FD;" defaultCardImageIcon: '&#xE7FD;'
}), cardBuilder.buildCards(items, options) });
cardBuilder.buildCards(items, options);
} }
return { return {
buildPeopleCards: buildPeopleCards buildPeopleCards: buildPeopleCards
} };
}); });

View file

@ -1,10 +1,7 @@
.card-round:focus>.cardBox-focustransform { .card-round:focus > .cardBox-focustransform {
-webkit-transform: scale(1.26, 1.26); transform: scale(1.26, 1.26);
transform: scale(1.26, 1.26)
} }
.cardImage-round, .cardImageContainer-round, .cardImage-round {
.cardImageContainer-round { border-radius: 1000px;
-webkit-border-radius: 1000px;
border-radius: 1000px
} }

View file

@ -1,67 +1,228 @@
define(["events"], function(events) { define(['events'], function (events) {
"use strict"; '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) { function isValidIpAddress(address) {
return 1 == LinkParser.parse(address).length
var links = LinkParser.parse(address);
return links.length == 1;
} }
function isLocalIpAddress(address) { 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) { function getServerAddress(apiClient) {
var serverAddress = apiClient.serverAddress(); 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); var cachedValue = getCachedValue(serverAddress);
return cachedValue ? Promise.resolve(cachedValue) : apiClient.getEndpointInfo().then(function(endpoint) { if (cachedValue) {
return endpoint.IsInNetwork ? apiClient.getPublicSystemInfo().then(function(info) { return Promise.resolve(cachedValue);
return addToCache(serverAddress, info.LocalAddress), info.LocalAddress }
}) : (addToCache(serverAddress, serverAddress), serverAddress)
}) 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() { function clearCache() {
cache = {} cache = {};
} }
function addToCache(key, value) { function addToCache(key, value) {
cache[key] = { cache[key] = {
value: value, value: value,
time: (new Date).getTime() time: new Date().getTime()
} };
} }
function getCachedValue(key) { function getCachedValue(key) {
var obj = cache[key]; var obj = cache[key];
return obj && (new Date).getTime() - obj.time < 18e4 ? obj.value : null
}! function() { if (obj && (new Date().getTime() - obj.time) < 180000) {
function ensureProtocol(url) { return obj.value;
return url.match(protocolRegExp) || (url = "http://" + url), url
} }
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"), return null;
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
} events.on(ConnectionManager, 'localusersignedin', clearCache);
}; events.on(ConnectionManager, 'localusersignedout', clearCache);
window.LinkParser = LinkParser
}(); return {
var cache = {};
return events.on(ConnectionManager, "localusersignedin", clearCache), events.on(ConnectionManager, "localusersignedout", clearCache), {
getServerAddress: getServerAddress getServerAddress: getServerAddress
} };
}); });

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
.clearButton { .clearButton {
background: 0 0; background: transparent;
border: 0 !important; border: 0 !important;
padding: 0 !important; padding: 0 !important;
cursor: pointer; cursor: pointer;
outline: 0 !important; outline: none !important;
color: inherit; color: inherit;
width: 100%; width: 100%;
vertical-align: middle; vertical-align: middle;
font-family: inherit; 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) { 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"; 'use strict';
var currentServerId;
function parentWithClass(elem, className) { function parentWithClass(elem, className) {
for (; !elem.classList || !elem.classList.contains(className);)
if (!(elem = elem.parentNode)) return null; while (!elem.classList || !elem.classList.contains(className)) {
return elem elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
} }
function onSubmit(e) { function onSubmit(e) {
loading.show(); loading.show();
var panel = parentWithClass(this, "dialog"),
collectionId = panel.querySelector("#selectCollectionToAddTo").value, var panel = parentWithClass(this, 'dialog');
apiClient = connectionManager.getApiClient(currentServerId);
return collectionId ? addToCollection(apiClient, panel, collectionId) : createCollection(apiClient, panel), e.preventDefault(), !1 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) { function createCollection(apiClient, dlg) {
var url = apiClient.getUrl("Collections", { var url = apiClient.getUrl("Collections", {
Name: dlg.querySelector("#txtNewCollectionName").value,
IsLocked: !dlg.querySelector("#chkEnableInternetMetadata").checked, Name: dlg.querySelector('#txtNewCollectionName').value,
Ids: dlg.querySelector(".fldSelectedItemIds").value || "" IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked,
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
}); });
apiClient.ajax({ apiClient.ajax({
type: "POST", type: "POST",
url: url, url: url,
dataType: "json" dataType: "json"
}).then(function(result) {
}).then(function (result) {
loading.hide(); loading.hide();
var id = result.Id; 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) { function redirectToCollection(apiClient, id) {
appRouter.showItem(id, apiClient.serverId())
appRouter.showItem(id, apiClient.serverId());
} }
function addToCollection(apiClient, dlg, id) { function addToCollection(apiClient, dlg, id) {
var url = apiClient.getUrl("Collections/" + id + "/Items", { var url = apiClient.getUrl("Collections/" + id + "/Items", {
Ids: dlg.querySelector(".fldSelectedItemIds").value || ""
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
}); });
apiClient.ajax({ apiClient.ajax({
type: "POST", type: "POST",
url: url url: url
}).then(function() {
loading.hide(), dlg.submitted = !0, dialogHelper.close(dlg), require(["toast"], function(toast) { }).then(function () {
toast(globalize.translate("sharedcomponents#MessageItemsAdded"))
}) loading.hide();
})
dlg.submitted = true;
dialogHelper.close(dlg);
require(['toast'], function (toast) {
toast(globalize.translate('sharedcomponents#MessageItemsAdded'));
});
});
} }
function triggerChange(select) { function triggerChange(select) {
select.dispatchEvent(new CustomEvent("change", {})) select.dispatchEvent(new CustomEvent('change', {}));
} }
function populateCollections(panel) { function populateCollections(panel) {
loading.show(); 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 = { var options = {
Recursive: !0,
Recursive: true,
IncludeItemTypes: "BoxSet", IncludeItemTypes: "BoxSet",
SortBy: "SortName", SortBy: "SortName",
EnableTotalRecordCount: !1 EnableTotalRecordCount: false
}, };
apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function(result) { var apiClient = connectionManager.getApiClient(currentServerId);
var html = ""; apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) {
html += '<option value="">' + globalize.translate("sharedcomponents#OptionNew") + "</option>", html += result.Items.map(function(i) {
return '<option value="' + i.Id + '">' + i.Name + "</option>" var html = '';
}), select.innerHTML = html, select.value = "", triggerChange(select), loading.hide()
}) 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() { 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) { 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('#selectCollectionToAddTo').addEventListener('change', function () {
}), content.querySelector("form").addEventListener("submit", onSubmit), content.querySelector(".fldSelectedItemIds", content).value = items.join(","), items.length) content.querySelector(".fldSelectCollection").classList.remove("hide"), populateCollections(content); if (this.value) {
else { content.querySelector('.newCollectionInfo').classList.add('hide');
content.querySelector(".fldSelectCollection").classList.add("hide"); content.querySelector('#txtNewCollectionName').removeAttribute('required');
var selectCollectionToAddTo = content.querySelector("#selectCollectionToAddTo"); } else {
selectCollectionToAddTo.innerHTML = "", selectCollectionToAddTo.value = "", triggerChange(selectCollectionToAddTo) 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) { function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
var fn = on ? "on" : "off"; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz) scrollHelper.centerFocus[fn](elem, horiz);
}) });
} }
function CollectionEditor() {} function CollectionEditor() {
var currentServerId;
return CollectionEditor.prototype.show = function(options) { }
CollectionEditor.prototype.show = function (options) {
var items = options.items || {}; var items = options.items || {};
currentServerId = options.serverId; currentServerId = options.serverId;
var dialogOptions = { var dialogOptions = {
removeOnClose: !0, removeOnClose: true,
scrollY: !1 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); var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog");
var html = "", dlg.classList.add('formDialog');
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() { var html = '';
dialogHelper.close(dlg) var title = items.length ? globalize.translate('sharedcomponents#HeaderAddToCollection') : globalize.translate('sharedcomponents#NewCollection');
}), 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() html += '<div class="formDialogHeader">';
}) html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button>';
}, CollectionEditor 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) { define(['dialog', 'globalize'], function (dialog, globalize) {
"use strict"; 'use strict';
return function(text, title) {
return function (text, title) {
var options; var options;
options = "string" == typeof text ? { if (typeof text === 'string') {
options = {
title: title, title: title,
text: text text: text
} : text; };
var items = []; } else {
return items.push({ options = text;
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()
})
} }
var items = [];
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() { define([], function () {
"use strict"; 'use strict';
function replaceAll(str, find, replace) { function replaceAll(str, find, replace) {
return str.split(find).join(replace)
return str.split(find).join(replace);
} }
return function(options) {
"string" == typeof options && (options = { return function (options) {
title: "",
if (typeof options === 'string') {
options = {
title: '',
text: options text: options
}); };
var text = replaceAll(options.text || "", "<br/>", "\n");
return confirm(text) ? Promise.resolve() : Promise.reject()
} }
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) { define(['globalize'], function (globalize) {
"use strict"; 'use strict';
function parseISO8601Date(s, toLocal) { 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); // parenthese matches:
if (!d) throw "Couldn't parse ISO 8601 date string '" + s + "'"; // 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]; 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]); 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]); 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; // if there are milliseconds, add them
d[11] && (offset += 60 * d[11] * 1e3), "-" === d[9] ? ms -= offset : ms += offset if (d[7] > 0) {
} else !1 === toLocal && (ms += 6e4 * (new Date).getTimezoneOffset()); ms += Math.round(d[7] * 1000);
return new Date(ms) }
// 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) { function getDisplayRunningTime(ticks) {
var parts = [], var ticksPerHour = 36000000000;
hours = ticks / 36e9; var ticksPerMinute = 600000000;
hours = Math.floor(hours), hours && parts.push(hours), ticks -= 36e9 * hours; var ticksPerSecond = 10000000;
var minutes = ticks / 6e8;
minutes = Math.floor(minutes), ticks -= 6e8 * minutes, minutes < 10 && hours && (minutes = "0" + minutes), parts.push(minutes); var parts = [];
var seconds = ticks / 1e7;
return seconds = Math.floor(seconds), seconds < 10 && (seconds = "0" + seconds), parts.push(seconds), parts.join(":") 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) { function getOptionList(options) {
var list = []; var list = [];
for (var i in options) list.push({
for (var i in options) {
list.push({
name: i, name: i,
value: options[i] value: options[i]
}); });
return list }
return list;
} }
function toLocaleString(date, options) { function toLocaleString(date, options) {
if (!date) throw new Error("date cannot be null");
if (options = options || {}, toLocaleTimeStringSupportsLocales) { if (!date) {
var currentLocale = globalize.getCurrentDateTimeLocale(); throw new Error('date cannot be null');
if (currentLocale) return date.toLocaleString(currentLocale, options)
} }
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) { 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(); 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); var optionList = getOptionList(options);
if (1 === optionList.length && "weekday" === optionList[0].name) { if (optionList.length === 1 && optionList[0].name === 'weekday') {
var 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) { function toLocaleTimeString(date, options) {
if (!date) throw new Error("date cannot be null");
if (options = options || {}, toLocaleTimeStringSupportsLocales) { if (!date) {
var currentLocale = globalize.getCurrentDateTimeLocale(); throw new Error('date cannot be null');
if (currentLocale) return date.toLocaleTimeString(currentLocale, options)
} }
return date.toLocaleTimeString()
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
var currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleTimeString(currentLocale, options);
}
}
return date.toLocaleTimeString();
} }
function getDisplayTime(date) { function getDisplayTime(date) {
if (!date) throw new Error("date cannot be null");
if ("string" === (typeof date).toString().toLowerCase()) try { if (!date) {
date = parseISO8601Date(date, !0) throw new Error('date cannot be null');
}
if ((typeof date).toString().toLowerCase() === 'string') {
try {
date = parseISO8601Date(date, true);
} catch (err) { } catch (err) {
return date return date;
} }
if (toLocaleTimeStringSupportsLocales) return toLocaleTimeString(date, { }
hour: "numeric",
minute: "2-digit" 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")) {
time = timeLower;
var hour = date.getHours() % 12,
suffix = date.getHours() > 11 ? "pm" : "am";
hour || (hour = 12);
var minutes = date.getMinutes();
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(":"))
} }
return time
var time = toLocaleTimeString(date);
var timeLower = time.toLowerCase();
if (timeLower.indexOf('am') !== -1 || timeLower.indexOf('pm') !== -1) {
time = timeLower;
var hour = date.getHours() % 12;
var suffix = date.getHours() > 11 ? 'pm' : 'am';
if (!hour) {
hour = 12;
}
var minutes = date.getMinutes();
if (minutes < 10) {
minutes = '0' + minutes;
}
minutes = ':' + minutes;
time = hour + minutes + suffix;
} else {
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;
} }
function isRelativeDay(date, offsetInDays) { function isRelativeDay(date, offsetInDays) {
if (!date) throw new Error("date cannot be null");
var yesterday = new Date, if (!date) {
day = yesterday.getDate() + offsetInDays; throw new Error('date cannot be null');
return yesterday.setDate(day), date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day
} }
var toLocaleTimeStringSupportsLocales = function() {
try { var yesterday = new Date();
(new Date).toLocaleTimeString("i") var day = yesterday.getDate() + offsetInDays;
} catch (e) {
return "RangeError" === e.name yesterday.setDate(day); // automatically adjusts month/year appropriately
return date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day;
} }
return !1
}();
return { return {
parseISO8601Date: parseISO8601Date, parseISO8601Date: parseISO8601Date,
getDisplayRunningTime: getDisplayRunningTime, getDisplayRunningTime: getDisplayRunningTime,
@ -116,8 +275,8 @@ define(["globalize"], function(globalize) {
getDisplayTime: getDisplayTime, getDisplayTime: getDisplayTime,
isRelativeDay: isRelativeDay, isRelativeDay: isRelativeDay,
toLocaleTimeString: toLocaleTimeString, toLocaleTimeString: toLocaleTimeString,
supportsLocalization: function() { supportsLocalization: function () {
return toLocaleTimeStringSupportsLocales return toLocaleTimeStringSupportsLocales;
}
} }
};
}); });

View file

@ -1,39 +1,57 @@
define(["connectionManager", "confirm", "appRouter", "globalize"], function(connectionManager, confirm, appRouter, globalize) { define(['connectionManager', 'confirm', 'appRouter', 'globalize'], function (connectionManager, confirm, appRouter, globalize) {
"use strict"; 'use strict';
function alertText(options) { function alertText(options) {
return new Promise(function(resolve, reject) {
require(["alert"], function(alert) { return new Promise(function (resolve, reject) {
alert(options).then(resolve, resolve)
}) require(['alert'], function (alert) {
}) alert(options).then(resolve, resolve);
});
});
} }
function deleteItem(options) { function deleteItem(options) {
var item = options.item,
itemId = item.Id, var item = options.item;
parentId = item.SeasonId || item.SeriesId || item.ParentId, var itemId = item.Id;
serverId = item.ServerId, var parentId = item.SeasonId || item.SeriesId || item.ParentId;
msg = globalize.translate("sharedcomponents#ConfirmDeleteItem"), var serverId = item.ServerId;
title = globalize.translate("sharedcomponents#HeaderDeleteItem"),
apiClient = connectionManager.getApiClient(item.ServerId); var msg = globalize.translate('sharedcomponents#ConfirmDeleteItem');
var title = globalize.translate('sharedcomponents#HeaderDeleteItem');
var apiClient = connectionManager.getApiClient(item.ServerId);
return confirm({ return confirm({
title: title, title: title,
text: msg, text: msg,
confirmText: globalize.translate("sharedcomponents#Delete"), confirmText: globalize.translate('sharedcomponents#Delete'),
primary: "cancel" primary: 'cancel'
}).then(function() {
return apiClient.deleteItem(itemId).then(function() { }).then(function () {
options.navigate && (parentId ? appRouter.showItem(parentId, serverId) : appRouter.goHome())
}, function(err) { return apiClient.deleteItem(itemId).then(function () {
var result = function() {
return Promise.reject(err) if (options.navigate) {
}; if (parentId) {
return alertText(globalize.translate("sharedcomponents#ErrorDeletingItem")).then(result, result) 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 { return {
deleteItem: deleteItem 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) { 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"; 'use strict';
function showDialog(options, template) { function showDialog(options, template) {
function onButtonClick() {
dialogResult = this.getAttribute("data-id"), dialogHelper.close(dlg)
}
var dialogOptions = { var dialogOptions = {
removeOnClose: !0, removeOnClose: true,
scrollY: !1 scrollY: false
}, };
enableTvLayout = layoutManager.tv;
enableTvLayout && (dialogOptions.size = "fullscreen"); var enableTvLayout = layoutManager.tv;
if (enableTvLayout) {
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions); 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"); dlg.classList.add('formDialog');
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.innerHTML = globalize.translateHtml(template, 'sharedcomponents');
dlg.querySelector(".text").innerHTML = displayText, displayText || dlg.querySelector(".dialogContentInner").classList.add("hide");
var i, length, html = "", dlg.classList.add('align-items-center');
hasDescriptions = !1; 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++) { for (i = 0, length = options.buttons.length; i < length; i++) {
var item = options.buttons[i],
autoFocus = 0 === i ? " autofocus" : "", var item = options.buttons[i];
buttonClass = "btnOption raised formDialogFooterItem formDialogFooterItem-autosize"; var autoFocus = i === 0 ? ' autofocus' : '';
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>")
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
if (item.type) {
buttonClass += ' button-' + item.type;
} }
dlg.querySelector(".formDialogFooter").innerHTML = html, hasDescriptions && dlg.querySelector(".formDialogFooter").classList.add("formDialogFooter-vertical");
var dialogResult, buttons = dlg.querySelectorAll(".btnOption"); if (item.description) {
for (i = 0, length = buttons.length; i < length; i++) buttons[i].addEventListener("click", onButtonClick); hasDescriptions = true;
return dialogHelper.open(dlg).then(function() {
return enableTvLayout && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), dialogResult || Promise.reject()
})
} }
return function(text, title) {
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) {
var options; var options;
return options = "string" == typeof text ? { if (typeof text === 'string') {
options = {
title: title, title: title,
text: text text: text
} : text, new Promise(function(resolve, reject) { };
require(["text!./dialog.template.html"], function(template) { } else {
showDialog(options, template).then(resolve, reject) 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 { .dialogContainer {
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
position: fixed; position: fixed;
top: 0; top: 0;
@ -16,234 +10,148 @@
z-index: 999999 !important; z-index: 999999 !important;
contain: strict; contain: strict;
overflow: hidden; overflow: hidden;
overscroll-behavior: contain overscroll-behavior: contain;
} }
.dialog { .dialog {
margin: 0; margin: 0;
-webkit-border-radius: .2em;
border-radius: .2em; border-radius: .2em;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
border: 0; border: 0;
padding: 0; padding: 0;
will-change: transform, opacity; will-change: transform, opacity;
/* Strict does not work well with actionsheet */
contain: style paint; 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, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 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)
} }
.dialog-fixedSize { .dialog-fixedSize {
-webkit-border-radius: 0;
border-radius: 0; border-radius: 0;
max-height: none; max-height: none;
max-width: none; max-width: none;
contain: layout style paint contain: layout style paint;
} }
.dialog-fullscreen { .dialog-fullscreen {
/* Needed due to formDialog style */
position: fixed !important; position: fixed !important;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
margin: 0; margin: 0;
-webkit-box-shadow: none; 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)
}
} }
@keyframes scaledown { @keyframes scaledown {
from { from {
opacity: 1; opacity: 1;
-webkit-transform: none; transform: none;
transform: none
} }
to { to {
opacity: 0; opacity: 0;
-webkit-transform: scale(.5);
transform: scale(.5)
}
}
@-webkit-keyframes scaleup {
from {
-webkit-transform: scale(.5);
transform: scale(.5); transform: scale(.5);
opacity: 0
}
to {
-webkit-transform: none;
transform: none;
opacity: 1
} }
} }
@keyframes scaleup { @keyframes scaleup {
from { from {
-webkit-transform: scale(.5);
transform: scale(.5); transform: scale(.5);
opacity: 0 opacity: 0;
} }
to { to {
-webkit-transform: none;
transform: none; transform: none;
opacity: 1 opacity: 1;
}
}
@-webkit-keyframes fadein {
from {
opacity: 0
}
to {
opacity: 1
} }
} }
@keyframes fadein { @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 { from {
opacity: 0; opacity: 0;
-webkit-transform: translate3d(0, 30%, 0);
transform: translate3d(0, 30%, 0)
} }
to { to {
opacity: 1; opacity: 1;
-webkit-transform: none; }
transform: none }
@keyframes fadeout {
from {
opacity: 1;
}
to {
opacity: 0;
} }
} }
@keyframes slideup { @keyframes slideup {
from { from {
opacity: 0; opacity: 0;
-webkit-transform: translate3d(0, 30%, 0); transform: translate3d(0, 30%, 0);
transform: translate3d(0, 30%, 0)
} }
to { to {
opacity: 1; opacity: 1;
-webkit-transform: none; 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)
} }
} }
@keyframes slidedown { @keyframes slidedown {
from { from {
opacity: 1; opacity: 1;
-webkit-transform: none; transform: none;
transform: none
} }
to { to {
opacity: 0; opacity: 0;
-webkit-transform: translate3d(0, 20%, 0); transform: translate3d(0, 20%, 0);
transform: translate3d(0, 20%, 0)
} }
} }
@media all and (max-width:80em), @media all and (max-width: 80em), all and (max-height: 45em) {
all and (max-height:45em) {
.dialog-fixedSize, .dialog-fixedSize, .dialog-fullscreen-lowres {
.dialog-fullscreen-lowres {
position: fixed !important; position: fixed !important;
top: 0 !important; top: 0 !important;
bottom: 0 !important; bottom: 0 !important;
left: 0 !important; left: 0 !important;
right: 0 !important; right: 0 !important;
margin: 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 { .dialog-medium {
width: 80%; width: 80%;
height: 80% height: 80%;
} }
.dialog-medium-tall { .dialog-medium-tall {
width: 80%; width: 80%;
height: 90% height: 90%;
} }
.dialog-small { .dialog-small {
width: 60%; width: 60%;
height: 80% height: 80%;
} }
.dialog-fullscreen-border { .dialog-fullscreen-border {
width: 90%; width: 90%;
height: 90% height: 90%;
} }
} }
.noScroll { .noScroll {
overflow-x: hidden !important; overflow-x: hidden !important;
overflow-y: hidden !important overflow-y: hidden !important;
} }
.dialogBackdrop { .dialogBackdrop {
@ -256,12 +164,10 @@ all and (max-height:45em) {
right: 0 !important; right: 0 !important;
margin: 0 !important; margin: 0 !important;
z-index: 999999 !important; z-index: 999999 !important;
-webkit-transition: opacity ease-out .2s; transition: opacity ease-out 0.2s;
-o-transition: opacity ease-out .2s; will-change: opacity;
transition: opacity ease-out .2s;
will-change: opacity
} }
.dialogBackdropOpened { .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) { define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', 'dom', 'css!./dialoghelper.css', 'scrollStyles'], function (appRouter, focusManager, browser, layoutManager, inputManager, dom) {
"use strict"; 'use strict';
var globalOnOpenCallback;
function enableAnimation() { function enableAnimation() {
return !browser.tv && browser.supportsCssAnimation()
// too slow
if (browser.tv) {
return false;
}
return browser.supportsCssAnimation();
} }
function removeCenterFocus(dlg) { 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) { function tryRemoveElement(elem) {
var parentNode = elem.parentNode; var parentNode = elem.parentNode;
if (parentNode) try { if (parentNode) {
parentNode.removeChild(elem)
// Seeing crashes in edge webview
try {
parentNode.removeChild(elem);
} catch (err) { } catch (err) {
console.log("Error removing dialog element: " + err) console.log('Error removing dialog element: ' + err);
}
} }
} }
function DialogHashHandler(dlg, hash, resolve) { function DialogHashHandler(dlg, hash, resolve) {
var self = this;
self.originalUrl = window.location.href;
var activeElement = document.activeElement;
var removeScrollLockOnClose = false;
function onHashChange(e) { function onHashChange(e) {
var isBack = self.originalUrl === window.location.href; 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) { 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() { 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); removeCenterFocus(dlg);
var dialogContainer = dlg.dialogContainer; 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({ resolve({
element: dlg, element: dlg,
closedByBack: self.closedByBack 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) { 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; 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) { backdropParent.parentNode.insertBefore(backdrop, backdropParent);
e.target === dlg.dialogContainer && close(dlg) 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) { function isHistoryEnabled(dlg) {
return "true" === dlg.getAttribute("data-history") return dlg.getAttribute('data-history') === 'true';
} }
function open(dlg) { function open(dlg) {
globalOnOpenCallback && globalOnOpenCallback(dlg);
if (globalOnOpenCallback) {
globalOnOpenCallback(dlg);
}
var parent = dlg.parentNode; var parent = dlg.parentNode;
parent && parent.removeChild(dlg); if (parent) {
var dialogContainer = document.createElement("div"); parent.removeChild(dlg);
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)
}) 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) { function isOpened(dlg) {
return !dlg.classList.contains("hide")
//return dlg.opened;
return !dlg.classList.contains('hide');
} }
function close(dlg) { 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) { function closeDialog(dlg) {
if (!dlg.classList.contains("hide")) {
dlg.dispatchEvent(new CustomEvent("closing", { if (!dlg.classList.contains('hide')) {
bubbles: !1,
cancelable: !1 dlg.dispatchEvent(new CustomEvent('closing', {
bubbles: false,
cancelable: false
})); }));
animateDialogClose(dlg, function() {
focusManager.popScope(dlg), dlg.classList.add("hide"), dlg.dispatchEvent(new CustomEvent("close", { var onAnimationFinish = function () {
bubbles: !1, focusManager.popScope(dlg);
cancelable: !1
})) dlg.classList.add('hide');
}) dlg.dispatchEvent(new CustomEvent('close', {
bubbles: false,
cancelable: false
}));
};
animateDialogClose(dlg, onAnimationFinish);
} }
} }
function animateDialogOpen(dlg) { function animateDialogOpen(dlg) {
var onAnimationFinish = function() {
focusManager.pushScope(dlg), "true" === dlg.getAttribute("data-autofocus") && focusManager.autoFocus(dlg) var onAnimationFinish = function () {
}; focusManager.pushScope(dlg);
if (enableAnimation()) { if (dlg.getAttribute('data-autofocus') === 'true') {
var onFinish = function() { focusManager.autoFocus(dlg);
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: !0
}), onAnimationFinish()
};
return void dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: !0
})
} }
onAnimationFinish() };
if (enableAnimation()) {
var onFinish = function () {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true
});
onAnimationFinish();
};
dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true
});
return;
}
onAnimationFinish();
} }
function animateDialogClose(dlg, onAnimationFinish) { function animateDialogClose(dlg, onAnimationFinish) {
if (enableAnimation()) { if (enableAnimation()) {
var animated = !0;
var animated = true;
switch (dlg.animationConfig.exit.name) { 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; break;
case "scaledown": case 'scaledown':
dlg.style.animation = "scaledown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both"; dlg.style.animation = 'scaledown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
break; break;
case "slidedown": case 'slidedown':
dlg.style.animation = "slidedown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both"; dlg.style.animation = 'slidedown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
break; break;
default: default:
animated = !1 animated = false;
break;
} }
var onFinish = function() { var onFinish = function () {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, { dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: !0 once: true
}), onAnimationFinish() });
onAnimationFinish();
}; };
if (dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, { dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: !0 once: true
}), animated) return });
if (animated) {
return;
} }
onAnimationFinish()
} }
onAnimationFinish();
}
var supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
function shouldLockDocumentScroll(options) { 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) { function removeBackdrop(dlg) {
var backdrop = dlg.backdrop; var backdrop = dlg.backdrop;
if (backdrop) {
dlg.backdrop = null; if (!backdrop) {
var onAnimationFinish = function() { return;
tryRemoveElement(backdrop)
};
if (enableAnimation()) return backdrop.classList.remove("dialogBackdropOpened"), void setTimeout(onAnimationFinish, 300);
onAnimationFinish()
} }
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) { function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
var fn = on ? "on" : "off"; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz) scrollHelper.centerFocus[fn](elem, horiz);
}) });
} }
function createDialog(options) { function createDialog(options) {
options = 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"); // If there's no native dialog support, use a plain div
var defaultEntryAnimation, defaultExitAnimation; // Also not working well in samsung tizen browser, content inside not clickable
defaultEntryAnimation = "scaleup", defaultExitAnimation = "scaledown"; // Just go ahead and always use a plain div because we're seeing issues overlaying absoltutely positioned content over a modal dialog
var entryAnimation = options.entryAnimation || defaultEntryAnimation, var dlg = document.createElement('div');
exitAnimation = options.exitAnimation || defaultExitAnimation,
entryAnimationDuration = options.entryAnimationDuration || ("fullscreen" !== options.size ? 180 : 280), dlg.classList.add('focuscontainer');
exitAnimationDuration = options.exitAnimationDuration || ("fullscreen" !== options.size ? 120 : 220); dlg.classList.add('hide');
if (dlg.animationConfig = {
entry: { if (shouldLockDocumentScroll(options)) {
dlg.setAttribute('data-lockscroll', 'true');
}
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, name: entryAnimation,
timing: { timing: {
duration: entryAnimationDuration, duration: entryAnimationDuration,
easing: "ease-out" easing: 'ease-out'
} }
}, },
exit: { // fade out
'exit': {
name: exitAnimation, name: exitAnimation,
timing: { timing: {
duration: exitAnimationDuration, duration: exitAnimationDuration,
easing: "ease-out", easing: 'ease-out',
fill: "both" 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"; 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; break;
case "scaleup": case 'scaleup':
dlg.style.animation = "scaleup " + entryAnimationDuration + "ms ease-out normal both"; dlg.style.animation = 'scaleup ' + entryAnimationDuration + 'ms ease-out normal both';
break; break;
case "slideup": case 'slideup':
dlg.style.animation = "slideup " + entryAnimationDuration + "ms ease-out normal"; dlg.style.animation = 'slideup ' + entryAnimationDuration + 'ms ease-out normal';
break;
case 'slidedown':
dlg.style.animation = 'slidedown ' + entryAnimationDuration + 'ms ease-out normal';
break;
default:
break; break;
case "slidedown":
dlg.style.animation = "slidedown " + entryAnimationDuration + "ms ease-out normal"
} }
return dlg
} }
var globalOnOpenCallback, supportsOverscrollBehavior = "overscroll-behavior-y" in document.body.style;
return dlg;
}
return { return {
open: open, open: open,
close: close, close: close,
createDialog: createDialog, createDialog: createDialog,
setOnOpen: function(val) { setOnOpen: function (val) {
globalOnOpenCallback = 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"; "use strict";
function fillThemes(select, isDashboard) { function fillThemes(select, isDashboard) {
select.innerHTML = skinManager.getThemes().map(function(t) {
select.innerHTML = skinManager.getThemes().map(function (t) {
var value = t.id; 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) { function loadScreensavers(context, userSettings) {
var selectScreensaver = context.querySelector(".selectScreensaver"),
options = pluginManager.ofType("screensaver").map(function(plugin) { var selectScreensaver = context.querySelector('.selectScreensaver');
var options = pluginManager.ofType('screensaver').map(function (plugin) {
return { return {
name: plugin.name, name: plugin.name,
value: plugin.id value: plugin.id
} };
}); });
options.unshift({ options.unshift({
name: globalize.translate("sharedcomponents#None"), name: globalize.translate('sharedcomponents#None'),
value: "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") 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) { function loadSoundEffects(context, userSettings) {
var selectSoundEffects = context.querySelector(".selectSoundEffects"),
options = pluginManager.ofType("soundeffects").map(function(plugin) { var selectSoundEffects = context.querySelector('.selectSoundEffects');
var options = pluginManager.ofType('soundeffects').map(function (plugin) {
return { return {
name: plugin.name, name: plugin.name,
value: plugin.id value: plugin.id
} };
}); });
options.unshift({ options.unshift({
name: globalize.translate("sharedcomponents#None"), name: globalize.translate('sharedcomponents#None'),
value: "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") 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) { function loadSkins(context, userSettings) {
var selectSkin = context.querySelector(".selectSkin"),
options = pluginManager.ofType("skin").map(function(plugin) { var selectSkin = context.querySelector('.selectSkin');
var options = pluginManager.ofType('skin').map(function (plugin) {
return { return {
name: plugin.name, name: plugin.name,
value: plugin.id value: plugin.id
} };
}); });
selectSkin.innerHTML = options.map(function(o) {
return '<option value="' + o.value + '">' + o.name + "</option>" selectSkin.innerHTML = options.map(function (o) {
}).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") 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) { 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) { 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 loggedInUserId = apiClient.getCurrentUserId();
var selectTheme = context.querySelector("#selectTheme"), var userId = user.Id;
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() 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) { 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) { function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loading.show(), apiClient.getUser(userId).then(function(user) {
saveUser(context, user, userSettings, apiClient).then(function() { loading.show();
loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) {
toast(globalize.translate("sharedcomponents#SettingsSaved")) apiClient.getUser(userId).then(function (user) {
}), events.trigger(instance, "saved")
}, function() { saveUser(context, user, userSettings, apiClient).then(function () {
loading.hide()
}) loading.hide();
}) if (enableSaveConfirmation) {
require(['toast'], function (toast) {
toast(globalize.translate('sharedcomponents#SettingsSaved'));
});
}
events.trigger(instance, 'saved');
}, function () {
loading.hide();
});
});
} }
function onSubmit(e) { function onSubmit(e) {
var self = this,
apiClient = connectionManager.getApiClient(self.options.serverId), var self = this;
userId = self.options.userId, var apiClient = connectionManager.getApiClient(self.options.serverId);
userSettings = self.options.userSettings; var userId = self.options.userId;
return userSettings.setUserInfo(userId, apiClient).then(function() { var userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(function () {
var enableSaveConfirmation = self.options.enableSaveConfirmation; var enableSaveConfirmation = self.options.enableSaveConfirmation;
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation) save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
}), e && e.preventDefault(), !1 });
// Disable default form submission
if (e) {
e.preventDefault();
}
return false;
} }
function embed(options, self) { 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) { function DisplaySettings(options) {
this.options = options, embed(options, this)
this.options = options;
embed(options, this);
} }
return DisplaySettings.prototype.loadData = function(autoFocus) {
var self = this, DisplaySettings.prototype.loadData = function (autoFocus) {
context = self.options.element;
var self = this;
var context = self.options.element;
loading.show(); loading.show();
var userId = self.options.userId,
apiClient = connectionManager.getApiClient(self.options.serverId), var userId = self.options.userId;
userSettings = self.options.userSettings; var apiClient = connectionManager.getApiClient(self.options.serverId);
return apiClient.getUser(userId).then(function(user) { var userSettings = self.options.userSettings;
return userSettings.setUserInfo(userId, apiClient).then(function() {
self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient), autoFocus && focusManager.autoFocus(context) return apiClient.getUser(userId).then(function (user) {
})
}) return userSettings.setUserInfo(userId, apiClient).then(function () {
}, DisplaySettings.prototype.submit = function() {
onSubmit.call(this) self.dataLoaded = true;
}, DisplaySettings.prototype.destroy = function() {
this.options = null loadForm(context, user, userSettings, apiClient);
}, DisplaySettings
if (autoFocus) {
focusManager.autoFocus(context);
}
});
});
};
DisplaySettings.prototype.submit = function () {
onSubmit.call(this);
};
DisplaySettings.prototype.destroy = function () {
this.options = null;
};
return DisplaySettings;
}); });

View file

@ -1,96 +1,170 @@
define([], function() { define([], function () {
"use strict"; 'use strict';
function parentWithAttribute(elem, name, value) { function parentWithAttribute(elem, name, value) {
for (; value ? elem.getAttribute(name) !== value : !elem.getAttribute(name);)
if (!(elem = elem.parentNode) || !elem.getAttribute) return null; while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) {
return elem elem = elem.parentNode;
if (!elem || !elem.getAttribute) {
return null;
}
}
return elem;
} }
function parentWithTag(elem, tagNames) { function parentWithTag(elem, tagNames) {
for (Array.isArray(tagNames) || (tagNames = [tagNames]); - 1 === tagNames.indexOf(elem.tagName || "");)
if (!(elem = elem.parentNode)) return null; // accept both string and array passed in
return elem 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) { function containsAnyClass(classList, classNames) {
for (var i = 0, length = classNames.length; i < length; i++)
if (classList.contains(classNames[i])) return !0; for (var i = 0, length = classNames.length; i < length; i++) {
return !1 if (classList.contains(classNames[i])) {
return true;
}
}
return false;
} }
function parentWithClass(elem, classNames) { function parentWithClass(elem, classNames) {
for (Array.isArray(classNames) || (classNames = [classNames]); !elem.classList || !containsAnyClass(elem.classList, classNames);)
if (!(elem = elem.parentNode)) return null; // accept both string and array passed in
return elem 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) { function addEventListenerWithOptions(target, type, handler, options) {
var optionsOrCapture = 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) { function removeEventListenerWithOptions(target, type, handler, options) {
var optionsOrCapture = 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() { function clearWindowSize() {
windowSize = null windowSize = null;
} }
function getWindowSize() { function getWindowSize() {
return windowSize || (windowSize = { if (!windowSize) {
windowSize = {
innerHeight: window.innerHeight, innerHeight: window.innerHeight,
innerWidth: window.innerWidth innerWidth: window.innerWidth
}, windowSizeEventsBound || (windowSizeEventsBound = !0, addEventListenerWithOptions(window, "orientationchange", clearWindowSize, { };
passive: !0
}), addEventListenerWithOptions(window, "resize", clearWindowSize, { if (!windowSizeEventsBound) {
passive: !0 windowSizeEventsBound = true;
}))), windowSize addEventListenerWithOptions(window, "orientationchange", clearWindowSize, { passive: true });
addEventListenerWithOptions(window, 'resize', clearWindowSize, { passive: true });
}
} }
return windowSize;
}
var _animationEvent;
function whichAnimationEvent() { function whichAnimationEvent() {
if (_animationEvent) return _animationEvent;
var t, el = document.createElement("div"), if (_animationEvent) {
animations = { return _animationEvent;
animation: "animationend", }
OAnimation: "oAnimationEnd",
MozAnimation: "animationend", var t,
WebkitAnimation: "webkitAnimationEnd" el = document.createElement("div");
var animations = {
"animation": "animationend",
"OAnimation": "oAnimationEnd",
"MozAnimation": "animationend",
"WebkitAnimation": "webkitAnimationEnd"
}; };
for (t in animations) for (t in animations) {
if (void 0 !== el.style[t]) return _animationEvent = animations[t], animations[t]; if (el.style[t] !== undefined) {
return _animationEvent = "animationend" _animationEvent = animations[t];
return animations[t];
}
}
_animationEvent = 'animationend';
return _animationEvent;
} }
function whichAnimationCancelEvent() { function whichAnimationCancelEvent() {
return whichAnimationEvent().replace("animationend", "animationcancel").replace("AnimationEnd", "AnimationCancel")
return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel');
} }
var _transitionEvent;
function whichTransitionEvent() { function whichTransitionEvent() {
if (_transitionEvent) return _transitionEvent; if (_transitionEvent) {
var t, el = document.createElement("div"), return _transitionEvent;
transitions = { }
transition: "transitionend",
OTransition: "oTransitionEnd", var t,
MozTransition: "transitionend", el = document.createElement("div");
WebkitTransition: "webkitTransitionEnd" var transitions = {
"transition": "transitionend",
"OTransition": "oTransitionEnd",
"MozTransition": "transitionend",
"WebkitTransition": "webkitTransitionEnd"
}; };
for (t in transitions) for (t in transitions) {
if (void 0 !== el.style[t]) return _transitionEvent = transitions[t], transitions[t]; if (el.style[t] !== undefined) {
return _transitionEvent = "transitionend" _transitionEvent = transitions[t];
return transitions[t];
} }
var supportsCaptureOption = !1;
try {
var opts = Object.defineProperty({}, "capture", {
get: function() {
supportsCaptureOption = !0
} }
});
window.addEventListener("test", null, opts) _transitionEvent = 'transitionend';
} catch (e) {} return _transitionEvent;
var windowSize, windowSizeEventsBound, _animationEvent, _transitionEvent; }
return { return {
parentWithAttribute: parentWithAttribute, parentWithAttribute: parentWithAttribute,
parentWithClass: parentWithClass, parentWithClass: parentWithClass,
@ -101,5 +175,5 @@ define([], function() {
whichTransitionEvent: whichTransitionEvent, whichTransitionEvent: whichTransitionEvent,
whichAnimationEvent: whichAnimationEvent, whichAnimationEvent: whichAnimationEvent,
whichAnimationCancelEvent: whichAnimationCancelEvent 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 { .emby-button {
display: -webkit-inline-box; position: relative;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
-webkit-align-items: center;
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
margin: 0 .29em; margin: 0 .29em;
text-align: center;
font-size: inherit; font-size: inherit;
font-family: inherit;
color: inherit;
outline-width: 0;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
@ -35,99 +16,98 @@
cursor: pointer; cursor: pointer;
z-index: 0; z-index: 0;
padding: .86em 1em; padding: .86em 1em;
vertical-align: middle;
border: 0; border: 0;
vertical-align: middle; vertical-align: middle;
-webkit-border-radius: .2em;
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; font-weight: 600;
/* Disable webkit tap highlighting */
-webkit-tap-highlight-color: rgba(0,0,0,0);
text-decoration: none; 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 { .emby-button::-moz-focus-inner {
border: 0 border: 0;
} }
.button-flat:hover { .button-flat {
opacity: .5 background: transparent;
} }
.button-flat:hover {
opacity: .5;
}
.button-link { .button-link {
background: transparent;
margin: 0; margin: 0;
padding: 0; padding: 0;
vertical-align: initial vertical-align: initial;
} }
.button-link-inline { .button-link-inline {
display: inline display: inline;
} }
.button-link:hover { .button-link:hover {
text-decoration: underline text-decoration: underline;
} }
.emby-button-focusscale { .emby-button-focusscale {
-webkit-transition: -webkit-transform 180ms ease-out !important;
-o-transition: transform 180ms ease-out !important;
transition: transform 180ms ease-out !important; transition: transform 180ms ease-out !important;
-webkit-transform-origin: center center; -webkit-transform-origin: center center;
transform-origin: center center transform-origin: center center;
} }
.emby-button-focusscale:focus { .emby-button-focusscale:focus {
-webkit-transform: scale(1.16);
transform: scale(1.16); transform: scale(1.16);
z-index: 1 z-index: 1;
}
.emby-button > i {
/* For non-fab buttons that have icons */
font-size: 1.36em;
} }
.emby-button>i { .button-link > i {
font-size: 1.36em font-size: 1em;
}
.button-link>i {
font-size: 1em
} }
.fab { .fab {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
-webkit-border-radius: 50%;
border-radius: 50%; border-radius: 50%;
padding: .6em; padding: .6em;
box-sizing: border-box; box-sizing: border-box;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
text-align: center text-align: center;
} }
.emby-button.block { .emby-button.block {
display: block; display: block;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
margin: .25em 0; margin: .25em 0;
width: 100% width: 100%;
} }
.paper-icon-button-light { .paper-icon-button-light {
display: -webkit-inline-box; position: relative;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
margin: 0 .29em; margin: 0 .29em;
background: 0 0; background: transparent;
text-align: center;
font-size: inherit; font-size: inherit;
font-family: inherit;
color: inherit;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
@ -139,84 +119,82 @@
width: auto; width: auto;
height: auto; height: auto;
padding: .556em; padding: .556em;
vertical-align: middle;
border: 0; border: 0;
vertical-align: middle; vertical-align: middle;
/* These are getting an outline in opera tv browsers, which run chrome 30 */
outline: none !important;
position: relative;
overflow: hidden; overflow: hidden;
-webkit-border-radius: 50%;
border-radius: 50%; border-radius: 50%;
-webkit-box-pack: center; /* Disable webkit tap highlighting */
-webkit-justify-content: center; -webkit-tap-highlight-color: rgba(0,0,0,0);
justify-content: center justify-content: center;
} }
.paper-icon-button-light::-moz-focus-inner { .paper-icon-button-light::-moz-focus-inner {
border: 0 border: 0;
} }
.paper-icon-button-light[disabled] { .paper-icon-button-light[disabled] {
opacity: .3 opacity: .3;
} }
.paper-icon-button-light>i { .paper-icon-button-light > i {
font-size: 1.66956521739130434em; font-size: 1.66956521739130434em;
/* Make sure its on top of the ripple */
position: relative; position: relative;
z-index: 1; z-index: 1;
vertical-align: middle vertical-align: middle;
} }
.paper-icon-button-light>img { .paper-icon-button-light > img {
width: 1.72em; width: 1.72em;
/* Can't use 100% height or it will stretch past the boundaries in safari */
/*height: 100%;*/
max-height: 100%; max-height: 100%;
/* Make sure its on top of the ripple */
position: relative; position: relative;
z-index: 1; z-index: 1;
vertical-align: middle vertical-align: middle;
} }
.emby-button-foreground { .emby-button-foreground {
position: relative; position: relative;
z-index: 1 z-index: 1;
} }
.icon-button-focusscale { .icon-button-focusscale {
-webkit-transition: -webkit-transform 180ms ease-out !important;
-o-transition: transform 180ms ease-out !important;
transition: transform 180ms ease-out !important; transition: transform 180ms ease-out !important;
-webkit-transform-origin: center center; -webkit-transform-origin: center center;
transform-origin: center center transform-origin: center center;
} }
.icon-button-focusscale:focus { .icon-button-focusscale:focus {
-webkit-transform: scale(1.3);
transform: scale(1.3); transform: scale(1.3);
z-index: 1 z-index: 1;
} }
.btnFilterWithBubble { .btnFilterWithBubble {
position: relative position: relative;
} }
.filterButtonBubble { .filterButtonBubble {
color: #fff; color: #fff;
position: absolute; position: absolute;
background: #444;
top: 0; top: 0;
right: 0; right: 0;
/* padding: .5em; */
width: 1.6em; width: 1.6em;
height: 1.6em; height: 1.6em;
z-index: 100000000; z-index: 100000000;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
font-size: 82%; font-size: 82%;
-webkit-border-radius: 100em;
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: 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);
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);
background: #03A9F4; 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) { define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css!./emby-button', 'registerElement'], function (browser, dom, layoutManager, shell, appRouter, appHost) {
"use strict"; 'use strict';
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
var EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype);
function openPremiumInfo() { function openPremiumInfo() {
require(["registrationServices"], function(registrationServices) {
registrationServices.showPremiereInfo() require(['registrationServices'], function (registrationServices) {
}) registrationServices.showPremiereInfo();
});
} }
function onAnchorClick(e) { 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();
} }
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype), else if (!appHost.supports('targetblank')) {
EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype); e.preventDefault();
return EmbyButtonPrototype.createdCallback = function() { shell.openUrl(href);
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() { } else {
"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"))) appRouter.handleAnchorClick(e);
}, EmbyButtonPrototype.detachedCallback = function() { }
dom.removeEventListener(this, "click", onAnchorClick, {}) } else {
}, EmbyLinkButtonPrototype.createdCallback = EmbyButtonPrototype.createdCallback, EmbyLinkButtonPrototype.attachedCallback = EmbyButtonPrototype.attachedCallback, document.registerElement("emby-button", { e.preventDefault();
}
}
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, prototype: EmbyButtonPrototype,
extends: "button" extends: 'button'
}), document.registerElement("emby-linkbutton", { });
document.registerElement('emby-linkbutton', {
prototype: EmbyLinkButtonPrototype, prototype: EmbyLinkButtonPrototype,
extends: "a" extends: 'a'
}), EmbyButtonPrototype });
// For extension purposes
return EmbyButtonPrototype;
}); });

View file

@ -1,10 +1,19 @@
define(["layoutManager", "css!./emby-button", "registerElement"], function(layoutManager) { define(['layoutManager', 'css!./emby-button', 'registerElement'], function (layoutManager) {
"use strict"; 'use strict';
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype); var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
EmbyButtonPrototype.createdCallback = function() {
this.classList.add("paper-icon-button-light"), layoutManager.tv && this.classList.add("icon-button-focusscale") EmbyButtonPrototype.createdCallback = function () {
}, document.registerElement("paper-icon-button-light", {
this.classList.add('paper-icon-button-light');
if (layoutManager.tv) {
this.classList.add('icon-button-focusscale');
}
};
document.registerElement('paper-icon-button-light', {
prototype: EmbyButtonPrototype, prototype: EmbyButtonPrototype,
extends: "button" extends: 'button'
}) });
}); });

View file

@ -2,45 +2,37 @@
position: relative; position: relative;
z-index: 1; z-index: 1;
vertical-align: middle; vertical-align: middle;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
margin: 0; margin: 0;
padding: 0 0 0 2.4em; padding: 0;
-webkit-box-align: center; padding-left: 2.4em;
-webkit-align-items: center;
align-items: center; align-items: center;
height: 2.35em; height: 2.35em;
cursor: pointer cursor: pointer;
}
.checkboxContainer,
.checkboxListContainer {
margin-bottom: 1.8em
} }
.checkboxFieldDescription { .checkboxFieldDescription {
padding-left: 2.4em padding-left: 2.4em;
} }
.checkboxContainer { .checkboxContainer {
display: -webkit-box; margin-bottom: 1.8em;
display: -webkit-flex; display: flex;
display: flex }
.checkboxListContainer {
margin-bottom: 1.8em;
} }
.checkboxContainer-withDescription { .checkboxContainer-withDescription {
-webkit-box-orient: vertical; flex-direction: column;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column
} }
.emby-checkbox { .emby-checkbox {
position: absolute; position: absolute;
/* This is for focusing purposes, so the focusManager doesn't skip over it */
width: 1px; width: 1px;
height: 1px; height: 1px;
margin: 0; margin: 0;
@ -50,112 +42,109 @@
-moz-appearance: none; -moz-appearance: none;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
border: none border: none;
} }
.checkboxOutline { .checkboxOutline {
position: absolute; position: absolute;
top: 3px; top: 3px;
left: 0; left: 0;
-webkit-box-sizing: border-box; display: inline-block;
box-sizing: border-box; box-sizing: border-box;
width: 1.83em; width: 1.83em;
height: 1.83em; height: 1.83em;
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
border: 2px solid currentcolor; border: 2px solid currentcolor;
-webkit-border-radius: .14em;
border-radius: .14em; border-radius: .14em;
z-index: 2; z-index: 2;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center; justify-content: center;
-webkit-justify-content: center;
justify-content: center
} }
/* Commenting this out - set by theme */
/*.emby-checkbox:checked + span + span + .checkboxOutline {
border-color: #52B54B;
}*/
.emby-checkbox-focushelper { .emby-checkbox-focushelper {
position: absolute; position: absolute;
top: -.915em; top: -0.915em;
left: -.915em; left: -0.915em;
width: 3.66em; width: 3.66em;
height: 3.66em; height: 3.66em;
display: inline-block; display: inline-block;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
margin: 3px 0 0; margin: 3px 0 0 0;
-webkit-border-radius: 50%;
border-radius: 50%; 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 { .checkboxIcon {
font-size: 1.6em; font-size: 1.6em;
color: #fff color: #fff;
} }
.checkboxIcon-checked { .checkboxIcon-checked {
display: none display: none;
} }
.emby-checkbox:checked+span+span+.checkboxOutline>.checkboxIcon-checked { .emby-checkbox:checked + span + span + .checkboxOutline > .checkboxIcon-checked {
display: -webkit-box !important; /* background-color set by theme */
display: -webkit-flex !important; /*background-color: #52B54B;*/
display: flex !important display: flex !important;
} }
.emby-checkbox:checked+span+span+.checkboxOutline>.checkboxIcon-unchecked { .emby-checkbox:checked + span + span + .checkboxOutline > .checkboxIcon-unchecked {
display: none !important /* background-color set by theme */
display: none !important;
} }
.emby-checkbox:checked[disabled]+span+span+.checkboxOutline>.checkboxIcon { .emby-checkbox:checked[disabled] + span + span + .checkboxOutline > .checkboxIcon {
background-color: rgba(0, 0, 0, .26) background-color: rgba(0, 0, 0, 0.26);
} }
.checkboxLabel { .checkboxLabel {
position: relative; position: relative;
margin: 0 margin: 0;
} }
.checkboxList>.emby-checkbox-label { .checkboxList > .emby-checkbox-label {
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
margin: .5em 0 margin: .5em 0;
} }
.checkboxList-verticalwrap { .checkboxList-verticalwrap {
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-flex-wrap: wrap; flex-wrap: wrap;
flex-wrap: wrap
} }
.checkboxList-verticalwrap>.emby-checkbox-label { .checkboxList-verticalwrap > .emby-checkbox-label {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
margin: .3em 0; margin: .3em 0 .3em 0;
width: 12em width: 12em;
} }
.checkboxList-paperList { .checkboxList-paperList {
padding: 1em !important padding: 1em !important;
} }
.checkboxListLabel { .checkboxListLabel {
margin-bottom: .25em margin-bottom: .25em;
} }
@-webkit-keyframes repaintChrome { @-webkit-keyframes repaintChrome {
from {
padding: 0;
}
from,
to { to {
padding: 0 padding: 0;
} }
} }

View file

@ -1,55 +1,110 @@
define(["browser", "dom", "css!./emby-checkbox", "registerElement"], function(browser, dom) { define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (browser, dom) {
"use strict"; 'use strict';
var EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype);
function onKeyDown(e) { function onKeyDown(e) {
if (13 === e.keyCode) return e.preventDefault(), this.checked = !this.checked, this.dispatchEvent(new CustomEvent("change", {
bubbles: !0 // Don't submit form on enter
})), !1 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) { function forceRefresh(loading) {
var elem = this.parentNode; 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 = "" elem.style.webkitAnimationName = 'repaintChrome';
}, !0 === loading ? 520 : 20) 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 () {
EmbyCheckboxPrototype.attachedCallback = function() {
if ("true" !== this.getAttribute("data-embycheckbox")) { if (this.getAttribute('data-embycheckbox') === 'true') {
this.setAttribute("data-embycheckbox", "true"), this.classList.add("emby-checkbox"); return;
}
this.setAttribute('data-embycheckbox', 'true');
this.classList.add('emby-checkbox');
var labelElement = this.parentNode; var labelElement = this.parentNode;
labelElement.classList.add("emby-checkbox-label"); labelElement.classList.add('emby-checkbox-label');
var labelTextElement = labelElement.querySelector("span"),
outlineClass = "checkboxOutline", var labelTextElement = labelElement.querySelector('span');
customClass = this.getAttribute("data-outlineclass");
customClass && (outlineClass += " " + customClass); var outlineClass = 'checkboxOutline';
var checkedIcon = this.getAttribute("data-checkedicon") || "&#xE5CA;",
uncheckedIcon = this.getAttribute("data-uncheckedicon") || "", var customClass = this.getAttribute('data-outlineclass');
checkHtml = '<i class="md-icon checkboxIcon checkboxIcon-checked">' + checkedIcon + "</i>", if (customClass) {
uncheckedHtml = '<i class="md-icon checkboxIcon checkboxIcon-unchecked">' + uncheckedIcon + "</i>"; outlineClass += ' ' + customClass;
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.detachedCallback = function() {
this.removeEventListener("keydown", onKeyDown), dom.removeEventListener(this, "click", forceRefresh, { var checkedIcon = this.getAttribute('data-checkedicon') || '&#xE5CA;';
passive: !0 var uncheckedIcon = this.getAttribute('data-uncheckedicon') || '';
}), dom.removeEventListener(this, "blur", forceRefresh, { var checkHtml = '<i class="md-icon checkboxIcon checkboxIcon-checked">' + checkedIcon + '</i>';
passive: !0 var uncheckedHtml = '<i class="md-icon checkboxIcon checkboxIcon-unchecked">' + uncheckedIcon + '</i>';
}), dom.removeEventListener(this, "focus", forceRefresh, { labelElement.insertAdjacentHTML('beforeend', '<span class="emby-checkbox-focushelper"></span><span class="' + outlineClass + '">' + checkHtml + uncheckedHtml + '</span>');
passive: !0
}), dom.removeEventListener(this, "change", forceRefresh, { labelTextElement.classList.add('checkboxLabel');
passive: !0
}) this.addEventListener('keydown', onKeyDown);
}, document.registerElement("emby-checkbox", {
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, prototype: EmbyCheckboxPrototype,
extends: "input" extends: 'input'
}) });
}); });

View file

@ -1,56 +1,44 @@
.emby-collapse { .emby-collapse {
margin: .5em 0 margin: .5em 0;
} }
.collapseContent { .collapseContent {
border-width: 0; border-width: 0;
padding: 1.25em; padding: 1.25em 1.25em;
height: 0; height: 0;
-webkit-transition-property: height;
-o-transition-property: height;
transition-property: height; transition-property: height;
-webkit-transition-duration: .3s; transition-duration: 300ms;
-o-transition-duration: .3s; overflow: hidden;
transition-duration: .3s;
overflow: hidden
} }
.emby-collapsible-button { .emby-collapsible-button {
margin: 0; margin: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
text-transform: none;
width: 100%; width: 100%;
text-align: left; text-align: left;
text-transform: none; text-transform: none;
border-width: 0 0 .1em; border-width: 0 0 .1em 0;
border-style: solid; border-style: solid;
padding-left: .1em; padding-left: .1em;
background: 0 0; background: transparent;
-webkit-box-shadow: none; box-shadow: none;
box-shadow: none
} }
.emby-collapse-expandIcon { .emby-collapse-expandIcon {
-webkit-transform-origin: 50% 50%;
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; transition: transform 180ms ease-out;
position: absolute; position: absolute;
right: .5em; right: .5em;
font-size: 1.5em font-size: 1.5em;
} }
.emby-collapse-expandIconExpanded { .emby-collapse-expandIconExpanded {
-webkit-transform: rotate(180deg); transform: rotate(180deg);
transform: rotate(180deg)
} }
.emby-collapsible-title { .emby-collapsible-title {
margin: 0; margin: 0;
padding: 0 padding: 0;
} }

View file

@ -1,43 +1,100 @@
define(["browser", "css!./emby-collapse", "registerElement", "emby-button"], function(browser) { define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], function (browser) {
"use strict"; 'use strict';
var EmbyButtonPrototype = Object.create(HTMLDivElement.prototype);
function slideDownToShow(button, elem) { function slideDownToShow(button, elem) {
elem.classList.remove("hide"), elem.classList.add("expanded"), elem.style.height = "auto";
var height = elem.offsetHeight + "px"; elem.classList.remove('hide');
elem.style.height = "0"; elem.classList.add('expanded');
elem.offsetHeight; elem.style.height = 'auto';
elem.style.height = height, setTimeout(function() { var height = elem.offsetHeight + 'px';
elem.classList.contains("expanded") ? elem.classList.remove("hide") : elem.classList.add("hide"), elem.style.height = "auto" elem.style.height = '0';
}, 300), button.querySelector("i").classList.add("emby-collapse-expandIconExpanded")
// 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) { function slideUpToHide(button, elem) {
elem.style.height = elem.offsetHeight + "px";
elem.offsetHeight; elem.style.height = elem.offsetHeight + 'px';
elem.classList.remove("expanded"), elem.style.height = "0", setTimeout(function() { // trigger reflow
elem.classList.contains("expanded") ? elem.classList.remove("hide") : elem.classList.add("hide") var newHeight = elem.offsetHeight;
}, 300), button.querySelector("i").classList.remove("emby-collapse-expandIconExpanded")
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) { function onButtonClick(e) {
var button = this,
collapseContent = button.parentNode.querySelector(".collapseContent"); var button = this;
collapseContent.expanded ? (collapseContent.expanded = !1, slideUpToHide(button, collapseContent)) : (collapseContent.expanded = !0, slideDownToShow(button, collapseContent)) var collapseContent = button.parentNode.querySelector('.collapseContent');
if (collapseContent.expanded) {
collapseContent.expanded = false;
slideUpToHide(button, collapseContent);
} else {
collapseContent.expanded = true;
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)
} }
}, 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, prototype: EmbyButtonPrototype,
extends: "div" extends: 'div'
}) });
}); });

View file

@ -1,106 +1,219 @@
define(["globalize", "apphost", "loading", "alert", "emby-linkbutton"], function(globalize, appHost, loading, alert) { define(['globalize', 'apphost', 'loading', 'alert', 'emby-linkbutton'], function (globalize, appHost, loading, alert) {
"use strict"; 'use strict';
function resolvePromise() { function resolvePromise() {
return Promise.resolve() return Promise.resolve();
} }
function rejectPromise() { function rejectPromise() {
return Promise.reject() return Promise.reject();
} }
function showNewUserInviteMessage(result) { 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({ return alert({
text: message, text: message,
title: globalize.translate("sharedcomponents#HeaderInvitationSent") title: globalize.translate('sharedcomponents#HeaderInvitationSent')
}).then(resolvePromise, resolvePromise)
}).then(resolvePromise, resolvePromise);
} }
function inviteGuest(options) { function inviteGuest(options) {
var apiClient = options.apiClient; var apiClient = options.apiClient;
return loading.show(), apiClient.ajax({
loading.show();
// Add/Update connect info
return apiClient.ajax({
type: "POST", type: "POST",
url: apiClient.getUrl("Connect/Invite"), url: apiClient.getUrl('Connect/Invite'),
dataType: "json", dataType: 'json',
data: options.guestOptions || {} data: options.guestOptions || {}
}).then(function(result) {
return loading.hide(), showNewUserInviteMessage(result) }).then(function (result) {
}, function(response) {
loading.hide(); loading.hide();
return showNewUserInviteMessage(result);
}, function (response) {
loading.hide();
var statusCode = response ? response.status : 0; var statusCode = response ? response.status : 0;
return 502 === statusCode ? showConnectServerUnreachableErrorMessage().then(rejectPromise, rejectPromise) : 404 === statusCode ? alert({
text: globalize.translate("sharedcomponents#GuestUserNotFound") if (statusCode === 502) {
}).then(rejectPromise, rejectPromise) : (statusCode || 0) >= 500 ? alert({ return showConnectServerUnreachableErrorMessage().then(rejectPromise, rejectPromise);
text: globalize.translate("sharedcomponents#ErrorReachingEmbyConnect") }
}).then(rejectPromise, rejectPromise) : showGuestGeneralErrorMessage().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() { function showGuestGeneralErrorMessage() {
var html; 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"); if (appHost.supports('externallinks')) {
return text += "\n\n" + globalize.translate("sharedcomponents#ErrorAddingGuestAccount2", "apps@emby.media"), alert({ 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, text: text,
html: html html: html
}) });
} }
function showConnectServerUnreachableErrorMessage() { function showConnectServerUnreachableErrorMessage() {
var text = globalize.translate("sharedcomponents#ErrorConnectServerUnreachable", "https://connect.emby.media");
var text = globalize.translate('sharedcomponents#ErrorConnectServerUnreachable', 'https://connect.emby.media');
return alert({ return alert({
text: text text: text
}) });
} }
function showLinkUserErrorMessage(username, statusCode) { 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, text: text,
html: html html: html
})) });
} }
function updateUserLink(apiClient, user, newConnectUsername) { function updateUserLink(apiClient, user, newConnectUsername) {
var currentConnectUsername = user.ConnectUserName || "", var currentConnectUsername = user.ConnectUserName || '';
enteredConnectUsername = newConnectUsername, var enteredConnectUsername = newConnectUsername;
linkUrl = apiClient.getUrl("Users/" + user.Id + "/Connect/Link");
return currentConnectUsername && !enteredConnectUsername ? apiClient.ajax({ var linkUrl = apiClient.getUrl('Users/' + user.Id + '/Connect/Link');
if (currentConnectUsername && !enteredConnectUsername) {
// Remove connect info
// Add/Update connect info
return apiClient.ajax({
type: "DELETE", type: "DELETE",
url: linkUrl url: linkUrl
}).then(function() {
}).then(function () {
return alert({ return alert({
text: globalize.translate("sharedcomponents#MessageEmbyAccontRemoved"), text: globalize.translate('sharedcomponents#MessageEmbyAccontRemoved'),
title: globalize.translate("sharedcomponents#HeaderEmbyAccountRemoved") title: globalize.translate('sharedcomponents#HeaderEmbyAccountRemoved'),
}).catch(resolvePromise)
}, function(response) { }).catch(resolvePromise);
return 502 === (response ? response.status : 0) ? showConnectServerUnreachableErrorMessage().then(rejectPromise) : alert({
text: globalize.translate("sharedcomponents#ErrorRemovingEmbyConnectAccount") }, function (response) {
}).then(rejectPromise)
}) : currentConnectUsername !== enteredConnectUsername ? apiClient.ajax({ 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", type: "POST",
url: linkUrl, url: linkUrl,
data: { data: {
ConnectUsername: enteredConnectUsername ConnectUsername: enteredConnectUsername
}, },
dataType: "json" dataType: 'json'
}).then(function(result) {
var msgKey = result.IsPending ? "sharedcomponents#MessagePendingEmbyAccountAdded" : "sharedcomponents#MessageEmbyAccountAdded"; }).then(function (result) {
var msgKey = result.IsPending ? 'sharedcomponents#MessagePendingEmbyAccountAdded' : 'sharedcomponents#MessageEmbyAccountAdded';
return alert({ return alert({
text: globalize.translate(msgKey), text: globalize.translate(msgKey),
title: globalize.translate("sharedcomponents#HeaderEmbyAccountAdded") title: globalize.translate('sharedcomponents#HeaderEmbyAccountAdded'),
}).catch(resolvePromise)
}, function(response) { }).catch(resolvePromise);
}, function (response) {
var statusCode = response ? response.status : 0; var statusCode = response ? response.status : 0;
return 502 === statusCode ? showConnectServerUnreachableErrorMessage().then(rejectPromise) : showLinkUserErrorMessage(".", statusCode).then(rejectPromise)
}) : Promise.reject() if (statusCode === 502) {
return showConnectServerUnreachableErrorMessage().then(rejectPromise);
} }
return showLinkUserErrorMessage('.', statusCode).then(rejectPromise);
});
} else {
return Promise.reject();
}
}
return { return {
inviteGuest: inviteGuest, inviteGuest: inviteGuest,
updateUserLink: updateUserLink, updateUserLink: updateUserLink,
showLinkUserErrorMessage: showLinkUserErrorMessage, showLinkUserErrorMessage: showLinkUserErrorMessage,
showConnectServerUnreachableErrorMessage: showConnectServerUnreachableErrorMessage showConnectServerUnreachableErrorMessage: showConnectServerUnreachableErrorMessage
} };
}); });

View file

@ -2,35 +2,39 @@
display: block; display: block;
margin: 0; margin: 0;
margin-bottom: 0 !important; margin-bottom: 0 !important;
/* Remove select styling */
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
font-size: 110%; font-size: 110%;
/* General select styles: change as needed */
font-family: inherit; font-family: inherit;
font-weight: inherit; font-weight: inherit;
padding: .4em .25em; padding: .4em .25em;
/* Prevent padding from causing width overflow */
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
outline: 0 !important; outline: none !important;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: rgba(0,0,0,0);
width: 100% width: 100%;
} }
.emby-input::-moz-focus-inner { .emby-input::-moz-focus-inner {
border: 0 border: 0;
} }
.inputContainer { .inputContainer {
margin-bottom: 1.8em margin-bottom: 1.8em;
} }
.inputLabel { .inputLabel {
display: inline-block; display: inline-block;
margin-bottom: .25em margin-bottom: .25em;
} }
.emby-input+.fieldDescription { .emby-input + .fieldDescription {
margin-top: .25em margin-top: .25em;
} }
.emby-input-iconbutton { .emby-input-iconbutton {
-webkit-align-self: flex-end; -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) { define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'registerElement'], function (layoutManager, browser, dom) {
"use strict"; '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) { 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) { if (descriptor && descriptor.configurable) {
var baseSetMethod = descriptor.set; var baseSetMethod = descriptor.set;
descriptor.set = function(value) { descriptor.set = function (value) {
baseSetMethod.call(this, value), this.dispatchEvent(new CustomEvent("valueset", { baseSetMethod.call(this, value);
bubbles: !1,
cancelable: !1 this.dispatchEvent(new CustomEvent('valueset', {
})) bubbles: false,
}, Object.defineProperty(HTMLInputElement.prototype, "value", descriptor), supportsFloatingLabel = !0 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")) { EmbyInputPrototype.createdCallback = function () {
this.classList.add("emby-input");
var parentNode = this.parentNode, if (!this.id) {
document = this.ownerDocument, this.id = 'embyinput' + inputId;
label = document.createElement("label"); inputId++;
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() { } if (this.classList.contains('emby-input')) {
onChange.call(this), document.attachIME && document.attachIME(this), label.classList.add("inputLabelFocused"), label.classList.remove("inputLabelUnfocused") return;
}
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: !0 passive: true
}), dom.addEventListener(this, "blur", function() { });
onChange.call(this), label.classList.remove("inputLabelFocused"), label.classList.add("inputLabelUnfocused")
dom.addEventListener(this, 'blur', function () {
onChange.call(this);
label.classList.remove('inputLabelFocused');
label.classList.add('inputLabelUnfocused');
}, { }, {
passive: !0 passive: true
}), dom.addEventListener(this, "change", onChange, { });
passive: !0
}), dom.addEventListener(this, "input", onChange, { dom.addEventListener(this, 'change', onChange, {
passive: !0 passive: true
}), dom.addEventListener(this, "valueset", onChange, { });
passive: !0 dom.addEventListener(this, 'input', onChange, {
}), browser.orsay && this === document.activeElement && document.attachIME && document.attachIME(this) 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);
} }
}, EmbyInputPrototype.attachedCallback = function() { }
this.labelElement.htmlFor = this.id, onChange.call(this) }
}, EmbyInputPrototype.label = function(text) {
this.labelElement.innerHTML = text };
}, document.registerElement("emby-input", {
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, prototype: EmbyInputPrototype,
extends: "input" extends: 'input'
}) });
}); });

View file

@ -1,32 +1,77 @@
define(["emby-progressring", "dom", "serverNotifications", "events", "registerElement"], function(EmbyProgressRing, dom, serverNotifications, events) { define(['emby-progressring', 'dom', 'serverNotifications', 'events', 'registerElement'], function (EmbyProgressRing, dom, serverNotifications, events) {
"use strict"; 'use strict';
function addNotificationEvent(instance, name, handler) { function addNotificationEvent(instance, name, handler) {
var localHandler = handler.bind(instance); 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) { function removeNotificationEvent(instance, name) {
var handler = 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) { function onRefreshProgress(e, apiClient, info) {
var indicator = this; 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); 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); var EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
EmbyItemRefreshIndicatorPrototype.createdCallback = function() {
EmbyProgressRing.createdCallback && EmbyProgressRing.createdCallback.call(this), addNotificationEvent(this, "RefreshProgress", onRefreshProgress) EmbyItemRefreshIndicatorPrototype.createdCallback = function () {
}, EmbyItemRefreshIndicatorPrototype.attachedCallback = function() {
EmbyProgressRing.attachedCallback && EmbyProgressRing.attachedCallback.call(this) // base method
}, EmbyItemRefreshIndicatorPrototype.detachedCallback = function() { if (EmbyProgressRing.createdCallback) {
EmbyProgressRing.detachedCallback && EmbyProgressRing.detachedCallback.call(this), removeNotificationEvent(this, "RefreshProgress"), this.itemId = null EmbyProgressRing.createdCallback.call(this);
}, document.registerElement("emby-itemrefreshindicator", { }
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, 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) { 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"; 'use strict';
var ItemsContainerProtoType = Object.create(HTMLDivElement.prototype);
function onClick(e) { function onClick(e) {
var itemsContainer = this,
multiSelect = (e.target, itemsContainer.multiSelect); var itemsContainer = this;
multiSelect && !1 === multiSelect.onContainerClick.call(itemsContainer, e) || itemShortcuts.onClick.call(itemsContainer, e) 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) { function disableEvent(e) {
return e.preventDefault(), e.stopPropagation(), !1
e.preventDefault();
e.stopPropagation();
return false;
} }
function onContextMenu(e) { function onContextMenu(e) {
var target = e.target,
card = dom.parentWithAttribute(target, "data-id"); var itemsContainer = this;
if (card && card.getAttribute("data-serverid")) return inputManager.trigger("menu", {
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 sourceElement: card
}), e.preventDefault(), e.stopPropagation(), !1 });
e.preventDefault();
e.stopPropagation();
return false;
}
} }
function getShortcutOptions() { function getShortcutOptions() {
return { 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) { function onDrop(evt, itemsContainer) {
var el = evt.item,
newIndex = evt.newIndex, var el = evt.item;
itemId = el.getAttribute("data-playlistitemid"),
playlistId = el.getAttribute("data-playlistid"); var newIndex = evt.newIndex;
var itemId = el.getAttribute('data-playlistitemid');
var playlistId = el.getAttribute('data-playlistid');
if (!playlistId) { if (!playlistId) {
var oldIndex = evt.oldIndex; var oldIndex = evt.oldIndex;
return void el.dispatchEvent(new CustomEvent("itemdrop", {
el.dispatchEvent(new CustomEvent('itemdrop', {
detail: { detail: {
oldIndex: oldIndex, oldIndex: oldIndex,
newIndex: newIndex, newIndex: newIndex,
playlistItemId: itemId playlistItemId: itemId
}, },
bubbles: !0, bubbles: true,
cancelable: !1 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()
})
} }
function onUserDataChanged(e, apiClient, userData) { var serverId = el.getAttribute('data-serverid');
var itemsContainer = this; var apiClient = connectionManager.getApiClient(serverId);
require(["cardBuilder"], function(cardBuilder) {
cardBuilder.onUserDataChanged(userData, itemsContainer) 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 eventsToMonitor = getEventsToMonitor(itemsContainer); - 1 !== eventsToMonitor.indexOf("markfavorite") ? itemsContainer.notifyRefreshNeeded() : -1 !== eventsToMonitor.indexOf("markplayed") && itemsContainer.notifyRefreshNeeded() }
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);
}
});
});
};
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) { 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) { function onTimerCreated(e, apiClient, data) {
var itemsContainer = this; var itemsContainer = this;
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("timers")) return void itemsContainer.notifyRefreshNeeded();
var programId = data.ProgramId, if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
newTimerId = data.Id;
require(["cardBuilder"], function(cardBuilder) { itemsContainer.notifyRefreshNeeded();
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer) 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) { function onSeriesTimerCreated(e, apiClient, data) {
var itemsContainer = this; 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) { function onTimerCancelled(e, apiClient, data) {
var itemsContainer = this; 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; 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) { function onSeriesTimerCancelled(e, apiClient, data) {
var itemsContainer = this; 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; 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) { function onLibraryChanged(e, apiClient, data) {
var itemsContainer = this,
eventsToMonitor = getEventsToMonitor(itemsContainer); var itemsContainer = this;
if (-1 === eventsToMonitor.indexOf("seriestimers") && -1 === eventsToMonitor.indexOf("timers")) { var eventsToMonitor = getEventsToMonitor(itemsContainer);
var itemsAdded = data.ItemsAdded || [], if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
itemsRemoved = data.ItemsRemoved || [];
if (itemsAdded.length || itemsRemoved.length) { // yes this is an assumption
var parentId = itemsContainer.getAttribute("data-parentid"); return;
}
var itemsAdded = data.ItemsAdded || [];
var itemsRemoved = data.ItemsRemoved || [];
if (!itemsAdded.length && !itemsRemoved.length) {
return;
}
var parentId = itemsContainer.getAttribute('data-parentid');
if (parentId) { if (parentId) {
var foldersAddedTo = data.FoldersAddedTo || [], var foldersAddedTo = data.FoldersAddedTo || [];
foldersRemovedFrom = data.FoldersRemovedFrom || [], var foldersRemovedFrom = data.FoldersRemovedFrom || [];
collectionFolders = data.CollectionFolders || []; var collectionFolders = data.CollectionFolders || [];
if (-1 === foldersAddedTo.indexOf(parentId) && -1 === foldersRemovedFrom.indexOf(parentId) && -1 === collectionFolders.indexOf(parentId)) return
} if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
itemsContainer.notifyRefreshNeeded() return;
} }
} }
itemsContainer.notifyRefreshNeeded();
} }
function onPlaybackStopped(e, stopInfo) { function onPlaybackStopped(e, stopInfo) {
var itemsContainer = this,
state = stopInfo.state, var itemsContainer = this;
eventsToMonitor = getEventsToMonitor(itemsContainer);
if (state.NowPlayingItem && "Video" === state.NowPlayingItem.MediaType) { var state = stopInfo.state;
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) 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 addNotificationEvent(instance, name, handler, owner) { function addNotificationEvent(instance, name, handler, owner) {
var localHandler = handler.bind(instance); 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) { 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) { 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) { 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) { function onDataFetched(result) {
var items = result.Items || result,
parentContainer = this.parentContainer; var items = result.Items || result;
parentContainer && (items.length ? parentContainer.classList.remove("hide") : parentContainer.classList.add("hide"));
var focusId, hasActiveElement, activeElement = document.activeElement; var parentContainer = this.parentContainer;
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) 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) { function setFocus(itemsContainer, focusId) {
if (focusId) { if (focusId) {
var newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]'); var newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]');
if (newElement) try { if (newElement) {
return void focusManager.focus(newElement)
} catch (err) {} try {
focusManager.focus(newElement);
return;
} }
focusManager.autoFocus(itemsContainer) catch (err) {
} }
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)
} }
})
}) focusManager.autoFocus(itemsContainer);
} }
}, ItemsContainerProtoType.createdCallback = function() {
this.classList.add("itemsContainer") document.registerElement('emby-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", {
prototype: ItemsContainerProtoType, prototype: ItemsContainerProtoType,
extends: "div" extends: 'div'
}) });
}); });

View file

@ -1,157 +1,105 @@
.progressring { .progressring {
position: relative; position: relative;
width: 2.6em; width: 2.6em;
height: 2.6em; height: 2.6em;
float: left; float: left;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
-webkit-box-sizing: border-box; box-sizing: border-box;
box-sizing: border-box
} }
.progressring-bg { .progressring-bg {
width: 100%; width: 100%;
height: 100%; height: 100%;
-webkit-border-radius: 50%;
border-radius: 50%; border-radius: 50%;
border: .25em solid rgba(0, 0, 0, 1); border: .25em solid rgba(0, 0, 0, 1);
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
background: rgba(0, 0, 0, .9); background: rgba(0, 0, 0, .9);
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center; justify-content: 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
} }
.progressring-text { .progressring-text {
text-align: center; text-align: center;
color: #ddd; color: #ddd;
font-size: 90% font-size: 90%;
} }
.spiner-holder-one { .spiner-holder-one {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
width: 51%; width: 51%;
height: 51%; height: 51%;
box-sizing: border-box background: transparent;
box-sizing: border-box;
} }
.spiner-holder-two { .spiner-holder-two {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
width: 100%; width: 100%;
height: 100%; height: 100%;
box-sizing: border-box background: transparent;
box-sizing: border-box;
} }
.progressring-spiner { .progressring-spiner {
width: 200%; width: 200%;
height: 200%; height: 200%;
-webkit-border-radius: 50%;
border-radius: 50%; border-radius: 50%;
border-width: .25em; border-width: .25em;
border-style: solid; border-style: solid;
-webkit-box-sizing: border-box; box-sizing: border-box;
box-sizing: border-box
} }
.animate-0-25-a { .animate-0-25-a {
-webkit-transform: rotate(90deg);
transform: rotate(90deg); transform: rotate(90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%; transform-origin: 100% 100%;
-webkit-transition: -webkit-transform 180ms ease-out; transition: 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
} }
.animate-0-25-b { .animate-0-25-b {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg); transform: rotate(-90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%; transform-origin: 100% 100%;
transition: transform 180ms ease-out transition: transform 180ms ease-out;
} }
.animate-25-50-a { .animate-25-50-a {
-webkit-transform: rotate(180deg);
transform: rotate(180deg); transform: rotate(180deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%; transform-origin: 100% 100%;
transition: transform 180ms ease-out 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
} }
.animate-25-50-b { .animate-25-50-b {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg); transform: rotate(-90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%; transform-origin: 100% 100%;
transition: transform 180ms ease-out transition: transform 180ms ease-out;
} }
.animate-50-75-a { .animate-50-75-a {
-webkit-transform: rotate(270deg);
transform: rotate(270deg); transform: rotate(270deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%; transform-origin: 100% 100%;
transition: transform 180ms ease-out 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
} }
.animate-50-75-b { .animate-50-75-b {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg); transform: rotate(-90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%; transform-origin: 100% 100%;
transition: transform 180ms ease-out transition: transform 180ms ease-out;
} }
.animate-75-100-a { .animate-75-100-a {
-webkit-transform: rotate(0); transform: rotate(0deg);
transform: rotate(0);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%; transform-origin: 100% 100%;
transition: transform 180ms ease-out transition: transform 180ms ease-out;
} }
.animate-75-100-b { .animate-75-100-b {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg); transform: rotate(-90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%; transform-origin: 100% 100%;
-webkit-transition: -webkit-transform 180ms ease-out; transition: transform 180ms ease-out;
-o-transition: transform 180ms ease-out;
transition: transform 180ms ease-out
} }

View file

@ -1,21 +1,105 @@
define(["require", "css!./emby-progressring", "registerElement"], function(require) { define(['require', 'css!./emby-progressring', 'registerElement'], function (require) {
"use strict"; 'use strict';
var EmbyProgressRing = Object.create(HTMLDivElement.prototype); var EmbyProgressRing = Object.create(HTMLDivElement.prototype);
return EmbyProgressRing.createdCallback = function() {
this.classList.add("progressring"); EmbyProgressRing.createdCallback = function () {
this.classList.add('progressring');
var instance = this; var instance = this;
require(["text!./emby-progressring.template.html"], function(template) {
instance.innerHTML = template, instance.setProgress(parseFloat(instance.getAttribute("data-progress") || "0")) require(['text!./emby-progressring.template.html'], function (template) {
}) instance.innerHTML = template;
}, EmbyProgressRing.setProgress = function(progress) {
//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); progress = Math.floor(progress);
var angle; 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; 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, prototype: EmbyProgressRing,
extends: "div" extends: 'div'
}), EmbyProgressRing });
return EmbyProgressRing;
}); });

View file

@ -2,26 +2,26 @@
position: relative; position: relative;
line-height: 24px; line-height: 24px;
display: inline-block; display: inline-block;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
padding-left: 24px padding-left: 0;
} }
.radio-label-block { .radio-label-block {
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
margin-top: .5em; margin-top: .5em;
margin-bottom: .5em margin-bottom: .5em;
}
.mdl-radio {
padding-left: 24px;
} }
.mdl-radio__button { .mdl-radio__button {
line-height: 24px; line-height: 24px;
position: absolute; position: absolute;
/* 1px is for focusing purposes, so the focusManager doesn't skip over it */
width: 1px; width: 1px;
height: 1px; height: 1px;
margin: 0; margin: 0;
@ -31,7 +31,7 @@
-moz-appearance: none; -moz-appearance: none;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
border: none border: none;
} }
.mdl-radio__outer-circle { .mdl-radio__outer-circle {
@ -39,25 +39,23 @@
top: 4px; top: 4px;
left: 0; left: 0;
display: inline-block; display: inline-block;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
width: 16px; width: 16px;
height: 16px; height: 16px;
margin: 0; margin: 0;
cursor: pointer; cursor: pointer;
border: 2px solid currentcolor; border: 2px solid currentcolor;
-webkit-border-radius: 50%;
border-radius: 50%; border-radius: 50%;
z-index: 2 z-index: 2;
} }
.mdl-radio__button:checked+.mdl-radio__label+.mdl-radio__outer-circle { .mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle {
border: 2px solid #00a4dc border: 2px solid #00a4dc;
} }
.mdl-radio__button:disabled+.mdl-radio__label+.mdl-radio__outer-circle { .mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle {
border: 2px solid rgba(0, 0, 0, .26); border: 2px solid rgba(0,0,0, 0.26);
cursor: auto cursor: auto;
} }
.mdl-radio__inner-circle { .mdl-radio__inner-circle {
@ -66,52 +64,44 @@
margin: 0; margin: 0;
top: 8px; top: 8px;
left: 4px; left: 4px;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
width: 8px; width: 8px;
height: 8px; height: 8px;
cursor: pointer; cursor: pointer;
-webkit-transition-duration: .28s; transition-duration: 0.28s;
-o-transition-duration: .28s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: .28s; transition-property: -webkit-transform;
-webkit-transition-timing-function: cubic-bezier(.4, 0, .2, 1); transition-property: transform;
-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-property: transform, -webkit-transform; transition-property: transform, -webkit-transform;
-webkit-transform: scale3d(0, 0, 0); -webkit-transform: scale3d(0, 0, 0);
transform: scale3d(0, 0, 0); transform: scale3d(0, 0, 0);
-webkit-border-radius: 50%;
border-radius: 50%; border-radius: 50%;
background: #00a4dc background: #00a4dc;
} }
.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); -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 { .mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
background: rgba(0, 0, 0, .26); background: rgba(0,0,0, 0.26);
cursor: auto cursor: auto;
} }
.mdl-radio__button:focus+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle { .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 0px 10px rgba(255, 255, 255, 0.76);
box-shadow: 0 0 0 10px rgba(255, 255, 255, .76)
} }
.mdl-radio__button:checked:focus+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle { .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, 0.26)
box-shadow: 0 0 0 10px rgba(0,164,220, .26)
} }
.mdl-radio__label { .mdl-radio__label {
cursor: pointer cursor: pointer;
} }
.mdl-radio__button:disabled+.mdl-radio__label { .mdl-radio__button:disabled + .mdl-radio__label {
color: rgba(0, 0, 0, .26); color: rgba(0,0,0, 0.26);
cursor: auto cursor: auto;
} }

View file

@ -1,20 +1,48 @@
define(["css!./emby-radio", "registerElement"], function() { define(['css!./emby-radio', 'registerElement'], function () {
"use strict"; 'use strict';
var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
function onKeyDown(e) { function onKeyDown(e) {
if (13 === e.keyCode) return e.preventDefault(), this.checked = !0, !1
// Don't submit form on enter
if (e.keyCode === 13) {
e.preventDefault();
this.checked = true;
return false;
} }
var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype); }
EmbyRadioPrototype.attachedCallback = function() {
if ("true" !== this.getAttribute("data-radio")) { EmbyRadioPrototype.attachedCallback = function () {
this.setAttribute("data-radio", "true"), this.classList.add("mdl-radio__button");
if (this.getAttribute('data-radio') === 'true') {
return;
}
this.setAttribute('data-radio', 'true');
this.classList.add('mdl-radio__button');
var labelElement = this.parentNode; var labelElement = this.parentNode;
labelElement.classList.add("mdl-radio"), labelElement.classList.add("mdl-js-radio"), labelElement.classList.add("mdl-js-ripple-effect"); //labelElement.classList.add('"mdl-radio mdl-js-radio mdl-js-ripple-effect');
var labelTextElement = labelElement.querySelector("span"); labelElement.classList.add('mdl-radio');
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) labelElement.classList.add('mdl-js-radio');
} labelElement.classList.add('mdl-js-ripple-effect');
}, document.registerElement("emby-radio", {
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, prototype: EmbyRadioPrototype,
extends: "input" extends: 'input'
}) });
}); });

View file

@ -1,67 +1,60 @@
.emby-scrollbuttons-scroller { .emby-scrollbuttons-scroller {
position: relative position: relative;
} }
.scrollbuttoncontainer { .scrollbuttoncontainer {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
z-index: 1; z-index: 1;
font-size: 3em; font-size: 3em;
color: #fff; color: #fff;
display: none; display: none;
overflow: hidden overflow: hidden;
} }
.scrollbuttoncontainer-left { .scrollbuttoncontainer-left {
background: rgba(20, 20, 20, .5); background: rgba(20, 20, 20, .5);
background: -webkit-linear-gradient(left, #000 0, rgba(0, 0, 0, 0) 100%); background: -moz-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 0,rgba(0,0,0,0) 100%);
background: -webkit-linear-gradient(left, #000, rgba(0, 0, 0, 0)); background: linear-gradient(to right,#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
} }
.scrollbuttoncontainer-right { .scrollbuttoncontainer-right {
background: rgba(20, 20, 20, .5); background: rgba(20, 20, 20, .5);
background: -webkit-linear-gradient(right, #000 0, rgba(0, 0, 0, 0) 100%); background: -moz-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 0,rgba(0,0,0,0) 100%);
background: -webkit-linear-gradient(right, #000, rgba(0, 0, 0, 0)); background: linear-gradient(to left,#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
} }
.emby-scrollbuttons-scroller:hover .scrollbuttoncontainer { .emby-scrollbuttons-scroller:hover .scrollbuttoncontainer {
display: -webkit-box; display: flex;
display: -webkit-flex; }
display: flex
.scrollbuttoncontainer-left {
left: 0;
}
.scrollbuttoncontainer-right {
right: 0;
} }
.emby-scrollbuttons-scrollbutton { .emby-scrollbuttons-scrollbutton {
margin: 0 -.2em; margin: 0 -.2em;
-webkit-transition: -webkit-transform 160ms ease-out; transition: transform 160ms ease-out;
-o-transition: transform 160ms ease-out;
transition: transform 160ms ease-out
} }
.scrollbuttoncontainer:hover>.emby-scrollbuttons-scrollbutton { .scrollbuttoncontainer:hover > .emby-scrollbuttons-scrollbutton {
-webkit-transform: scale(1.3, 1.3); transform: scale(1.3, 1.3);
transform: scale(1.3, 1.3)
} }
.emby-scrollbuttons-scrollbutton:after { .emby-scrollbuttons-scrollbutton:after {
content: ''; content: '';
display: none !important display: none !important;
} }
.emby-scrollbuttons-scrollbutton:focus { .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) { define(['layoutManager', 'dom', 'css!./emby-scrollbuttons', 'registerElement', 'paper-icon-button-light'], function (layoutManager, dom) {
"use strict"; 'use strict';
var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
EmbyScrollButtonsPrototype.createdCallback = function () {
};
function getScrollButtonContainerHtml(direction) { function getScrollButtonContainerHtml(direction) {
var html = "";
html += '<div class="scrollbuttoncontainer scrollbuttoncontainer-' + direction + ("left" === direction ? " hide" : "") + '">'; var html = '';
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 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) { function getScrollPosition(parent) {
return parent.getScrollPosition ? parent.getScrollPosition() : 0
if (parent.getScrollPosition) {
return parent.getScrollPosition();
}
return 0;
} }
function getScrollWidth(parent) { function getScrollWidth(parent) {
return parent.getScrollSize ? parent.getScrollSize() : 0
if (parent.getScrollSize) {
return parent.getScrollSize();
}
return 0;
} }
function onScrolledToPosition(scrollButtons, pos, scrollWidth) { 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) { function onScroll(e) {
var scrollButtons = this,
scroller = this.scroller; var scrollButtons = this;
onScrolledToPosition(scrollButtons, getScrollPosition(scroller), getScrollWidth(scroller)) var scroller = this.scroller;
var pos = getScrollPosition(scroller);
var scrollWidth = getScrollWidth(scroller);
onScrolledToPosition(scrollButtons, pos, scrollWidth);
} }
function getStyleValue(style, name) { function getStyleValue(style, name) {
var value = style.getPropertyValue(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) { function getScrollSize(elem) {
var scrollSize = elem.offsetWidth,
style = window.getComputedStyle(elem, null), var scrollSize = elem.offsetWidth;
paddingLeft = getStyleValue(style, "padding-left");
paddingLeft && (scrollSize -= paddingLeft); var style = window.getComputedStyle(elem, null);
var paddingRight = getStyleValue(style, "padding-right");
paddingRight && (scrollSize -= paddingRight); var paddingLeft = getStyleValue(style, 'padding-left');
if (paddingLeft) {
scrollSize -= paddingLeft;
}
var paddingRight = getStyleValue(style, 'padding-right');
if (paddingRight) {
scrollSize -= paddingRight;
}
var slider = elem.getScrollSlider(); 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) { function onScrollButtonClick(e) {
var newPos, parent = dom.parentWithAttribute(this, "is", "emby-scroller"),
direction = this.getAttribute("data-direction"), var parent = dom.parentWithAttribute(this, 'is', 'emby-scroller');
scrollSize = getScrollSize(parent),
pos = getScrollPosition(parent); var direction = this.getAttribute('data-direction');
newPos = "left" === direction ? Math.max(0, pos - scrollSize) : pos + scrollSize, parent.scrollToPosition(newPos, !1)
var scrollSize = getScrollSize(parent);
var pos = getScrollPosition(parent);
var newPos;
if (direction === 'left') {
newPos = Math.max(0, pos - scrollSize);
} else {
newPos = pos + scrollSize;
} }
var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
EmbyScrollButtonsPrototype.createdCallback = function() {}, EmbyScrollButtonsPrototype.attachedCallback = function() { parent.scrollToPosition(newPos, false);
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); var scrollHandler = onScroll.bind(this);
this.scrollHandler = scrollHandler; 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, { var buttons = this.querySelectorAll('.emby-scrollbuttons-scrollbutton');
capture: !1, buttons[0].addEventListener('click', onScrollButtonClick);
passive: !0 buttons[1].addEventListener('click', onScrollButtonClick);
})
}, EmbyScrollButtonsPrototype.detachedCallback = function() { 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; var parent = this.scroller;
this.scroller = null; this.scroller = null;
var scrollHandler = this.scrollHandler; var scrollHandler = this.scrollHandler;
parent && scrollHandler && parent.removeScrollEventListener(scrollHandler, {
capture: !1, if (parent && scrollHandler) {
passive: !0 parent.removeScrollEventListener(scrollHandler, {
}), this.scrollHandler = null, this.scrollButtonsLeft = null, this.scrollButtonsRight = null capture: false,
}, document.registerElement("emby-scrollbuttons", { passive: true
});
}
this.scrollHandler = null;
this.scrollButtonsLeft = null;
this.scrollButtonsRight = null;
};
document.registerElement('emby-scrollbuttons', {
prototype: EmbyScrollButtonsPrototype, 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) { define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'browser', 'registerElement'], function (scroller, dom, layoutManager, inputManager, focusManager, browser) {
"use strict"; 'use strict';
var ScrollerProtoType = Object.create(HTMLDivElement.prototype);
ScrollerProtoType.createdCallback = function () {
this.classList.add('emby-scroller');
};
function initCenterFocus(elem, scrollerInstance) { function initCenterFocus(elem, scrollerInstance) {
dom.addEventListener(elem, "focus", function(e) {
dom.addEventListener(elem, 'focus', function (e) {
var focused = focusManager.focusableParent(e.target); var focused = focusManager.focusableParent(e.target);
focused && scrollerInstance.toCenter(focused)
}, { if (focused) {
capture: !0, scrollerInstance.toCenter(focused);
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) { function onInputCommand(e) {
var cmd = e.detail.command; 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) { function initHeadroom(elem) {
require(["headroom"], function(Headroom) { require(['headroom'], function (Headroom) {
var headroom = new Headroom([], { var headroom = new Headroom([], {
scroller: elem scroller: elem
}); });
headroom.init(), headroom.add(document.querySelector(".skinHeader")), elem.headroom = headroom // initialise
}) headroom.init();
headroom.add(document.querySelector('.skinHeader'));
elem.headroom = headroom;
});
} }
function loadScrollButtons(scroller) { ScrollerProtoType.attachedCallback = function () {
require(["emby-scrollbuttons"], function() {
scroller.insertAdjacentHTML("beforeend", '<div is="emby-scrollbuttons"></div>') if (this.getAttribute('data-navcommands')) {
}) inputManager.on(this, onInputCommand);
} }
var ScrollerProtoType = Object.create(HTMLDivElement.prototype);
ScrollerProtoType.createdCallback = function() { var horizontal = this.getAttribute('data-horizontal') !== 'false';
this.classList.add("emby-scroller")
}, ScrollerProtoType.scrollToBeginning = function() { var slider = this.querySelector('.scrollSlider');
this.scroller && this.scroller.slideTo(0, !0)
}, ScrollerProtoType.toStart = function(elem, immediate) { if (horizontal) {
this.scroller && this.scroller.toStart(elem, immediate) slider.style['white-space'] = 'nowrap';
}, ScrollerProtoType.toCenter = function(elem, immediate) { }
this.scroller && this.scroller.toCenter(elem, immediate)
}, ScrollerProtoType.scrollToPosition = function(pos, immediate) { var bindHeader = this.getAttribute('data-bindheader') === 'true';
this.scroller && this.scroller.slideTo(pos, immediate)
}, ScrollerProtoType.getScrollPosition = function() { var scrollFrame = this;
if (this.scroller) return this.scroller.getScrollPosition() var enableScrollButtons = layoutManager.desktop && horizontal && this.getAttribute('data-scrollbuttons') !== 'false';
}, ScrollerProtoType.getScrollSize = function() {
if (this.scroller) return this.scroller.getScrollSize() var options = {
}, 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, horizontal: horizontal,
mouseDragging: 1, mouseDragging: 1,
mouseWheel: "false" !== this.getAttribute("data-mousewheel"), mouseWheel: this.getAttribute('data-mousewheel') !== 'false',
touchDragging: 1, touchDragging: 1,
slidee: slider, slidee: slider,
scrollBy: 200, scrollBy: 200,
speed: horizontal ? 270 : 240, speed: horizontal ? 270 : 240,
//immediateSpeed: pageOptions.immediateSpeed,
elasticBounds: 1, elasticBounds: 1,
dragHandle: 1, dragHandle: 1,
scrollWidth: "auto" === this.getAttribute("data-scrollsize") ? null : 5e6, scrollWidth: this.getAttribute('data-scrollsize') === 'auto' ? null : 5000000,
autoImmediate: !0, autoImmediate: true,
skipSlideToWhenVisible: "true" === this.getAttribute("data-skipfocuswhenvisible"), skipSlideToWhenVisible: this.getAttribute('data-skipfocuswhenvisible') === 'true',
dispatchScrollEvent: enableScrollButtons || bindHeader || "true" === this.getAttribute("data-scrollevent"), dispatchScrollEvent: enableScrollButtons || bindHeader || this.getAttribute('data-scrollevent') === 'true',
hideScrollbar: enableScrollButtons || "true" === this.getAttribute("data-hidescrollbar"), hideScrollbar: enableScrollButtons || this.getAttribute('data-hidescrollbar') === 'true',
allowNativeSmoothScroll: "true" === this.getAttribute("data-allownativesmoothscroll") && !enableScrollButtons, allowNativeSmoothScroll: this.getAttribute('data-allownativesmoothscroll') === 'true' && !enableScrollButtons,
allowNativeScroll: !enableScrollButtons, allowNativeScroll: !enableScrollButtons,
forceHideScrollbars: enableScrollButtons, forceHideScrollbars: enableScrollButtons,
// In edge, with the native scroll, the content jumps around when hovering over the buttons
requireAnimation: enableScrollButtons && browser.edge 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() { // 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>');
});
}
ScrollerProtoType.pause = function () {
var headroom = this.headroom; var headroom = this.headroom;
headroom && headroom.pause() if (headroom) {
}, ScrollerProtoType.resume = function() { headroom.pause();
}
};
ScrollerProtoType.resume = function () {
var headroom = this.headroom; var headroom = this.headroom;
headroom && headroom.resume() if (headroom) {
}, ScrollerProtoType.detachedCallback = function() { headroom.resume();
this.getAttribute("data-navcommands") && inputManager.off(this, onInputCommand); }
};
ScrollerProtoType.detachedCallback = function () {
if (this.getAttribute('data-navcommands')) {
inputManager.off(this, onInputCommand);
}
var headroom = this.headroom; var headroom = this.headroom;
headroom && (headroom.destroy(), this.headroom = null); if (headroom) {
headroom.destroy();
this.headroom = null;
}
var scrollerInstance = this.scroller; var scrollerInstance = this.scroller;
scrollerInstance && (scrollerInstance.destroy(), this.scroller = null) if (scrollerInstance) {
}, document.registerElement("emby-scroller", { scrollerInstance.destroy();
this.scroller = null;
}
};
document.registerElement('emby-scroller', {
prototype: ScrollerProtoType, prototype: ScrollerProtoType,
extends: "div" extends: 'div'
}) });
}); });

View file

@ -2,91 +2,84 @@
display: block; display: block;
margin: 0; margin: 0;
margin-bottom: 0 !important; margin-bottom: 0 !important;
/* Remove select styling */
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
font-size: 110%; font-size: 110%;
/* General select styles: change as needed */
font-family: inherit; font-family: inherit;
font-weight: inherit; font-weight: inherit;
padding: .5em 1.9em .5em .5em; padding: .5em 1.9em .5em .5em;
-webkit-box-sizing: border-box; /* Prevent padding from causing width overflow */
box-sizing: border-box; box-sizing: border-box;
outline: 0 !important; outline: none !important;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: rgba(0,0,0,0);
width: 100% width: 100%;
} }
.emby-select[disabled] { .emby-select[disabled] {
background: 0 0 !important; background: none !important;
border-color: transparent !important; border-color: transparent !important;
color: inherit !important; color: inherit !important;
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
appearance: none appearance: none;
} }
.selectContainer-inline>.emby-select { .selectContainer-inline > .emby-select {
padding: .3em 1.9em .3em .5em; padding: .3em 1.9em .3em .5em;
font-size: inherit font-size: inherit;
} }
.selectContainer-inline>.emby-select[disabled] { .selectContainer-inline > .emby-select[disabled] {
padding-left: 0; padding-left: 0;
padding-right: 0 padding-right: 0;
} }
.emby-select::-moz-focus-inner { .emby-select::-moz-focus-inner {
border: 0 border: 0;
} }
.emby-select-focusscale { .emby-select-focusscale {
-webkit-transition: -webkit-transform 180ms ease-out !important;
-o-transition: transform 180ms ease-out !important;
transition: transform 180ms ease-out !important; transition: transform 180ms ease-out !important;
-webkit-transform-origin: center center; -webkit-transform-origin: center center;
transform-origin: center center transform-origin: center center;
} }
.emby-select-focusscale:focus { .emby-select-focusscale:focus {
-webkit-transform: scale(1.04);
transform: scale(1.04); transform: scale(1.04);
z-index: 1 z-index: 1;
} }
.emby-select+.fieldDescription { .emby-select + .fieldDescription {
margin-top: .25em margin-top: .25em;
} }
.selectContainer { .selectContainer {
margin-bottom: 1.8em; margin-bottom: 1.8em;
position: relative position: relative;
} }
.selectContainer-inline { .selectContainer-inline {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
margin-bottom: 0; margin-bottom: 0;
-webkit-box-align: center; align-items: center;
-webkit-align-items: center;
align-items: center
} }
.selectLabel { .selectLabel {
display: block; display: block;
margin-bottom: .25em margin-bottom: .25em;
} }
.selectContainer-inline>.selectLabel { .selectContainer-inline > .selectLabel {
margin-bottom: 0; margin-bottom: 0;
margin-right: .5em; margin-right: .5em;
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
.emby-select-withcolor { .emby-select-withcolor {
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none;
appearance: none; appearance: none;
-webkit-border-radius: .2em; border-radius: .2em;
border-radius: .2em
} }
.selectArrowContainer { .selectArrowContainer {
@ -94,25 +87,24 @@
right: .3em; right: .3em;
top: .2em; top: .2em;
color: inherit; color: inherit;
pointer-events: none pointer-events: none;
} }
.selectContainer-inline>.selectArrowContainer { .selectContainer-inline > .selectArrowContainer {
top: initial; top: initial;
bottom: .24em; bottom: .24em;
font-size: 90% font-size: 90%;
} }
.emby-select[disabled]+.selectArrowContainer { .emby-select[disabled] + .selectArrowContainer {
display: none display: none;
} }
.selectArrow { .selectArrow {
margin-top: .35em; margin-top: .35em;
font-size: 1.7em font-size: 1.7em;
} }
.emby-select-iconbutton { .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) { define(['layoutManager', 'browser', 'actionsheet', 'css!./emby-select', 'registerElement'], function (layoutManager, browser, actionsheet) {
"use strict"; 'use strict';
var EmbySelectPrototype = Object.create(HTMLSelectElement.prototype);
function enableNativeMenu() { 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) { function triggerChange(select) {
var evt = document.createEvent("HTMLEvents"); 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) { function setValue(select, value) {
select.value = value
select.value = value;
} }
function showActionSheet(select) { 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({ actionsheet.show({
items: select.options, items: select.options,
positionTo: select, positionTo: select,
title: title title: title
}).then(function(value) {
setValue(select, value), triggerChange(select) }).then(function (value) {
}) setValue(select, value);
triggerChange(select);
});
} }
function getLabel(select) { function getLabel(select) {
for (var elem = select.previousSibling; elem && "LABEL" !== elem.tagName;) elem = elem.previousSibling; var elem = select.previousSibling;
return elem while (elem && elem.tagName !== 'LABEL') {
elem = elem.previousSibling;
}
return elem;
} }
function onFocus(e) { function onFocus(e) {
var label = getLabel(this); var label = getLabel(this);
label && label.classList.add("selectLabelFocused") if (label) {
label.classList.add('selectLabelFocused');
}
} }
function onBlur(e) { function onBlur(e) {
var label = getLabel(this); var label = getLabel(this);
label && label.classList.remove("selectLabelFocused") if (label) {
label.classList.remove('selectLabelFocused');
}
} }
function onMouseDown(e) { 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) { function onKeyDown(e) {
switch (e.keyCode) { switch (e.keyCode) {
case 13: case 13:
return void(enableNativeMenu() || (e.preventDefault(), showActionSheet(this))); if (!enableNativeMenu()) {
e.preventDefault();
showActionSheet(this);
}
return;
case 37: case 37:
case 38: case 38:
case 39: case 39:
case 40: case 40:
return void(layoutManager.tv && e.preventDefault()) if (layoutManager.tv) {
e.preventDefault();
}
return;
default:
break;
} }
} }
var EmbySelectPrototype = Object.create(HTMLSelectElement.prototype),
inputId = 0; var 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.createdCallback = function () {
}, EmbySelectPrototype.attachedCallback = function() {
if (!this.classList.contains("emby-select")) { if (!this.id) {
this.classList.add("emby-select"); this.id = 'embyselect' + inputId;
var label = this.ownerDocument.createElement("label"); inputId++;
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>')
} }
}, EmbySelectPrototype.setLabel = function(text) {
this.parentNode.querySelector("label").innerHTML = text if (!browser.firefox) {
}, document.registerElement("emby-select", { 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, prototype: EmbySelectPrototype,
extends: "select" extends: 'select'
}) });
}); });

View file

@ -1,7 +1,7 @@
_:-ms-input-placeholder { _:-ms-input-placeholder {
-ms-appearance: none; -ms-appearance: none;
height: 2.223em; height: 2.223em;
margin: 0 margin: 0;
} }
.mdl-slider { .mdl-slider {
@ -11,7 +11,7 @@ _:-ms-input-placeholder {
-ms-appearance: none; -ms-appearance: none;
appearance: none; appearance: none;
height: .2em; height: .2em;
background: 0 0; background: transparent;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
@ -20,78 +20,79 @@ _:-ms-input-placeholder {
padding: 1em 0; padding: 1em 0;
color: #00a4dc; color: #00a4dc;
-webkit-align-self: center; -webkit-align-self: center;
-ms-flex-item-align: center;
align-self: center; align-self: center;
z-index: 1; z-index: 1;
cursor: pointer; cursor: pointer;
margin: 0; margin: 0;
-webkit-tap-highlight-color: transparent; /* Disable webkit tap highlighting */
display: block -webkit-tap-highlight-color: rgba(0,0,0,0);
display: block;
/**************************** Tracks ****************************/
/**************************** Thumbs ****************************/
/**************************** 0-value ****************************/
/**************************** Disabled ****************************/
} }
.mdl-slider::-moz-focus-outer { .mdl-slider::-moz-focus-outer {
border: 0 border: 0;
} }
.mdl-slider::-ms-tooltip { .mdl-slider::-ms-tooltip {
display: none display: none;
} }
.mdl-slider::-webkit-slider-runnable-track { .mdl-slider::-webkit-slider-runnable-track {
background: 0 0 background: transparent;
} }
.mdl-slider::-moz-range-track { .mdl-slider::-moz-range-track {
background: #444; background: #444;
border: none border: none;
} }
.mdl-slider::-moz-range-progress { .mdl-slider::-moz-range-progress {
background: #00a4dc background: #00a4dc;
} }
.mdl-slider::-ms-track { .mdl-slider::-ms-track {
background: 0 0; background: none;
color: transparent; color: transparent;
height: .2em; height: .2em;
width: 100%; width: 100%;
border: none border: none;
} }
.mdl-slider::-ms-fill-lower { .mdl-slider::-ms-fill-lower {
display: none display: none;
} }
.mdl-slider::-ms-fill-upper { .mdl-slider::-ms-fill-upper {
display: none display: none;
} }
.mdl-slider::-webkit-slider-thumb { .mdl-slider::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
width: 1.8em; width: 1.8em;
height: 1.8em; height: 1.8em;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
-webkit-border-radius: 50%;
border-radius: 50%; border-radius: 50%;
background: #00a4dc; background: #00a4dc;
border: none; 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 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);
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-hoverthumb::-webkit-slider-thumb { .mdl-slider-hoverthumb::-webkit-slider-thumb {
margin-left: -.12em; margin-left: -.12em;
-webkit-transform: scale(.7, .7); transform: scale(.7, .7);
transform: scale(.7, .7)
} }
.mdl-slider:hover::-webkit-slider-thumb { .mdl-slider:hover::-webkit-slider-thumb {
-webkit-transform: none; transform: none;
transform: none
} }
.slider-no-webkit-thumb::-webkit-slider-thumb { .slider-no-webkit-thumb::-webkit-slider-thumb {
opacity: 0 !important opacity: 0 !important;
} }
.mdl-slider::-moz-range-thumb { .mdl-slider::-moz-range-thumb {
@ -100,8 +101,9 @@ _:-ms-input-placeholder {
height: 1.8em; height: 1.8em;
box-sizing: border-box; box-sizing: border-box;
border-radius: 50%; border-radius: 50%;
background-image: none;
background: #00a4dc; background: #00a4dc;
border: none border: none;
} }
.mdl-slider::-ms-thumb { .mdl-slider::-ms-thumb {
@ -112,28 +114,28 @@ _:-ms-input-placeholder {
border-radius: 50%; border-radius: 50%;
background: #00a4dc; background: #00a4dc;
border: none; 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 { .mdl-slider-hoverthumb::-ms-thumb {
margin-left: -.4em; margin-left: -.4em;
transform: scale(.5, .5) transform: scale(.5, .5);
} }
.mdl-slider:hover::-ms-thumb { .mdl-slider:hover::-ms-thumb {
transform: none transform: none;
} }
.mdl-slider[disabled]::-webkit-slider-thumb { .mdl-slider[disabled]::-webkit-slider-thumb {
display: none display: none;
} }
.mdl-slider[disabled]::-moz-range-thumb { .mdl-slider[disabled]::-moz-range-thumb {
display: none display: none;
} }
.mdl-slider[disabled]::-ms-thumb { .mdl-slider[disabled]::-ms-thumb {
display: none display: none;
} }
.mdl-slider-ie-container { .mdl-slider-ie-container {
@ -141,20 +143,15 @@ _:-ms-input-placeholder {
overflow: visible; overflow: visible;
border: none; border: none;
margin: 0; margin: 0;
padding: 0 padding: 0;
} }
.mdl-slider-container { .mdl-slider-container {
height: 1.25em; height: 1.25em;
position: relative; position: relative;
background: 0 0; background: none;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-orient: horizontal; flex-direction: row;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row
} }
.mdl-slider-background-flex { .mdl-slider-background-flex {
@ -165,70 +162,62 @@ _:-ms-input-placeholder {
width: 100%; width: 100%;
top: 50%; top: 50%;
left: 0; left: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
overflow: hidden; overflow: hidden;
border: 0; border: 0;
padding: 0 padding: 0;
} }
.mdl-slider-background-flex-inner { .mdl-slider-background-flex-inner {
position: relative; position: relative;
width: 100% width: 100%;
} }
.mdl-slider-background-lower { .mdl-slider-background-lower {
/*transition: width 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/
position: absolute; position: absolute;
left: 0; left: 0;
width: 0; width: 0;
top: 0; top: 0;
bottom: 0; bottom: 0;
background-color: #00a4dc background-color: #00a4dc;
} }
.mdl-slider-background-lower-clear { .mdl-slider-background-lower-clear {
background-color: transparent background-color: transparent;
} }
.mdl-slider-background-lower-withtransform { .mdl-slider-background-lower-withtransform {
width: 100%; width: 100%;
-webkit-transform-origin: left center; /*transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/
transform-origin: left center; transform-origin: left center;
-webkit-transform: scaleX(0); transform: scaleX(0);
transform: scaleX(0)
} }
.mdl-slider-background-upper { .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: #666;
background: rgba(255, 255, 255, .4); background: rgba(255, 255, 255, .4);
position: absolute; position: absolute;
left: 0; left: 0;
width: 0; width: 0;
top: 0; top: 0;
bottom: 0 bottom: 0;
} }
.sliderBubble { .sliderBubble {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
-webkit-transform: translate3d(-48%, -120%, 0);
transform: translate3d(-48%, -120%, 0); transform: translate3d(-48%, -120%, 0);
background: #282828; background: #282828;
color: #fff; color: #fff;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center; justify-content: center;
-webkit-justify-content: center;
justify-content: center
} }
.sliderBubbleText { .sliderBubbleText {
margin: 0; 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) { define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom, layoutManager) {
"use strict"; '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() { function updateValues() {
var range = this,
value = range.value; var range = this;
requestAnimationFrame(function() { 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; var backgroundLower = range.backgroundLower;
if (backgroundLower) { if (backgroundLower) {
var fraction = (value - range.min) / (range.max - range.min); 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) { 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) { function setRange(elem, startPercent, endPercent) {
var style = elem.style; var style = elem.style;
style.left = Math.max(startPercent, 0) + "%"; style.left = Math.max(startPercent, 0) + '%';
var widthPercent = endPercent - startPercent; 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) { function mapRangesFromRuntimeToPercent(ranges, runtime) {
return runtime ? ranges.map(function(r) {
if (!runtime) {
return [];
}
return ranges.map(function (r) {
return { return {
start: r.start / runtime * 100, start: (r.start / runtime) * 100,
end: r.end / 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) { function startInterval(range) {
var interval = range.interval; var interval = range.interval;
interval && clearInterval(interval), range.interval = setInterval(updateValues.bind(range), 100) if (interval) {
clearInterval(interval);
} }
var enableWidthWithTransform, EmbySliderPrototype = Object.create(HTMLInputElement.prototype), range.interval = setInterval(updateValues.bind(range), 100);
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")) { EmbySliderPrototype.detachedCallback = function () {
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))
}
}, 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() {
var interval = this.interval; var interval = this.interval;
interval && clearInterval(interval), this.interval = null, this.backgroundUpper = null, this.backgroundLower = null if (interval) {
}, document.registerElement("emby-slider", { clearInterval(interval);
}
this.interval = null;
this.backgroundUpper = null;
this.backgroundLower = null;
};
document.registerElement('emby-slider', {
prototype: EmbySliderPrototype, prototype: EmbySliderPrototype,
extends: "input" extends: 'input'
}) });
}); });

View file

@ -1,43 +1,47 @@
.emby-tab-button, .emby-tab-button {
.emby-tabs-slider { background: transparent;
position: relative
}
.emby-tab-button {
background: 0 0;
-webkit-box-shadow: none;
box-shadow: none; box-shadow: none;
cursor: pointer; cursor: pointer;
outline: 0 !important; outline: none !important;
width: auto; width: auto;
font-family: inherit; font-family: inherit;
font-size: inherit; font-size: inherit;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
-webkit-flex-shrink: 0;
flex-shrink: 0; flex-shrink: 0;
margin: 0; margin: 0;
padding: 1em .9em; padding: 1em .9em;
position: relative;
height: auto; height: auto;
min-width: initial; min-width: initial;
line-height: initial; line-height: initial;
-webkit-border-radius: 0 !important;
border-radius: 0 !important; border-radius: 0 !important;
overflow: hidden; overflow: hidden;
font-weight: 600 font-weight: 600;
} }
.emby-tab-button.emby-button-tv:focus { /*.emby-tab-button-active {
-webkit-transform: scale(1.32); 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: scale(1.32);
-webkit-transform-origin: center center; transform-origin: center center;
transform-origin: center center }
.emby-tabs-slider {
position: relative;
} }
.emby-tab-button-ripple-effect { .emby-tab-button-ripple-effect {
background: rgba(0, 0, 0, .7) !important background: rgba(0,0,0,.7) !important;
} }
.tabContent:not(.is-active) { .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) { define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'registerElement', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser, layoutManager, focusManager) {
"use strict"; 'use strict';
var EmbyTabs = Object.create(HTMLDivElement.prototype);
var buttonClass = 'emby-tab-button';
var activeButtonClass = buttonClass + '-active';
function setActiveTabButton(tabs, newButton, oldButton, animate) { function setActiveTabButton(tabs, newButton, oldButton, animate) {
newButton.classList.add(activeButtonClass)
newButton.classList.add(activeButtonClass);
} }
function getFocusCallback(tabs, e) { function getFocusCallback(tabs, e) {
return function() { return function () {
onClick.call(tabs, e) onClick.call(tabs, e);
} };
} }
function onFocus(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) { function getTabPanel(tabs, index) {
return null
return null;
} }
function removeActivePanelClass(tabs, index) { function removeActivePanelClass(tabs, index) {
var tabPanel = getTabPanel(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) { function fadeInRight(elem) {
var pct = browser.mobile ? "4%" : "0.5%",
keyframes = [{ var pct = browser.mobile ? '4%' : '0.5%';
opacity: "0",
transform: "translate3d(" + pct + ", 0, 0)", var keyframes = [
offset: 0 { opacity: '0', transform: 'translate3d(' + pct + ', 0, 0)', offset: 0 },
}, { { opacity: '1', transform: 'none', offset: 1 }];
opacity: "1",
transform: "none",
offset: 1
}];
elem.animate(keyframes, { elem.animate(keyframes, {
duration: 160, duration: 160,
iterations: 1, iterations: 1,
easing: "ease-out" easing: 'ease-out'
}) });
} }
function triggerBeforeTabChange(tabs, index, previousIndex) { function triggerBeforeTabChange(tabs, index, previousIndex) {
tabs.dispatchEvent(new CustomEvent("beforetabchange", { tabs.dispatchEvent(new CustomEvent("beforetabchange", {
detail: { detail: {
selectedTabIndex: index, selectedTabIndex: index,
previousIndex: previousIndex previousIndex: previousIndex
} }
})), null != previousIndex && previousIndex !== index && removeActivePanelClass(tabs, previousIndex); }));
if (previousIndex != null && previousIndex !== index) {
removeActivePanelClass(tabs, previousIndex);
}
var newPanel = getTabPanel(tabs, index); 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) { function onClick(e) {
this.focusTimeout && clearTimeout(this.focusTimeout);
var tabs = this, if (this.focusTimeout) {
current = tabs.querySelector("." + activeButtonClass), clearTimeout(this.focusTimeout);
tabButton = dom.parentWithClass(e.target, buttonClass); }
var tabs = this;
var current = tabs.querySelector('.' + activeButtonClass);
var tabButton = dom.parentWithClass(e.target, buttonClass);
if (tabButton && tabButton !== current) { if (tabButton && tabButton !== current) {
current && current.classList.remove(activeButtonClass);
var previousIndex = current ? parseInt(current.getAttribute("data-index")) : null; if (current) {
setActiveTabButton(tabs, tabButton, current, !0); current.classList.remove(activeButtonClass);
var index = parseInt(tabButton.getAttribute("data-index")); }
triggerBeforeTabChange(tabs, index, previousIndex), setTimeout(function() {
tabs.selectedTabIndex = index, tabs.dispatchEvent(new CustomEvent("tabchange", { 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: { detail: {
selectedTabIndex: index, selectedTabIndex: index,
previousIndex: previousIndex previousIndex: previousIndex
} }
})) }));
}, 120), tabs.scroller && tabs.scroller.toCenter(tabButton, !1) }, 120);
if (tabs.scroller) {
tabs.scroller.toCenter(tabButton, false);
}
} }
} }
function initScroller(tabs) { function initScroller(tabs) {
if (!tabs.scroller) {
var contentScrollSlider = tabs.querySelector(".emby-tabs-slider"); if (tabs.scroller) {
contentScrollSlider ? (tabs.scroller = new scroller(tabs, { return;
}
var contentScrollSlider = tabs.querySelector('.emby-tabs-slider');
if (contentScrollSlider) {
tabs.scroller = new scroller(tabs, {
horizontal: 1, horizontal: 1,
itemNav: 0, itemNav: 0,
mouseDragging: 1, mouseDragging: 1,
touchDragging: 1, touchDragging: 1,
slidee: contentScrollSlider, slidee: contentScrollSlider,
smart: !0, smart: true,
releaseSwing: !0, releaseSwing: true,
scrollBy: 200, scrollBy: 200,
speed: 120, speed: 120,
elasticBounds: 1, elasticBounds: 1,
dragHandle: 1, dragHandle: 1,
dynamicHandle: 1, dynamicHandle: 1,
clickBar: 1, clickBar: 1,
hiddenScroll: !0, hiddenScroll: true,
// In safari the transform is causing the headers to occasionally disappear or flicker
requireAnimation: !browser.safari, requireAnimation: !browser.safari,
allowNativeSmoothScroll: !0 allowNativeSmoothScroll: true
}), tabs.scroller.init()) : (tabs.classList.add("scrollX"), tabs.classList.add("hiddenScrollX"), tabs.classList.add("smoothScrollX")) });
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) { function getSelectedTabButton(elem) {
return elem.querySelector("." + activeButtonClass)
return elem.querySelector('.' + activeButtonClass);
} }
function getSibling(elem, method) { EmbyTabs.selectedIndex = function (selected, triggerEvent) {
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) {
var tabs = this; var tabs = this;
if (null == selected) return tabs.selectedTabIndex || 0;
if (selected == null) {
return tabs.selectedTabIndex || 0;
}
var current = tabs.selectedIndex(); var current = tabs.selectedIndex();
tabs.selectedTabIndex = selected; tabs.selectedTabIndex = selected;
var tabButtons = tabs.querySelectorAll("." + buttonClass);
if (current === selected || !1 === triggerEvent) { var tabButtons = tabs.querySelectorAll('.' + buttonClass);
triggerBeforeTabChange(tabs, selected, current), tabs.dispatchEvent(new CustomEvent("tabchange", {
if (current === selected || triggerEvent === false) {
triggerBeforeTabChange(tabs, selected, current);
tabs.dispatchEvent(new CustomEvent("tabchange", {
detail: { detail: {
selectedTabIndex: selected selectedTabIndex: selected
} }
})); }));
var currentTabButton = tabButtons[current]; var currentTabButton = tabButtons[current];
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, !1), current !== selected && currentTabButton && currentTabButton.classList.remove(activeButtonClass) setActiveTabButton(tabs, tabButtons[selected], currentTabButton, false);
} else onClick.call(tabs, {
if (current !== selected && currentTabButton) {
currentTabButton.classList.remove(activeButtonClass);
}
} else {
onClick.call(tabs, {
target: tabButtons[selected] target: tabButtons[selected]
}) });
}, EmbyTabs.selectNext = function() { //tabButtons[selected].click();
var current = getSelectedTabButton(this), }
sibling = getSibling(current, "nextSibling"); };
sibling && onClick.call(this, {
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 target: sibling
}) });
}, EmbyTabs.selectPrevious = function() { }
var current = getSelectedTabButton(this), };
sibling = getSibling(current, "previousSibling");
sibling && onClick.call(this, { EmbyTabs.selectPrevious = function () {
var current = getSelectedTabButton(this);
var sibling = getSibling(current, 'previousSibling');
if (sibling) {
onClick.call(this, {
target: sibling target: sibling
}) });
}, EmbyTabs.triggerBeforeTabChange = function(selected) { }
};
EmbyTabs.triggerBeforeTabChange = function (selected) {
var tabs = this; var tabs = this;
triggerBeforeTabChange(tabs, tabs.selectedIndex())
}, EmbyTabs.triggerTabChange = function(selected) { triggerBeforeTabChange(tabs, tabs.selectedIndex());
};
EmbyTabs.triggerTabChange = function (selected) {
var tabs = this; var tabs = this;
tabs.dispatchEvent(new CustomEvent("tabchange", { tabs.dispatchEvent(new CustomEvent("tabchange", {
detail: { detail: {
selectedTabIndex: tabs.selectedIndex() 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 + '"]'); 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, prototype: EmbyTabs,
extends: "div" extends: 'div'
}) });
}); });

View file

@ -2,30 +2,31 @@
display: block; display: block;
margin: 0; margin: 0;
margin-bottom: 0 !important; margin-bottom: 0 !important;
/* Remove select styling */
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
font-size: inherit; font-size: inherit;
/* General select styles: change as needed */
font-family: inherit; font-family: inherit;
font-weight: inherit; font-weight: inherit;
color: inherit; color: inherit;
padding: .35em .25em; padding: .35em .25em;
-webkit-box-sizing: border-box; /* Prevent padding from causing width overflow */
box-sizing: border-box; box-sizing: border-box;
outline: 0 !important; outline: none !important;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: rgba(0,0,0,0);
width: 100% width: 100%;
} }
.emby-textarea::-moz-focus-inner { .emby-textarea::-moz-focus-inner {
border: 0 border: 0;
} }
.textareaLabel { .textareaLabel {
display: inline-block; display: inline-block;
-webkit-transition: all .2s ease-out;
-o-transition: all .2s ease-out;
transition: all .2s ease-out; transition: all .2s ease-out;
margin-bottom: .25em margin-bottom: .25em;
} }
.emby-textarea+.fieldDescription { .emby-textarea + .fieldDescription {
margin-top: .25em margin-top: .25em;
} }

View file

@ -1,55 +1,138 @@
define(["layoutManager", "browser", "css!./emby-textarea", "registerElement", "emby-input"], function(layoutManager, browser) { define(['layoutManager', 'browser', 'css!./emby-textarea', 'registerElement', 'emby-input'], function (layoutManager, browser) {
"use strict"; 'use strict';
function autoGrow(textarea, maxLines) { 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() { 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() { 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); if (!self.lineHeight || self.lineHeight <= 0) {
var newHeight = 0; reset();
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"
} }
var self = this; if (self.lineHeight <= 0) {
void 0 === maxLines && (maxLines = 999), self.getOffset = function(textarea) { textarea.style.overflowY = 'scroll';
for (var style = window.getComputedStyle(textarea, null), props = ["paddingTop", "paddingBottom"], offset = 0, i = 0; i < props.length; i++) offset += parseInt(style[props[i]]); textarea.style.height = 'auto';
return offset textarea.rows = 3;
}; return;
var offset;
textarea.addEventListener("input", autogrowFn), textarea.addEventListener("focus", autogrowFn), textarea.addEventListener("valueset", autogrowFn), autogrowFn()
} }
var EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype), var newHeight = 0, hasGrown = false;
elementId = 0;
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';
}
// 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);
var elementId = 0;
if (Object.getOwnPropertyDescriptor && Object.defineProperty) { 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) { if (descriptor && descriptor.configurable) {
var baseSetMethod = descriptor.set; var baseSetMethod = descriptor.set;
descriptor.set = function(value) { descriptor.set = function (value) {
baseSetMethod.call(this, value), this.dispatchEvent(new CustomEvent("valueset", { baseSetMethod.call(this, value);
bubbles: !1,
cancelable: !1 this.dispatchEvent(new CustomEvent('valueset', {
})) bubbles: false,
}, Object.defineProperty(HTMLTextAreaElement.prototype, "value", descriptor) cancelable: false
}));
};
Object.defineProperty(HTMLTextAreaElement.prototype, 'value', descriptor);
} }
} }
EmbyTextAreaPrototype.createdCallback = function() {
this.id || (this.id = "embytextarea" + elementId, elementId++) EmbyTextAreaPrototype.createdCallback = function () {
}, EmbyTextAreaPrototype.attachedCallback = function() {
if (!this.classList.contains("emby-textarea")) { if (!this.id) {
this.rows = 1, this.classList.add("emby-textarea"); this.id = 'embytextarea' + elementId;
var parentNode = this.parentNode, elementId++;
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", { };
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, prototype: EmbyTextAreaPrototype,
extends: "textarea" extends: 'textarea'
}) });
}); });

View file

@ -2,13 +2,8 @@
position: relative; position: relative;
z-index: 1; z-index: 1;
vertical-align: middle; vertical-align: middle;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -19,17 +14,12 @@
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
-webkit-box-orient: horizontal;
-webkit-box-direction: reverse;
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse; flex-direction: row-reverse;
-webkit-box-pack: end; justify-content: flex-end;
-webkit-justify-content: flex-end;
justify-content: flex-end
} }
.toggleContainer { .toggleContainer {
margin-bottom: 1.8em margin-bottom: 1.8em;
} }
.mdl-switch__input { .mdl-switch__input {
@ -42,29 +32,28 @@
-moz-appearance: none; -moz-appearance: none;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
border: none border: none;
} }
.mdl-switch__trackContainer { .mdl-switch__trackContainer {
position: relative; position: relative;
width: 2.9em width: 2.9em;
} }
.mdl-switch__track { .mdl-switch__track {
background: rgba(0, 0, 0, .2); background: rgba(0,0,0, 0.2);
height: 1em; height: 1em;
-webkit-border-radius: 1em;
border-radius: 1em; border-radius: 1em;
cursor: pointer cursor: pointer;
} }
.mdl-switch__input:checked+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__track { .mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track {
background: rgba(0,164,220, .5) background: rgba(0, 164, 220, 0.5);
} }
.mdl-switch__input[disabled]+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__track { .mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track {
background: rgba(0, 0, 0, .12); background: rgba(0,0,0, 0.12);
cursor: auto cursor: auto;
} }
.mdl-switch__thumb { .mdl-switch__thumb {
@ -74,41 +63,26 @@
top: -.25em; top: -.25em;
height: 1.44em; height: 1.44em;
width: 1.44em; width: 1.44em;
-webkit-border-radius: 50%;
border-radius: 50%; border-radius: 50%;
cursor: pointer; 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, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 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); transition-duration: 0.28s;
-webkit-transition-duration: .28s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
-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;
transition-property: left; transition-property: left;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center; justify-content: center;
-webkit-justify-content: center;
justify-content: center
} }
.mdl-switch__input:checked+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__thumb { .mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb {
background: #00a4dc; background: #00a4dc;
left: 1.466em; 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 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);
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)
} }
.mdl-switch__input[disabled]+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__thumb { .mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb {
background: #bdbdbd; background: rgb(189,189,189);
cursor: auto cursor: auto;
} }
.mdl-switch__focus-helper { .mdl-switch__focus-helper {
@ -118,38 +92,31 @@
-webkit-transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
display: inline-block; display: inline-block;
-webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
width: .6em; width: .6em;
height: .6em; height: .6em;
-webkit-border-radius: 50%;
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 { .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);
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 { .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, 0.26);
box-shadow: 0 0 0 1.39em rgba(0,164,220, .26); background-color: rgba(0, 164, 220, 0.26);
background-color: rgba(0,164,220, .26)
} }
.mdl-switch__label { .mdl-switch__label {
cursor: pointer; cursor: pointer;
margin: 0 0 0 .7em; margin: 0;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
-webkit-box-align: center; align-items: center;
-webkit-align-items: center; margin-left: .7em;
align-items: center
} }
.mdl-switch__input[disabled] .mdl-switch__label { .mdl-switch__input[disabled] .mdl-switch__label {
color: #bdbdbd; color: rgb(189,189,189);
cursor: auto cursor: auto;
} }

View file

@ -1,22 +1,50 @@
define(["css!./emby-toggle", "registerElement"], function() { define(['css!./emby-toggle', 'registerElement'], function () {
"use strict"; 'use strict';
var EmbyTogglePrototype = Object.create(HTMLInputElement.prototype);
function onKeyDown(e) { function onKeyDown(e) {
if (13 === e.keyCode) return e.preventDefault(), this.checked = !this.checked, this.dispatchEvent(new CustomEvent("change", {
bubbles: !0 // Don't submit form on enter
})), !1 if (e.keyCode === 13) {
e.preventDefault();
this.checked = !this.checked;
this.dispatchEvent(new CustomEvent('change', {
bubbles: true
}));
return false;
} }
var EmbyTogglePrototype = Object.create(HTMLInputElement.prototype); }
EmbyTogglePrototype.attachedCallback = function() {
if ("true" !== this.getAttribute("data-embytoggle")) { EmbyTogglePrototype.attachedCallback = function () {
this.setAttribute("data-embytoggle", "true"), this.classList.add("mdl-switch__input");
if (this.getAttribute('data-embytoggle') === 'true') {
return;
}
this.setAttribute('data-embytoggle', 'true');
this.classList.add('mdl-switch__input');
var labelElement = this.parentNode; var labelElement = this.parentNode;
labelElement.classList.add("mdl-switch"), labelElement.classList.add("mdl-js-switch"); labelElement.classList.add('mdl-switch');
var labelTextElement = labelElement.querySelector("span"); labelElement.classList.add('mdl-js-switch');
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)
} var labelTextElement = labelElement.querySelector('span');
}, document.registerElement("emby-toggle", {
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, prototype: EmbyTogglePrototype,
extends: "input" extends: 'input'
}) });
}); });

View file

@ -1,54 +1,132 @@
define([], function() { define([], function () {
"use strict"; 'use strict';
function getFetchPromise(request) { function getFetchPromise(request) {
var headers = request.headers || {}; var headers = request.headers || {};
"json" === request.dataType && (headers.accept = "application/json");
if (request.dataType === 'json') {
headers.accept = 'application/json';
}
var fetchRequest = { var fetchRequest = {
headers: headers, headers: headers,
method: request.type, method: request.type,
credentials: "same-origin" 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); 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; var url = request.url;
if (request.query) { if (request.query) {
var paramString = paramsToString(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) { 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); 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) options = options || {};
}, function(error) { options.credentials = 'same-origin';
clearTimeout(timeout), console.log("fetchWithTimeout: timed out connecting to url: " + url), reject()
}) 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) { function paramsToString(params) {
var values = []; var values = [];
for (var key in params) { for (var key in params) {
var value = params[key]; 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) { 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) { if (!request) {
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) throw new Error("Request cannot be null");
}, function(err) { }
throw console.log("request failed to url: " + request.url), err
}) 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 { return {
getFetchPromise: getFetchPromise, getFetchPromise: getFetchPromise,
ajax: ajax ajax: ajax
} };
}); });

View file

@ -1,10 +1,12 @@
define(["multi-download"], function(multiDownload) { define(['multi-download'], function (multiDownload) {
"use strict"; 'use strict';
return { return {
download: function(items) { download: function (items) {
multiDownload(items.map(function(item) {
return item.url multiDownload(items.map(function (item) {
})) return item.url;
} }));
} }
};
}); });

View file

@ -1,11 +1,12 @@
define([], function() { define([], function () {
"use strict"; 'use strict';
return { return {
fileExists: function(path) { fileExists: function (path) {
return Promise.reject() return Promise.reject();
}, },
directoryExists: function(path) { directoryExists: function (path) {
return Promise.reject() 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) { 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"; 'use strict';
function onSubmit(e) { function onSubmit(e) {
return e.preventDefault(), !1
e.preventDefault();
return false;
} }
function renderOptions(context, selector, cssClass, items, isCheckedFn) { function renderOptions(context, selector, cssClass, items, isCheckedFn) {
var elem = context.querySelector(selector); var elem = context.querySelector(selector);
items.length ? elem.classList.remove("hide") : elem.classList.add("hide");
var html = ""; if (items.length) {
html += items.map(function(filter) {
var itemHtml = "", elem.classList.remove('hide');
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>" } else {
}).join(""), elem.querySelector(".filterOptions").innerHTML = html 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) { function renderDynamicFilters(context, result, options) {
renderOptions(context, ".genreFilters", "chkGenreFilter", result.Genres, function(i) {
var delimeter = -1 === (options.settings.GenreIds || "").indexOf("|") ? "," : "|"; // If there's a huge number of these they will be really show to render
return -1 !== (delimeter + (options.settings.GenreIds || "") + delimeter).indexOf(delimeter + i.Id + delimeter) //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) { function loadDynamicFilters(context, options) {
var apiClient = connectionManager.getApiClient(options.serverId),
filterMenuOptions = Object.assign(options.filterMenuOptions, { var apiClient = connectionManager.getApiClient(options.serverId);
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
UserId: apiClient.getCurrentUserId(), UserId: apiClient.getCurrentUserId(),
ParentId: options.parentId, ParentId: options.parentId,
IncludeItemTypes: options.itemTypes.join(",") IncludeItemTypes: options.itemTypes.join(',')
});
apiClient.getFilters(filterMenuOptions).then(function (result) {
renderDynamicFilters(context, result, options);
}, function () {
// older server
}); });
apiClient.getFilters(filterMenuOptions).then(function(result) {
renderDynamicFilters(context, result, options)
}, function() {})
} }
function initEditor(context, settings) { function initEditor(context, settings) {
context.querySelector("form").addEventListener("submit", onSubmit);
var i, length, elems = context.querySelectorAll(".simpleFilter"); context.querySelector('form').addEventListener('submit', onSubmit);
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(",") : []; var elems = context.querySelectorAll('.simpleFilter');
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 i, length;
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")); for (i = 0, length = elems.length; i < length; i++) {
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")
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) { 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 = []; 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")); elems = context.querySelectorAll('.chkVideoTypeFilter');
userSettings.setFilter(settingsKey + "-filter-VideoTypes", videoTypes.join(","));
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 = []; 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 = []; 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")); elems = context.querySelectorAll('.chkGenreFilter');
userSettings.setFilter(settingsKey + "-filter-GenreIds", genres.join(","))
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) { function setBasicFilter(context, key, elem) {
var value = elem.checked; var value = elem.checked;
value = value || null, userSettings.setFilter(key, value) value = value ? value : null;
userSettings.setFilter(key, value);
} }
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
var fn = on ? "on" : "off"; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz) scrollHelper.centerFocus[fn](elem, horiz);
}) });
} }
function moveCheckboxFocus(elem, offset) { 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) { if (elems[i] === elem) {
index = i; index = i;
break break;
} index += offset, index = Math.min(elems.length - 1, index), index = Math.max(0, index); }
}
index += offset;
index = Math.min(elems.length - 1, index);
index = Math.max(0, index);
var newElem = elems[index]; var newElem = elems[index];
newElem && focusManager.focus(newElem) if (newElem) {
focusManager.focus(newElem);
}
} }
function onInputCommand(e) { function onInputCommand(e) {
switch (e.detail.command) { 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; break;
case "right":
moveCheckboxFocus(e.target, 1), e.preventDefault()
} }
} }
function FilterMenu() {} function FilterMenu() {
}
function bindCheckboxInput(context, on) { 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 = { var dialogOptions = {
removeOnClose: !0, removeOnClose: true,
scrollY: !1 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); var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog");
var html = ""; dlg.classList.add('formDialog');
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"); var html = '';
initEditor(dlg, options.settings), loadDynamicFilters(dlg, options), bindCheckboxInput(dlg, !0), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg) html += '<div class="formDialogHeader">';
}), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0); 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; var submitted;
dlg.querySelector("form").addEventListener("change", function() {
submitted = !0 dlg.querySelector('form').addEventListener('change', function () {
}, !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(); submitted = true;
reject() //if (options.onChange) {
}) // saveValues(dlg, options.settings, options.settingsKey);
}) // options.onChange();
}) //}
}, FilterMenu
}, 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 { .flex {
display: -webkit-box; display: flex;
display: -webkit-flex;
display: flex
} }
.inline-flex { .inline-flex {
display: -webkit-inline-box; display: inline-flex;
display: -webkit-inline-flex;
display: inline-flex
} }
.flex-direction-column { .flex-direction-column {
-webkit-box-orient: vertical; flex-direction: column;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column
} }
.flex-direction-row { .flex-direction-row {
-webkit-box-orient: horizontal; flex-direction: row;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row
} }
.flex-grow { .flex-grow {
-webkit-box-flex: 1; flex-grow: 1;
-webkit-flex-grow: 1;
flex-grow: 1
} }
.flex-shrink-zero { .flex-shrink-zero {
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
.align-items-center { .align-items-center {
-webkit-box-align: center; align-items: center;
-webkit-align-items: center;
align-items: center
} }
.align-items-flex-start { .align-items-flex-start {
-webkit-box-align: start; align-items: flex-start;
-webkit-align-items: flex-start;
align-items: flex-start
} }
.justify-content-center { .justify-content-center {
-webkit-box-pack: center; justify-content: center;
-webkit-justify-content: center;
justify-content: center
} }
.justify-content-flex-end { .justify-content-flex-end {
-webkit-box-pack: end; justify-content: flex-end;
-webkit-justify-content: flex-end;
justify-content: flex-end
} }
.flex-wrap-wrap { .flex-wrap-wrap {
-webkit-flex-wrap: wrap; flex-wrap: wrap;
flex-wrap: wrap
} }
.align-self-flex-end { .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) { define(['dom'], function (dom) {
"use strict"; 'use strict';
var scopes = [];
function pushScope(elem) { function pushScope(elem) {
scopes.push(elem) scopes.push(elem);
} }
function popScope(elem) { function popScope(elem) {
scopes.length && (scopes.length -= 1)
if (scopes.length) {
scopes.length -= 1;
}
} }
function autoFocus(view, defaultToFirst, findAutoFocusElement) { function autoFocus(view, defaultToFirst, findAutoFocusElement) {
var element; var element;
return !1 !== findAutoFocusElement && (element = view.querySelector("*[autofocus]")) ? (focus(element), element) : !1 !== defaultToFirst && (element = getFocusableElements(view, 1, "noautofocus")[0]) ? (focus(element), element) : null 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) { function focus(element) {
try { try {
element.focus({ element.focus({
preventScroll: !0 preventScroll: true
}) });
} catch (err) { } catch (err) {
console.log("Error in focusManager.autoFocus: " + 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) { 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) { function normalizeFocusable(elem, originalElement) {
if (elem) { if (elem) {
var tagName = elem.tagName; 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) { function focusableParent(elem) {
for (var originalElement = elem; !isFocusable(elem);) {
var originalElement = elem;
while (!isFocusable(elem)) {
var parent = elem.parentNode; var parent = elem.parentNode;
if (!parent) return normalizeFocusable(elem, originalElement);
elem = parent if (!parent) {
} return normalizeFocusable(elem, originalElement);
return normalizeFocusable(elem, originalElement)
} }
elem = parent;
}
return normalizeFocusable(elem, originalElement);
}
// Determines if a focusable element can be focused at a given point in time
function isCurrentlyFocusableInternal(elem) { 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;
} }
function isCurrentlyFocusable(elem) { return true;
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
} }
return isCurrentlyFocusableInternal(elem)
// Determines if a focusable element can be focused at a given point in time
function isCurrentlyFocusable(elem) {
if (elem.disabled) {
return false;
}
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() { function getDefaultScope() {
return scopes[0] || document.body return scopes[0] || document.body;
} }
function getFocusableElements(parent, limit, excludeClass) { 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]; 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;
} }
return focusableElements
if (isCurrentlyFocusableInternal(elem)) {
focusableElements.push(elem);
if (limit && focusableElements.length >= limit) {
break;
}
}
}
return focusableElements;
} }
function isFocusContainer(elem, direction) { function isFocusContainer(elem, direction) {
if (-1 !== focusableContainerTagNames.indexOf(elem.tagName)) return !0;
var classList = elem.classList; if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) {
if (classList.contains("focuscontainer")) return !0; return true;
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
} }
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) { function getFocusContainer(elem, direction) {
for (; !isFocusContainer(elem, direction);) while (!isFocusContainer(elem, direction)) {
if (!(elem = elem.parentNode)) return getDefaultScope(); elem = elem.parentNode;
return elem
if (!elem) {
return getDefaultScope();
}
}
return elem;
} }
function getOffset(elem) { function getOffset(elem) {
var box; 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, top: 0,
left: 0, left: 0,
width: 0, width: 0,
height: 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, top: box.top,
left: box.left, left: box.left,
width: box.width, width: box.width,
height: box.height 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) { 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]; var curr = focusable[i];
if (curr !== activeElement && curr !== focusableContainer) {
if (curr === activeElement) {
continue;
}
// Don't refocus into the same container
if (curr === focusableContainer) {
continue;
}
//if (!isCurrentlyFocusableInternal(curr)) {
// continue;
//}
var elementRect = getOffset(curr); var elementRect = getOffset(curr);
if (elementRect.width || elementRect.height) {
// not currently visible
if (!elementRect.width && !elementRect.height) {
continue;
}
switch (direction) { switch (direction) {
case 0: case 0:
if (elementRect.left >= rect.left) continue; // left
if (elementRect.right === rect.right) continue; if (elementRect.left >= rect.left) {
continue;
}
if (elementRect.right === rect.right) {
continue;
}
break; break;
case 1: case 1:
if (elementRect.right <= rect.right) continue; // right
if (elementRect.left === rect.left) continue; if (elementRect.right <= rect.right) {
continue;
}
if (elementRect.left === rect.left) {
continue;
}
break; break;
case 2: case 2:
if (elementRect.top >= rect.top) continue; // up
if (elementRect.bottom >= rect.bottom) continue; if (elementRect.top >= rect.top) {
continue;
}
if (elementRect.bottom >= rect.bottom) {
continue;
}
break; break;
case 3: case 3:
if (elementRect.bottom <= rect.bottom) continue; // down
if (elementRect.top <= rect.top) continue if (elementRect.bottom <= rect.bottom) {
continue;
} }
var distX, distY, x = elementRect.left, if (elementRect.top <= rect.top) {
continue;
}
break;
default:
break;
}
var x = elementRect.left,
y = elementRect.top, y = elementRect.top,
x2 = x + elementRect.width - 1, x2 = x + elementRect.width - 1,
y2 = y + elementRect.height - 1, y2 = y + elementRect.height - 1;
intersectX = intersects(point1x, point2x, x, x2),
intersectY = intersects(point1y, point2y, y, y2), var intersectX = intersects(point1x, point2x, x, x2);
midX = elementRect.left + elementRect.width / 2, var intersectY = intersects(point1y, point2y, y, y2);
midY = elementRect.top + elementRect.height / 2;
var midX = elementRect.left + (elementRect.width / 2);
var midY = elementRect.top + (elementRect.height / 2);
var distX;
var distY;
switch (direction) { switch (direction) {
case 0: case 0:
distX = Math.abs(point1x - Math.min(point1x, x2)), distY = intersectY ? 0 : Math.abs(sourceMidY - midY); // left
distX = Math.abs(point1x - Math.min(point1x, x2));
distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
break; break;
case 1: case 1:
distX = Math.abs(point2x - Math.max(point2x, x)), distY = intersectY ? 0 : Math.abs(sourceMidY - midY); // right
distX = Math.abs(point2x - Math.max(point2x, x));
distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
break; break;
case 2: case 2:
distY = Math.abs(point1y - Math.min(point1y, y2)), distX = intersectX ? 0 : Math.abs(sourceMidX - midX); // up
distY = Math.abs(point1y - Math.min(point1y, y2));
distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
break; break;
case 3: case 3:
distY = Math.abs(point2y - Math.max(point2y, y)), distX = intersectX ? 0 : Math.abs(sourceMidX - midX) // 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); var dist = Math.sqrt(distX * distX + distY * distY);
dist < minDistance && (nearestElement = curr, minDistance = dist)
} if (dist < minDistance) {
nearestElement = curr;
minDistance = dist;
} }
} }
if (nearestElement) { if (nearestElement) {
// See if there's a focusable container, and if so, send the focus command to that
if (activeElement) { if (activeElement) {
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, "focusable"); var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement && focusableContainer !== nearestElementFocusableParent && (nearestElement = nearestElementFocusableParent) if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) {
if (focusableContainer !== nearestElementFocusableParent) {
nearestElement = nearestElementFocusableParent;
} }
focus(nearestElement) }
}
focus(nearestElement);
} }
} }
function intersectsInternal(a1, a2, b1, b2) { 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) { 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) { function sendText(text) {
document.activeElement.value = text var elem = document.activeElement;
elem.value = text;
} }
function focusFirst(container, focusableSelector) { 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]; var elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) { if (isCurrentlyFocusableInternal(elem)) {
focus(elem); focus(elem);
break break;
} }
} }
} }
function focusLast(container, focusableSelector) { 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]; var elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) { if (isCurrentlyFocusableInternal(elem)) {
focus(elem); focus(elem);
break break;
} }
} }
} }
function moveFocus(sourceElement, container, focusableSelector, offset) { function moveFocus(sourceElement, container, focusableSelector, offset) {
var i, length, elem, elems = container.querySelectorAll(focusableSelector),
list = []; var elems = container.querySelectorAll(focusableSelector);
for (i = 0, length = elems.length; i < length; i++) elem = elems[i], isCurrentlyFocusableInternal(elem) && list.push(elem); 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; 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; currentIndex = i;
break break;
} if (-1 !== currentIndex) { }
}
if (currentIndex === -1) {
return;
}
var newIndex = currentIndex + offset; var newIndex = currentIndex + offset;
newIndex = Math.max(0, newIndex), newIndex = Math.min(newIndex, list.length - 1); newIndex = Math.max(0, newIndex);
newIndex = Math.min(newIndex, list.length - 1);
var newElem = list[newIndex]; var newElem = list[newIndex];
newElem && focus(newElem) 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 { return {
autoFocus: autoFocus, autoFocus: autoFocus,
focus: focus, focus: focus,
focusableParent: focusableParent, focusableParent: focusableParent,
getFocusableElements: getFocusableElements, getFocusableElements: getFocusableElements,
moveLeft: function(sourceElement, options) { moveLeft: function (sourceElement, options) {
nav(sourceElement, 0, options ? options.container : null, options ? options.focusableElements : null)
var container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 0, container, focusableElements);
}, },
moveRight: function(sourceElement, options) { moveRight: function (sourceElement, options) {
nav(sourceElement, 1, options ? options.container : null, options ? options.focusableElements : null)
var container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 1, container, focusableElements);
}, },
moveUp: function(sourceElement, options) { moveUp: function (sourceElement, options) {
nav(sourceElement, 2, options ? options.container : null, options ? options.focusableElements : null)
var container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 2, container, focusableElements);
}, },
moveDown: function(sourceElement, options) { moveDown: function (sourceElement, options) {
nav(sourceElement, 3, options ? options.container : null, options ? options.focusableElements : null)
var container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 3, container, focusableElements);
}, },
sendText: sendText, sendText: sendText,
isCurrentlyFocusable: isCurrentlyFocusable, isCurrentlyFocusable: isCurrentlyFocusable,
@ -252,5 +547,5 @@ define(["dom"], function(dom) {
focusFirst: focusFirst, focusFirst: focusFirst,
focusLast: focusLast, focusLast: focusLast,
moveFocus: moveFocus moveFocus: moveFocus
} };
}); });

View file

@ -1,39 +1,37 @@
h1, html {
h2, font-family: -apple-system, "Helvetica", system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", 'Open Sans', sans-serif;
h3 {
font-weight: 500
} }
html { 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%; font-size: 93%;
-webkit-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;
-moz-text-size-adjust: 100%; text-size-adjust: 100%;
text-size-adjust: 100%
} }
h1, h1, h2, h3 {
h2, /* For better bolding, since Helvetica does not support 500 weight, and 600 is too thick */
h3 { font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", 'Open Sans', sans-serif;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", 'Open Sans', sans-serif
} }
h1 { h1 {
font-size: 1.8em font-weight: 500;
font-size: 1.8em;
} }
h2 { h2 {
font-size: 1.5em font-weight: 500;
font-size: 1.5em;
} }
h3 { h3 {
font-size: 1.17em font-weight: 500;
font-size: 1.17em;
} }
.layout-tv { .layout-tv {
font-size: 2.5vh font-size: 2.5vh;
} }
.layout-mobile { .layout-mobile {
font-size: 90% font-size: 90%;
} }

View file

@ -1,33 +1,32 @@
h1,
h2,
h3 {
font-weight: 500
}
h1 { h1 {
font-size: 1.8em font-weight: 500;
font-size: 1.8em;
} }
.layout-desktop h1 { .layout-desktop h1 {
font-size: 2em font-size: 2em;
} }
h2 { h2 {
font-size: 1.5em font-weight: 500;
font-size: 1.5em;
} }
h3 { 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 { 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 { html {
font-size: 27px font-size: 27px;
} }
} }

View file

@ -2,12 +2,12 @@
font-family: 'Material Icons'; font-family: 'Material Icons';
font-style: normal; font-style: normal;
font-weight: 400; 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 { .md-icon {
font-family: 'Material Icons'; font-family: 'Material Icons';
font-weight: 400; font-weight: normal;
font-style: normal; font-style: normal;
letter-spacing: normal; letter-spacing: normal;
text-transform: none; text-transform: none;
@ -15,12 +15,11 @@
white-space: nowrap; white-space: nowrap;
word-wrap: normal; word-wrap: normal;
direction: ltr; direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
-webkit-font-feature-settings: "liga"1; font-feature-settings: "liga" 1;
-moz-font-feature-settings: "liga"1;
font-feature-settings: "liga"1;
line-height: 1; line-height: 1;
overflow: hidden; 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 { .formDialog {
display: flex; display: flex;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
position: relative position: relative;
} }
.formDialogHeader { .formDialogHeader {
padding: 1em .5em; padding: 1em .5em;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
.formDialogHeaderTitle { .formDialogHeaderTitle {
margin-left: .25em; margin-left: .25em;
/* In case of h1, h2, h3 */
margin-top: 0; margin-top: 0;
margin-bottom: 0 margin-bottom: 0;
} }
.formDialogContent:not(.no-grow) { .formDialogContent:not(.no-grow) {
-webkit-box-flex: 1; flex-grow: 1;
-webkit-flex-grow: 1;
flex-grow: 1
} }
.dialogContentInner { .dialogContentInner {
padding: .5em 1em 20em padding: .5em 1em 20em 1em;
} }
.dialogContentInner-mini { .dialogContentInner-mini {
padding-bottom: 10em padding-bottom: 10em;
} }
.dialog-content-centered { .dialog-content-centered {
margin: 0 auto; margin: 0 auto;
max-width: 53em max-width: 53em;
} }
.dialogContentTitle { .dialogContentTitle {
margin-top: 1em margin-top: 1em;
} }
.formDialogFooter { .formDialogFooter {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
position: absolute; position: absolute;
padding: 1.25em 1em; padding: 1.25em 1em;
/* Without this emby-checkbox is able to appear on top */
z-index: 1; z-index: 1;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
-webkit-flex-wrap: wrap; flex-wrap: wrap;
flex-wrap: wrap
} }
.formDialogFooter-flex { .formDialogFooter-flex {
position: static; position: static;
width: 100% width: 100%;
} }
.formDialogFooter-vertical { .formDialogFooter-vertical {
padding-bottom: 1.5em; padding-bottom: 1.5em;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
width: 80% !important; width: 80% !important;
padding-top: .5em padding-top: .5em;
} }
.formDialogFooterItem { .formDialogFooterItem {
margin: .5em !important; margin: .5em !important;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1; flex-grow: 1;
text-align: center; text-align: center;
-webkit-flex-basis: 0; flex-basis: 0;
flex-basis: 0
} }
.formDialogFooterItem-vertical { .formDialogFooterItem-vertical {
max-width: none !important; max-width: none !important;
width: 100%; width: 100%;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
margin: 1em !important margin: 1em !important;
} }
.formDialogFooterItem-nomarginbottom { .formDialogFooterItem-nomarginbottom {
margin-bottom: 0 !important margin-bottom: 0 !important;
} }
.formDialogFooterItem-autosize { .formDialogFooterItem-autosize {
-webkit-flex-basis: initial;
flex-basis: initial; flex-basis: initial;
-webkit-box-flex: initial;
-webkit-flex-grow: initial;
flex-grow: initial; flex-grow: initial;
padding-left: 2em; padding-left: 2em;
padding-right: 2em padding-right: 2em;
} }
@media all and (min-width:50em) { @media all and (min-width: 50em) {
.formDialogFooterItem { .formDialogFooterItem {
max-width: 80% max-width: 80%;
} }
.dialogContentInner { .dialogContentInner {
padding-left: 1.5em; 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 { .formDialogFooterItem {
max-width: 70% max-width: 70%;
} }
.dialogContentInner { .dialogContentInner {
padding-left: 2em; padding-left: 2em;
padding-right: 2em padding-right: 2em;
} }
} }

View file

@ -1,12 +1,26 @@
define(["dom", "fullscreenManager"], function(dom, fullscreenManager) { define(['dom', 'fullscreenManager'], function (dom, fullscreenManager) {
"use strict"; 'use strict';
function isTargetValid(target) { function isTargetValid(target) {
return !dom.parentWithTag(target, ["BUTTON", "INPUT", "TEXTAREA"])
if (dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA'])) {
return false;
} }
dom.addEventListener(window, "dblclick", function(e) {
isTargetValid(e.target) && (fullscreenManager.isFullScreen() ? fullscreenManager.exitFullscreen() : fullscreenManager.requestFullscreen()) return true;
}
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) { define(['events', 'dom'], function (events, dom) {
"use strict"; '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() { 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())) dom.addEventListener(document, 'fullscreenchange', onFullScreenChange, {
}, fullscreenManager.prototype.exitFullscreen = function() { passive: true
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) dom.addEventListener(document, 'webkitfullscreenchange', onFullScreenChange, {
}; passive: true
var manager = new fullscreenManager; });
return dom.addEventListener(document, "fullscreenchange", onFullScreenChange, {
passive: !0 dom.addEventListener(document, 'mozfullscreenchange', onFullScreenChange, {
}), dom.addEventListener(document, "webkitfullscreenchange", onFullScreenChange, { passive: true
passive: !0 });
}), dom.addEventListener(document, "mozfullscreenchange", onFullScreenChange, {
passive: !0 return manager;
}), manager
}); });

View file

@ -1,127 +1,287 @@
define(["connectionManager", "userSettings", "events"], function(connectionManager, userSettings, events) { define(['connectionManager', 'userSettings', 'events'], function (connectionManager, userSettings, events) {
"use strict"; 'use strict';
var allTranslations = {};
var currentCulture;
var currentDateTimeCulture;
function getCurrentLocale() { function getCurrentLocale() {
return currentCulture
return currentCulture;
} }
function getCurrentDateTimeLocale() { function getCurrentDateTimeLocale() {
return currentDateTimeCulture return currentDateTimeCulture;
} }
function getDefaultLanguage() { 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() { function updateCurrentCulture() {
var culture; var culture;
try { try {
culture = userSettings.language() culture = userSettings.language();
} catch (err) {} } catch (err) {
culture = culture || getDefaultLanguage(), currentCulture = normalizeLocaleName(culture);
}
culture = culture || getDefaultLanguage();
currentCulture = normalizeLocaleName(culture);
var dateTimeCulture; var dateTimeCulture;
try { try {
dateTimeCulture = userSettings.dateTimeLocale() dateTimeCulture = userSettings.dateTimeLocale();
} catch (err) {} } catch (err) {
currentDateTimeCulture = dateTimeCulture ? normalizeLocaleName(dateTimeCulture) : currentCulture, ensureTranslations(currentCulture)
}
if (dateTimeCulture) {
currentDateTimeCulture = normalizeLocaleName(dateTimeCulture);
}
else {
currentDateTimeCulture = currentCulture;
}
ensureTranslations(currentCulture);
} }
function ensureTranslations(culture) { function ensureTranslations(culture) {
for (var i in allTranslations) ensureTranslation(allTranslations[i], culture)
for (var i in allTranslations) {
ensureTranslation(allTranslations[i], culture);
}
} }
function ensureTranslation(translationInfo, culture) { function ensureTranslation(translationInfo, culture) {
return translationInfo.dictionaries[culture] ? Promise.resolve() : loadTranslation(translationInfo.translations, culture).then(function(dictionary) {
translationInfo.dictionaries[culture] = dictionary if (translationInfo.dictionaries[culture]) {
}) return Promise.resolve();
}
return loadTranslation(translationInfo.translations, culture).then(function (dictionary) {
translationInfo.dictionaries[culture] = dictionary;
});
} }
function normalizeLocaleName(culture) { function normalizeLocaleName(culture) {
culture = culture.replace("_", "-");
var parts = culture.split("-"); culture = culture.replace('_', '-');
2 === parts.length && parts[0].toLowerCase() === parts[1].toLowerCase() && (culture = parts[0].toLowerCase());
// 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(); var lower = culture.toLowerCase();
return "ca-es" === lower ? "ca" : "sv-se" === lower ? "sv" : lower
if (lower === 'ca-es') {
return 'ca';
}
// normalize Swedish
if (lower === 'sv-se') {
return 'sv';
}
return lower;
} }
function getDictionary(module) { function getDictionary(module) {
module || (module = defaultModule());
if (!module) {
module = defaultModule();
}
var translations = allTranslations[module]; var translations = allTranslations[module];
return translations ? translations.dictionaries[getCurrentLocale()] : {}
if (!translations) {
return {};
}
return translations.dictionaries[getCurrentLocale()];
} }
function register(options) { function register(options) {
allTranslations[options.name] = { allTranslations[options.name] = {
translations: options.strings || options.translations, translations: options.strings || options.translations,
dictionaries: {} dictionaries: {}
} };
} }
function loadStrings(options) { function loadStrings(options) {
var locale = getCurrentLocale(); var locale = getCurrentLocale();
return "string" == typeof options ? ensureTranslation(allTranslations[options], locale) : (register(options), ensureTranslation(allTranslations[options.name], locale))
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) { function loadTranslation(translations, lang) {
lang = normalizeLocaleName(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) if (!filtered.length) {
})), new Promise(function(resolve, reject) { filtered = translations.filter(function (t) {
if (!filtered.length) return void resolve(); return normalizeLocaleName(t.lang) === 'en-us';
});
}
return new Promise(function (resolve, reject) {
if (!filtered.length) {
resolve();
return;
}
var url = filtered[0].path; var url = filtered[0].path;
url += -1 === url.indexOf("?") ? "?" : "&", url += "v=" + cacheParam;
var xhr = new XMLHttpRequest; url += url.indexOf('?') === -1 ? '?' : '&';
xhr.open("GET", url, !0), xhr.onload = function(e) { url += 'v=' + cacheParam;
resolve(this.status < 400 ? JSON.parse(this.response) : {})
}, xhr.onerror = function() { var xhr = new XMLHttpRequest();
resolve({}) xhr.open('GET', url, true);
}, xhr.send()
}) xhr.onload = function (e) {
if (this.status < 400) {
resolve(JSON.parse(this.response));
} else {
resolve({});
}
};
xhr.onerror = function () {
resolve({});
};
xhr.send();
});
} }
function translateKey(key) { 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) { function translateKeyFromModule(key, module) {
var dictionary = getDictionary(module); var dictionary = getDictionary(module);
return dictionary ? dictionary[key] || key : key
if (!dictionary) {
return key;
}
return dictionary[key] || key;
} }
function replaceAll(str, find, replace) { function replaceAll(str, find, replace) {
return str.split(find).join(replace)
return str.split(find).join(replace);
} }
function translate(key) { 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) { function translateHtml(html, module) {
if (module || (module = defaultModule()), !module) throw new Error("module cannot be null or empty");
var startIndex = html.indexOf("${"); if (!module) {
if (-1 === startIndex) return html; module = defaultModule();
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)
} }
function defaultModule(val) { if (!module) {
return val && (_defaultModule = val), _defaultModule throw new Error('module cannot be null or empty');
} }
var currentCulture, currentDateTimeCulture, _defaultModule, allTranslations = {},
cacheParam = (new Date).getTime(); var startIndex = html.indexOf('${');
return updateCurrentCulture(), events.on(connectionManager, "localusersignedin", updateCurrentCulture), events.on(userSettings, "change", function(e, name) {
"language" !== name && "datetimelocale" !== name || updateCurrentCulture() if (startIndex === -1) {
}), { return html;
}
startIndex += 2;
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) {
if (val) {
_defaultModule = val;
}
return _defaultModule;
}
updateCurrentCulture();
events.on(connectionManager, 'localusersignedin', updateCurrentCulture);
events.on(userSettings, 'change', function (e, name) {
if (name === 'language' || name === 'datetimelocale') {
updateCurrentCulture();
}
});
return {
getString: translate, getString: translate,
translate: translate, translate: translate,
translateDocument: translateHtml, translateDocument: translateHtml,
@ -131,5 +291,5 @@ define(["connectionManager", "userSettings", "events"], function(connectionManag
getCurrentLocale: getCurrentLocale, getCurrentLocale: getCurrentLocale,
getCurrentDateTimeLocale: getCurrentDateTimeLocale, getCurrentDateTimeLocale: getCurrentDateTimeLocale,
register: register 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) { 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"; 'use strict';
function saveCategories(context, options) { 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"); var categories = [];
chkCategorys[i].checked && categories.push(type)
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) { 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"); var selectedCategories = options.categories || [];
chkCategorys[i].checked = !selectedCategories.length || -1 !== selectedCategories.indexOf(type)
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) { 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++) { 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"); userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked);
for (i = 0, length = sortBys.length; i < length; i++) 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) { if (sortBys[i].checked) {
userSettings.set("livetv-channelorder", sortBys[i].value); userSettings.set('livetv-channelorder', sortBys[i].value);
break break;
}
} }
} }
function load(context) { 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++) { 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) { function showEditor(options) {
return new Promise(function(resolve, reject) {
var settingsChanged = !1; return new Promise(function (resolve, reject) {
require(["text!./guide-settings.template.html"], function(template) {
var settingsChanged = false;
require(['text!./guide-settings.template.html'], function (template) {
var dialogOptions = { var dialogOptions = {
removeOnClose: !0, removeOnClose: true,
scrollY: !1 scrollY: false
}; };
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small";
var dlg = dialogHelper.createDialog(dialogOptions); if (layoutManager.tv) {
dlg.classList.add("formDialog"); dialogOptions.size = 'fullscreen';
var html = ""; } else {
html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, dlg.addEventListener("change", function() { dialogOptions.size = 'small';
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)
})
})
} }
var dlg = dialogHelper.createDialog(dialogOptions);
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 { return {
show: showEditor 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 { .tvguide {
display: flex; display: flex;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
-webkit-box-align: initial; align-items: initial;
-webkit-align-items: initial;
align-items: initial
} }
.tvGuideHeader { .tvGuideHeader {
white-space: nowrap; white-space: nowrap;
width: 100%; width: 100%;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
-webkit-flex-shrink: 0;
flex-shrink: 0; flex-shrink: 0;
display: flex; display: flex;
contain: layout style paint contain: layout style paint;
} }
.layout-desktop .tvGuideHeader { .layout-desktop .tvGuideHeader {
margin-bottom: .5em margin-bottom: .5em;
} }
.guideHeaderDateSelection { .guideHeaderDateSelection {
font-size: 86%; font-size: 86%;
padding: .4em 0 padding: .4em 0;
} }
.guide-headerTimeslots { .guide-headerTimeslots {
display: -webkit-box; display: flex;
display: -webkit-flex;
display: flex
} }
.tvProgramSectionHeader { .tvProgramSectionHeader {
margin: 0 margin: 0;
} }
.tvProgram { .tvProgram {
display: block; display: block;
text-decoration: none; text-decoration: none;
white-space: nowrap white-space: nowrap;
position: relative;
} }
.guideProgramIndicator { .guideProgramIndicator {
text-transform: uppercase; text-transform: uppercase;
-webkit-border-radius: .25em;
border-radius: .25em; border-radius: .25em;
margin-right: .5em; margin-right: .5em;
font-size: 82%; font-size: 82%;
padding: .2em .25em; padding: .2em .25em;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
text-align: center; text-align: center;
margin-left: 1em margin-left: 1em;
} }
.guide-channelTimeslotHeader { .guide-channelTimeslotHeader {
-webkit-box-pack: center; flex-shrink: 0;
-webkit-justify-content: center; justify-content: center;
justify-content: center
} }
.timeslotHeaders { .timeslotHeaders {
white-space: nowrap; white-space: nowrap;
font-weight: 500; font-weight: 500;
font-size: 120% font-size: 120%;
} }
.programContainer { .programContainer {
white-space: nowrap; white-space: nowrap;
-webkit-box-align: start; position: relative;
-webkit-align-items: flex-start;
align-items: flex-start; align-items: flex-start;
contain: strict contain: strict;
}
.channelPrograms {
white-space: nowrap;
position: relative;
contain: strict;
box-sizing: border-box;
}
.timeslotHeadersInner {
position: relative;
} }
.guideSpacer { .guideSpacer {
width: .3em; width: .3em;
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
.channelPrograms, .channelPrograms, .timeslotHeadersInner {
.timeslotHeadersInner { width: 1800vw;
width: 1800vw
} }
@media all and (min-width:37.5em) { @media all and (min-width: 37.5em) {
.channelPrograms, .channelPrograms, .timeslotHeadersInner {
.timeslotHeadersInner { width: 1400vw;
width: 1400vw
} }
} }
@media all and (min-width:50em) { @media all and (min-width: 50em) {
.channelPrograms, .channelPrograms, .timeslotHeadersInner {
.timeslotHeadersInner { width: 1200vw;
width: 1200vw
} }
} }
@media all and (min-width:80em) { @media all and (min-width: 80em) {
.channelPrograms, .channelPrograms, .timeslotHeadersInner {
.timeslotHeadersInner { width: 810vw;
width: 810vw
} }
} }
.timeslotHeader { .timeslotHeader {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex; display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
text-indent: .25em; text-indent: .25em;
width: 2.0833333333333333333333333333333% width: 2.0833333333333333333333333333333%;
} }
.guide-channelHeaderCell, .guide-channelHeaderCell, .guide-channelTimeslotHeader {
.guide-channelTimeslotHeader, padding: 0 !important;
.programCell {
color: inherit;
cursor: pointer; cursor: pointer;
outline: none !important;
width: 100%;
vertical-align: middle; vertical-align: middle;
font-family: inherit; 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; font-size: inherit;
-o-text-overflow: ellipsis; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
margin: 0 1px 0 0; margin: 0 1px 0 0;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-align-items: center;
align-items: center; align-items: center;
text-decoration: none;
/* Needed in firefox */
text-align: left;
contain: strict; contain: strict;
-webkit-flex-shrink: 0;
flex-shrink: 0; flex-shrink: 0;
-webkit-border-radius: .12em; border-radius: .12em;
border-radius: .12em color: inherit;
} }
.guide-channelHeaderCell { .guide-channelHeaderCell {
@ -198,187 +145,151 @@
height: 4.42em; height: 4.42em;
contain: strict; contain: strict;
position: relative; position: relative;
background: 0 0 background: transparent;
} }
.guide-channelTimeslotHeader { .guide-channelTimeslotHeader {
border: 0 !important; border: 0 !important;
border-right-color: transparent
} }
.channelsContainer, /* Important - have to put the fixed width on channelsContainer, not the individual channelHeaderCell
.guide-channelTimeslotHeader { This was causing channelsContainer to extend beyond the fixed width on ps4, tizen, lg and opera tv.
width: 24vw */
.channelsContainer, .guide-channelTimeslotHeader {
width: 24vw;
} }
@media all and (min-width:31.25em) { @media all and (min-width:31.25em) {
.channelsContainer, .guide-channelTimeslotHeader {
.channelsContainer, width: 16vw;
.guide-channelTimeslotHeader {
width: 16vw
} }
} }
@media all and (min-width:37.5em) { @media all and (min-width:37.5em) {
.channelsContainer, .guide-channelTimeslotHeader {
.channelsContainer, width: 16vw;
.guide-channelTimeslotHeader {
width: 16vw
} }
} }
@media all and (min-width:50em) { @media all and (min-width:50em) {
.channelsContainer, .guide-channelTimeslotHeader {
.channelsContainer, width: 14vw;
.guide-channelTimeslotHeader {
width: 14vw
} }
} }
@media all and (min-width:80em) { @media all and (min-width:80em) {
.channelsContainer, .guide-channelTimeslotHeader {
.channelsContainer, width: 12vw;
.guide-channelTimeslotHeader {
width: 12vw
} }
} }
.btnGuideViewSettings { .btnGuideViewSettings {
margin: 0; margin: 0;
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
.btnGuideViewSettingsIcon { .btnGuideViewSettingsIcon {
font-size: 1.5em !important font-size: 1.5em !important;
} }
.selectDateIcon { .selectDateIcon {
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
@media all and (max-width:50em) { @media all and (max-width: 50em) {
.guideHdIcon, .newTvProgram, .liveTvProgram, .premiereTvProgram, .guideHdIcon {
.liveTvProgram, display: none;
.newTvProgram,
.premiereTvProgram {
display: none
} }
} }
.channelPrograms,
.programCell {
border-style: solid;
display: -webkit-box;
display: -webkit-flex;
contain: strict
}
.channelPrograms { .channelPrograms {
white-space: nowrap;
-webkit-box-sizing: border-box;
box-sizing: border-box;
height: 4.42em; height: 4.42em;
contain: strict;
display: flex; display: flex;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
border-width: 1px 0 border-style: solid;
border-width: 1px 0 1px 0;
} }
.channelPrograms+.channelPrograms, .channelPrograms + .channelPrograms, .guide-channelHeaderCell + .guide-channelHeaderCell {
.guide-channelHeaderCell+.guide-channelHeaderCell { margin-top: -1px;
margin-top: -1px }
.channelPrograms-tv, .guide-channelHeaderCell-tv {
height: 3em;
} }
.channelPrograms-tv, .guide-channelTimeslotHeader {
.guide-channelHeaderCell-tv { border-right-color: transparent;
height: 3em
} }
.guide-channelTimeslotHeader, .guide-channelTimeslotHeader, .timeslotHeader {
.timeslotHeader { background: transparent !important;
background: 0 0 !important; height: 2.8em;
height: 2.8em
} }
.programGrid { .programGrid {
padding-bottom: 4px; padding-bottom: 4px;
-webkit-box-flex: 1; flex-grow: 1;
-webkit-flex-grow: 1;
flex-grow: 1
} }
.programCell { .programCell {
background: 0 0; color: inherit;
background: transparent;
border-style: solid;
border-width: 0 0 0 1px; border-width: 0 0 0 1px;
padding: 0 !important; padding: 0 !important;
cursor: pointer;
outline: none !important;
width: 100%; width: 100%;
vertical-align: middle;
font-family: inherit;
font-size: inherit; font-size: inherit;
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
display: flex; display: flex;
-webkit-align-items: center; text-decoration: none;
overflow: hidden;
align-items: center; align-items: center;
-webkit-box-flex: 1; /* Needed for Firefox */
-webkit-flex-grow: 1; text-align: left;
contain: strict;
flex-grow: 1; flex-grow: 1;
margin: 0 !important margin: 0 !important;
}
.channelsContainer,
.guideProgramName,
.programGrid {
contain: layout style paint
}
.guide-programNameCaret,
.guideProgramName {
display: -webkit-box;
display: -webkit-flex;
-webkit-box-align: center
} }
.guideProgramName { .guideProgramName {
padding: 0 .7em; padding: 0 .7em 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
-webkit-align-items: center;
align-items: center; align-items: center;
display: flex; display: flex;
position: relative; position: relative;
-webkit-box-flex: 1; flex-grow: 1;
-webkit-flex-grow: 1; contain: layout style paint;
flex-grow: 1 /*transition: transform 60ms ease-out;*/
} }
.guide-programNameCaret { .guide-programNameCaret {
display: flex; display: flex;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
font-size: 200% font-size: 200%;
} }
.guideProgramNameText { .guideProgramNameText {
margin: 0; margin: 0;
font-weight: 400; font-weight: normal;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis text-overflow: ellipsis;
} }
.guideProgramSecondaryInfo { .guideProgramSecondaryInfo {
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
margin-top: .1em margin-top: .1em;
} }
.programIcon { .programIcon {
@ -387,26 +298,22 @@
width: 1em; width: 1em;
font-size: 1.6em; font-size: 1.6em;
color: #ddd; color: #ddd;
-webkit-flex-shrink: 0;
flex-shrink: 0; flex-shrink: 0;
-webkit-box-flex: 0; flex-grow: 0;
-webkit-flex-grow: 0;
flex-grow: 0
} }
.guide-programTextIcon { .guide-programTextIcon {
font-weight: 700; font-weight: bold;
font-size: .9em; font-size: .9em;
padding: .16em .3em; padding: .16em .3em;
-webkit-border-radius: .25em;
border-radius: .25em; border-radius: .25em;
margin-right: .35em; margin-right: .35em;
width: auto; width: auto;
height: auto height: auto;
} }
.guide-programTextIcon-tv { .guide-programTextIcon-tv {
font-size: .74em font-size: .74em;
} }
.guideChannelNumber { .guideChannelNumber {
@ -414,8 +321,8 @@
max-width: 30%; max-width: 30%;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
font-weight: 400; font-weight: normal;
margin: 0 margin: 0;
} }
.guideChannelName { .guideChannelName {
@ -423,7 +330,7 @@
margin-right: 1em; margin-right: 1em;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
max-width: 70% max-width: 70%;
} }
.guideChannelImage { .guideChannelImage {
@ -432,68 +339,62 @@
top: 15%; top: 15%;
bottom: 15%; bottom: 15%;
width: 40%; width: 40%;
-webkit-background-size: contain;
background-size: contain; background-size: contain;
background-repeat: no-repeat; 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 { .guideChannelName {
max-width: 40% max-width: 40%;
} }
} }
@media all and (max-width:62.5em) { @media all and (max-width: 62.5em) {
.guideChannelNumber { .guideChannelNumber {
display: none display: none;
} }
.guideChannelImage { .guideChannelImage {
width: 70% width: 70%;
} }
} }
.channelsContainer { .channelsContainer {
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-flex-shrink: 0;
flex-shrink: 0; flex-shrink: 0;
-webkit-flex-direction: column; flex-direction: column;
flex-direction: column
} }
.guide-channelHeaderCell, .channelsContainer, .programGrid {
.programCell { contain: layout style paint;
outline: 0 !important
} }
.seriesTimerIcon, .programCell, .guide-channelHeaderCell {
.timerIcon { outline: none !important;
color: #c33 !important }
.timerIcon, .seriesTimerIcon {
color: #cc3333 !important;
} }
.seriesTimerIcon-inactive { .seriesTimerIcon-inactive {
color: inherit !important; color: inherit !important;
opacity: .7 opacity: .7;
} }
.guideOptions { .guideOptions {
-webkit-flex-shrink: 0;
flex-shrink: 0; flex-shrink: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center; align-items: center;
-webkit-align-items: center;
align-items: center
} }
@media all and (max-width:50em), @media all and (max-width: 50em), all and (max-height: 37.5em) {
all and (max-height:37.5em) {
.tvGuideHeader { .tvGuideHeader {
padding-left: 0 padding-left: 0;
} }
} }
@ -501,31 +402,29 @@ all and (max-height:37.5em) {
margin: 1em auto; margin: 1em auto;
text-align: center; text-align: center;
padding: 1em; padding: 1em;
-webkit-flex-shrink: 0; flex-shrink: 0;
flex-shrink: 0
} }
.noRubberBanding { .noRubberBanding {
padding-bottom: 7em /* This is needed to combat the rubber banding in iOS */
padding-bottom: 7em;
} }
.guideDateTabsSlider { .guideDateTabsSlider {
text-align: center text-align: center;
} }
.guide-date-tab-button { .guide-date-tab-button {
padding: .3em .7em !important; padding: .3em .7em !important;
margin: 0 .3em !important; margin: 0 .3em !important;
font-weight: 400 font-weight: normal;
} }
.guide-date-tab-button.emby-tab-button-active { .guide-date-tab-button.emby-tab-button-active {
border-color: transparent !important border-color: transparent !important;
} }
.guide-date-tab-button.emby-button-tv:focus { .guide-date-tab-button.emby-button-tv:focus {
-webkit-border-radius: .15em !important;
border-radius: .15em !important; border-radius: .15em !important;
-webkit-transform: none !important; transform: none !important;
transform: none !important }
}

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,19 @@
.newTvProgram { .newTvProgram {
background: #38c; background: #3388cc;
color: #fff color: #fff;
} }
.liveTvProgram { .liveTvProgram {
background: #c33; background: #cc3333;
color: #fff color: #fff;
} }
.premiereTvProgram { .premiereTvProgram {
background: #EF6C00; background: #EF6C00;
color: #fff color: #fff;
} }
.repeatTvProgram { .repeatTvProgram {
background: #009688; background: #009688;
color: #fff color: #fff;
} }

View file

@ -1,15 +1,11 @@
.headroom { .headroom {
-webkit-transition: -webkit-transform 140ms linear; transition: transform 140ms linear;
-o-transition: transform 140ms linear;
transition: transform 140ms linear
} }
.headroom--pinned { .headroom--pinned {
-webkit-transform: none; transform: none;
transform: none
} }
.headroom--unpinned:not(.headroomDisabled) { .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) { 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() { 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) { 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() { function onScroll() {
this.paused || requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)))
if (this.paused) {
return;
} }
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
return Debouncer.prototype = { requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
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)
} }
}, Headroom.prototype = {
Headroom.prototype = {
constructor: Headroom, constructor: Headroom,
init: function() {
/**
* Initialises the widget
*/
init: function () {
if (browser.supportsCssAnimation()) { 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)); for (var i = 0, length = this.elems.length; i < length; i++) {
this.attachEvent() this.elems[i].classList.add(this.initialClass);
this.elems[i].addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this));
} }
return this
this.attachEvent();
}
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); remove: function (elem) {
var i = this.elems.indexOf(elem); - 1 !== i && this.elems.splice(i, 1)
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++) { for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList; var classList = this.elems[i].classList;
classList.remove(this.unPinnedClass), classList.remove(this.initialClass), classList.remove(this.pinnedClass)
} classList.remove(unpinnedClass);
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : "scroll"; //classList.remove(pinnedClass);
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()
} }
}, },
clear: function() {
if ("clear" !== this.state) { /**
this.state = "clear"; * Unpins the header if it's currently pinned
for (var unpinnedClass = this.unPinnedClass, i = (this.pinnedClass, 0), length = this.elems.length; i < length; i++) { */
this.elems[i].classList.remove(unpinnedClass) pin: function () {
if (this.state === 'pin') {
return;
} }
}
}, this.state = 'pin';
pin: function() {
if ("pin" !== this.state) { var unpinnedClass = this.unPinnedClass;
this.state = "pin"; var pinnedClass = this.pinnedClass;
for (var unpinnedClass = this.unPinnedClass, pinnedClass = this.pinnedClass, i = 0, length = this.elems.length; i < length; i++) {
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList; var classList = this.elems[i].classList;
classList.remove(unpinnedClass), classList.add(pinnedClass)
} classList.remove(unpinnedClass);
classList.add(pinnedClass);
} }
}, },
unpin: function() {
if ("unpin" !== this.state) { /**
this.state = "unpin"; * Unpins the header if it's currently pinned
for (var unpinnedClass = this.unPinnedClass, i = (this.pinnedClass, 0), length = this.elems.length; i < length; i++) { */
this.elems[i].classList.add(unpinnedClass) 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);
} }
}, },
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; var scroller = this.scroller;
if (scroller.getScrollPosition) return scroller.getScrollPosition();
if (scroller.getScrollPosition) {
return scroller.getScrollPosition();
}
var pageYOffset = scroller.pageYOffset; var pageYOffset = scroller.pageYOffset;
if (void 0 !== pageYOffset) return pageYOffset; if (pageYOffset !== undefined) {
return pageYOffset;
}
var scrollTop = scroller.scrollTop; 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, var scrollingDown = currentScrollY > this.lastKnownScrollY,
pastOffset = currentScrollY >= this.offset; 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, var scrollingUp = currentScrollY < this.lastKnownScrollY,
pastOffset = currentScrollY <= this.offset; pastOffset = currentScrollY <= this.offset;
return scrollingUp || pastOffset
return scrollingUp || pastOffset;
}, },
update: function() {
if (!this.paused) { /**
var currentScrollY = this.getScrollY(), * Handles updating the state of the widget
lastKnownScrollY = this.lastKnownScrollY, */
isTv = layoutManager.tv; update: function () {
if (currentScrollY <= (isTv ? 120 : 10)) this.clear();
else if (this.shouldUnpin(currentScrollY)) this.unpin(); 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)) { else if (this.shouldPin(currentScrollY)) {
var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14; var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14;
currentScrollY && isTv ? this.unpin() : toleranceExceeded && this.clear()
if (currentScrollY && isTv) {
this.unpin();
} else if (toleranceExceeded) {
this.clear();
} }
this.lastKnownScrollY = currentScrollY } else if (isTv) {
//this.clear();
} }
this.lastKnownScrollY = currentScrollY;
} }
}, Headroom.options = { };
/**
* Default options
* @type {Object}
*/
Headroom.options = {
offset: 0, offset: 0,
scroller: window, scroller: window,
initialClass: "headroom", initialClass: 'headroom',
unPinnedClass: "headroom--unpinned", unPinnedClass: 'headroom--unpinned',
pinnedClass: "headroom--pinned" pinnedClass: 'headroom--pinned'
}, Headroom };
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"; "use strict";
var numConfigurableSections = 7;
function renderViews(page, user, result) { function renderViews(page, user, result) {
var folderHtml = "";
folderHtml += '<div class="checkboxList">', folderHtml += result.map(function(i) { var folderHtml = '';
var currentHtml = "",
id = "chkGroupFolder" + i.Id, folderHtml += '<div class="checkboxList">';
isChecked = -1 !== user.Configuration.GroupedFolders.indexOf(i.Id), folderHtml += result.map(function (i) {
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>" var currentHtml = '';
}).join(""), folderHtml += "</div>", page.querySelector(".folderGroupList").innerHTML = folderHtml
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) { function getLandingScreenOptions(type) {
var list = []; var list = [];
return "movies" === type ? (list.push({
name: globalize.translate("sharedcomponents#Movies"), if (type === 'movies') {
value: "movies",
isDefault: !0 list.push({
}), list.push({ name: globalize.translate('sharedcomponents#Movies'),
name: globalize.translate("sharedcomponents#Suggestions"), value: 'movies',
value: "suggestions" isDefault: true
}), list.push({ });
name: globalize.translate("sharedcomponents#Favorites"),
value: "favorites" list.push({
}), list.push({ name: globalize.translate('sharedcomponents#Suggestions'),
name: globalize.translate("sharedcomponents#Collections"), value: 'suggestions'
value: "collections" });
})) : "tvshows" === type ? (list.push({
name: globalize.translate("sharedcomponents#Shows"), list.push({
value: "shows", name: globalize.translate('sharedcomponents#Favorites'),
isDefault: !0 value: 'favorites'
}), list.push({ });
name: globalize.translate("sharedcomponents#Suggestions"), list.push({
value: "suggestions" name: globalize.translate('sharedcomponents#Collections'),
}), list.push({ value: 'collections'
name: globalize.translate("sharedcomponents#Latest"), });
value: "latest" }
}), list.push({ else if (type === 'tvshows') {
name: globalize.translate("sharedcomponents#Favorites"),
value: "favorites" list.push({
})) : "music" === type ? (list.push({ name: globalize.translate('sharedcomponents#Shows'),
name: globalize.translate("sharedcomponents#Suggestions"), value: 'shows',
value: "suggestions", isDefault: true
isDefault: !0 });
}), list.push({ list.push({
name: globalize.translate("sharedcomponents#Albums"), name: globalize.translate('sharedcomponents#Suggestions'),
value: "albums" value: 'suggestions'
}), list.push({ });
name: globalize.translate("sharedcomponents#HeaderAlbumArtists"),
value: "albumartists" list.push({
}), list.push({ name: globalize.translate('sharedcomponents#Latest'),
name: globalize.translate("sharedcomponents#Artists"), value: 'latest'
value: "artists" });
}), list.push({ list.push({
name: globalize.translate("sharedcomponents#Playlists"), name: globalize.translate('sharedcomponents#Favorites'),
value: "playlists" value: 'favorites'
}), list.push({ });
name: globalize.translate("sharedcomponents#Genres"), }
value: "genres" else if (type === 'music') {
})) : "livetv" === type && (list.push({
name: globalize.translate("sharedcomponents#Suggestions"), list.push({
value: "suggestions", name: globalize.translate('sharedcomponents#Suggestions'),
isDefault: !0 value: 'suggestions',
}), list.push({ isDefault: true
name: globalize.translate("sharedcomponents#Guide"), });
value: "guide"
})), list 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) { function getLandingScreenOptionsHtml(type, userValue) {
return getLandingScreenOptions(type).map(function(o) {
var selected = userValue === o.value || o.isDefault && !userValue, return getLandingScreenOptions(type).map(function (o) {
selectedHtml = selected ? " selected" : "";
return '<option value="' + (o.isDefault ? "" : o.value) + '"' + selectedHtml + ">" + o.name + "</option>" var selected = userValue === o.value || (o.isDefault && !userValue);
}).join("") var selectedHtml = selected ? ' selected' : '';
var optionValue = o.isDefault ? '' : o.value;
return '<option value="' + optionValue + '"' + selectedHtml + '>' + o.name + '</option>';
}).join('');
} }
function renderViewOrder(context, user, result) { function renderViewOrder(context, user, result) {
var html = "",
index = 0; var html = '';
html += result.Items.map(function(view) {
var currentHtml = ""; var index = 0;
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 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) { function updateHomeSectionValues(context, userSettings) {
for (var i = 1; i <= 7; i++) { for (var i = 1; i <= 7; i++) {
var select = context.querySelector("#selectHomeSection" + i),
defaultValue = homeSections.getDefaultSection(i - 1), var select = context.querySelector('#selectHomeSection' + i);
option = select.querySelector("option[value=" + defaultValue + "]") || select.querySelector('option[value=""]'), var defaultValue = homeSections.getDefaultSection(i - 1);
userValue = userSettings.get("homesection" + (i - 1));
option.value = "", select.value = userValue !== defaultValue && userValue ? userValue : "" 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) { 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 html = '';
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 isChecked;
var userValue = userSettings.get("landing-" + idForLanding);
html += getLandingScreenOptionsHtml(item.CollectionType, userValue), html += "</select>", html += "</div>" 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) { 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) { 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) { function loadForm(context, user, userSettings, apiClient) {
context.querySelector(".chkHidePlayedFromLatest").checked = user.Configuration.HidePlayedInLatest || !1, updateHomeSectionValues(context, userSettings);
var promise1 = apiClient.getUserViews({ context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false;
IncludeHidden: !0
}, user.Id), updateHomeSectionValues(context, userSettings);
promise2 = apiClient.getJSON(apiClient.getUrl("Users/" + user.Id + "/GroupingOptions"));
Promise.all([promise1, promise2]).then(function(responses) { var promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id);
renderViewOrder(context, user, responses[0]), renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient), renderViews(context, user, responses[1]), loading.hide() 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) { function onSectionOrderListClick(e) {
var target = dom.parentWithClass(e.target, "btnViewItemMove");
var target = dom.parentWithClass(e.target, 'btnViewItemMove');
if (target) { if (target) {
var viewItem = dom.parentWithClass(target, "viewItem"); var viewItem = dom.parentWithClass(target, 'viewItem');
if (viewItem) { if (viewItem) {
dom.parentWithClass(viewItem, "paperList"); var ul = dom.parentWithClass(viewItem, 'paperList');
if (target.classList.contains("btnViewItemDown")) {
if (target.classList.contains('btnViewItemDown')) {
var next = viewItem.nextSibling; 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 { } else {
var prev = viewItem.previousSibling; 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) { 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) { 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.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked;
}), user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, !1).map(function(i) {
return i.getAttribute("data-folderid") user.Configuration.LatestItemsExcludes = getCheckboxItems(".chkIncludeInLatest", context, false).map(function (i) {
}), user.Configuration.GroupedFolders = getCheckboxItems(".chkGroupFolder", context, !0).map(function(i) {
return i.getAttribute("data-folderid") return i.getAttribute('data-folderid');
}); });
var i, length, viewItems = context.querySelectorAll(".viewItem"),
orderedViews = []; user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, false).map(function (i) {
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); return i.getAttribute('data-folderid');
var selectLandings = context.querySelectorAll(".selectLanding"); });
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++) { for (i = 0, length = selectLandings.length; i < length; i++) {
var selectLanding = selectLandings[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) { function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loading.show(), apiClient.getUser(userId).then(function(user) {
saveUser(context, user, userSettings, apiClient).then(function() { loading.show();
loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) {
toast(globalize.translate("sharedcomponents#SettingsSaved")) apiClient.getUser(userId).then(function (user) {
}), events.trigger(instance, "saved")
}, function() { saveUser(context, user, userSettings, apiClient).then(function () {
loading.hide()
}) loading.hide();
}) if (enableSaveConfirmation) {
require(['toast'], function (toast) {
toast(globalize.translate('sharedcomponents#SettingsSaved'));
});
}
events.trigger(instance, 'saved');
}, function () {
loading.hide();
});
});
} }
function onSubmit(e) { function onSubmit(e) {
var self = this,
apiClient = connectionManager.getApiClient(self.options.serverId), var self = this;
userId = self.options.userId, var apiClient = connectionManager.getApiClient(self.options.serverId);
userSettings = self.options.userSettings; var userId = self.options.userId;
return userSettings.setUserInfo(userId, apiClient).then(function() { var userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(function () {
var enableSaveConfirmation = self.options.enableSaveConfirmation; var enableSaveConfirmation = self.options.enableSaveConfirmation;
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation) save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
}), e && e.preventDefault(), !1 });
// Disable default form submission
if (e) {
e.preventDefault();
}
return false;
} }
function onChange(e) { function onChange(e) {
var chkIncludeInMyMedia = dom.parentWithClass(e.target, "chkIncludeInMyMedia");
if (chkIncludeInMyMedia) { var chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
var section = dom.parentWithClass(chkIncludeInMyMedia, "verticalSection"), if (!chkIncludeInMyMedia) {
fldIncludeInLatest = section.querySelector(".fldIncludeInLatest"); return;
fldIncludeInLatest && (chkIncludeInMyMedia.checked ? fldIncludeInLatest.classList.remove("hide") : fldIncludeInLatest.classList.add("hide")) }
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) { 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)); require(['text!./homescreensettings.template.html'], function (template) {
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)
}) 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) { function HomeScreenSettings(options) {
this.options = options, embed(options, this)
this.options = options;
embed(options, this);
} }
var numConfigurableSections = 7;
return HomeScreenSettings.prototype.loadData = function(autoFocus) { HomeScreenSettings.prototype.loadData = function (autoFocus) {
var self = this,
context = self.options.element; var self = this;
var context = self.options.element;
loading.show(); loading.show();
var userId = self.options.userId,
apiClient = connectionManager.getApiClient(self.options.serverId), var userId = self.options.userId;
userSettings = self.options.userSettings; var apiClient = connectionManager.getApiClient(self.options.serverId);
apiClient.getUser(userId).then(function(user) { var userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(function() {
self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient), autoFocus && focusManager.autoFocus(context) apiClient.getUser(userId).then(function (user) {
})
}) userSettings.setUserInfo(userId, apiClient).then(function () {
}, HomeScreenSettings.prototype.submit = function() {
onSubmit.call(this) self.dataLoaded = true;
}, HomeScreenSettings.prototype.destroy = function() {
this.options = null loadForm(context, user, userSettings, apiClient);
}, HomeScreenSettings
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) { define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'events', 'homescreenSettings', 'paper-icon-button-light', 'css!./../formdialog'], function (dialogHelper, layoutManager, globalize, require, events, HomescreenSettings) {
"use strict"; 'use strict';
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
var fn = on ? "on" : "off"; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz) scrollHelper.centerFocus[fn](elem, horiz);
}) });
} }
function show(options) { function show(options) {
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
require(["text!./homescreensettingsdialog.template.html"], function(template) {
require(['text!./homescreensettingsdialog.template.html'], function (template) {
var dialogOptions = { var dialogOptions = {
removeOnClose: !0, removeOnClose: true,
scrollY: !1 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); var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog");
var html = "", dlg.classList.add('formDialog');
submitted = !1;
html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0); 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({ var homescreenSettingsInstance = new HomescreenSettings({
serverId: options.serverId, serverId: options.serverId,
userId: options.userId, userId: options.userId,
element: dlg.querySelector(".settingsContent"), element: dlg.querySelector('.settingsContent'),
userSettings: options.userSettings, userSettings: options.userSettings,
enableSaveButton: !1, enableSaveButton: false,
enableSaveConfirmation: !1 enableSaveConfirmation: false
}); });
dialogHelper.open(dlg), dlg.addEventListener("close", function() {
layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted ? resolve() : reject() dialogHelper.open(dlg);
}), dlg.querySelector(".btnCancel").addEventListener("click", function(e) {
dialogHelper.close(dlg) dlg.addEventListener('close', function () {
}), dlg.querySelector(".btnSave").addEventListener("click", function(e) {
submitted = !0, homescreenSettingsInstance.submit() if (layoutManager.tv) {
}), events.on(homescreenSettingsInstance, "saved", function() { centerFocus(dlg.querySelector('.formDialogContent'), false, false);
submitted = !0, dialogHelper.close(dlg)
})
})
})
} }
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 { return {
show: show show: show
} };
}); });

View file

@ -1,10 +1,11 @@
.homeLibraryButton { .homeLibraryButton {
min-width: 18%; min-width: 18%;
margin: .5em !important margin: .5em !important;
} }
@media all and (max-width:50em) { @media all and (max-width: 50em) {
.homeLibraryButton { .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"; "use strict";
function getDefaultProfile() { function getDefaultProfile() {
return new Promise(function(resolve, reject) {
require(["browserdeviceprofile"], function(profileBuilder) { return new Promise(function (resolve, reject) {
resolve(profileBuilder({}))
}) require(['browserdeviceprofile'], function (profileBuilder) {
})
resolve(profileBuilder({}));
});
});
} }
var fadeTimeout;
function fade(instance, elem, startingVolume) { function fade(instance, elem, startingVolume) {
instance._isFadingOut = !0;
var newVolume = Math.max(0, startingVolume - .15); instance._isFadingOut = true;
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() { // Need to record the starting volume on each pass rather than querying elem.volume
fade(instance, elem, newVolume).then(resolve, reject) // This is due to iOS safari not allowing volume changes and always returning the system volume value
}, 100)
}) 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() { function cancelFadeTimeout() {
var timeout = fadeTimeout; var timeout = fadeTimeout;
timeout && (clearTimeout(timeout), fadeTimeout = null) if (timeout) {
clearTimeout(timeout);
fadeTimeout = null;
}
} }
function supportsFade() { 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) { function requireHlsPlayer(callback) {
require(["hlsjs"], function(hls) { require(['hlsjs'], function (hls) {
window.Hls = hls, callback() window.Hls = hls;
}) callback();
});
} }
function enableHlsPlayer(url, item, mediaSource, mediaType) { 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({ fetchHelper.ajax({
url: url, url: url,
type: "HEAD" type: 'HEAD'
}).then(function(response) { }).then(function (response) {
"application/x-mpegurl" === (response.headers.get("Content-Type") || "").toLowerCase() ? resolve() : reject()
}, reject) var contentType = (response.headers.get('Content-Type') || '').toLowerCase();
}) if (contentType === 'application/x-mpegurl') {
}) : Promise.reject() resolve();
} else {
reject();
}
}, reject);
});
});
} }
function HtmlAudioPlayer() { 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) { function setCurrentSrc(elem, options) {
elem.removeEventListener("error", onError), unBindEvents(elem), bindEvents(elem);
elem.removeEventListener('error', onError);
unBindEvents(elem);
bindEvents(elem);
var val = options.url; var val = options.url;
console.log("playing url: " + val); console.log('playing url: ' + val);
var seconds = (options.playerStartPositionTicks || 0) / 1e7;
seconds && (val += "#t=" + seconds), htmlMediaHelper.destroyHlsPlayer(self), self._currentPlayOptions = options; // 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); var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
return crossOrigin && (elem.crossOrigin = crossOrigin), enableHlsPlayer(val, options.item, options.mediaSource, "Audio").then(function() { if (crossOrigin) {
return new Promise(function(resolve, reject) { elem.crossOrigin = crossOrigin;
requireHlsPlayer(function() { }
return enableHlsPlayer(val, options.item, options.mediaSource, 'Audio').then(function () {
return new Promise(function (resolve, reject) {
requireHlsPlayer(function () {
var hls = new Hls({ 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 () {
elem.autoplay = true;
return htmlMediaHelper.applySrc(elem, val, options).then(function () {
self._currentSrc = val;
return 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() {
return elem.autoplay = !0, htmlMediaHelper.applySrc(elem, val, options).then(function() {
return self._currentSrc = val, htmlMediaHelper.playWithPromise(elem, onError)
})
})
} }
function bindEvents(elem) { 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) { 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; 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() { function onEnded() {
htmlMediaHelper.onEndedInternal(self, this, onError)
htmlMediaHelper.onEndedInternal(self, this, onError);
} }
function onTimeUpdate() { function onTimeUpdate() {
// Get the player position + the transcoding offset
var time = this.currentTime; 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() { 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) { 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) { function onPlay(e) {
events.trigger(self, "unpause")
events.trigger(self, 'unpause');
} }
function onPause() { function onPause() {
events.trigger(self, "pause") events.trigger(self, 'pause');
} }
function onError() { function onError() {
var errorCode = this.error ? this.error.code || 0 : 0,
errorMessage = this.error ? this.error.message || "" : ""; var errorCode = this.error ? (this.error.code || 0) : 0;
console.log("Media element error: " + errorCode.toString() + " " + errorMessage); var errorMessage = this.error ? (this.error.message || '') : '';
console.log('Media element error: ' + errorCode.toString() + ' ' + errorMessage);
var type; var type;
switch (errorCode) { switch (errorCode) {
case 1: case 1:
// MEDIA_ERR_ABORTED
// This will trigger when changing media while something is playing
return; return;
case 2: case 2:
type = "network"; // MEDIA_ERR_NETWORK
type = 'network';
break; break;
case 3: case 3:
if (self._hlsPlayer) return void htmlMediaHelper.handleHlsJsMediaError(self); // MEDIA_ERR_DECODE
type = "mediadecodeerror"; if (self._hlsPlayer) {
htmlMediaHelper.handleHlsJsMediaError(self);
return;
} else {
type = 'mediadecodeerror';
}
break; break;
case 4: case 4:
type = "medianotsupported"; // MEDIA_ERR_SRC_NOT_SUPPORTED
type = 'medianotsupported';
break; break;
default: 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)
} 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)
} }
} }
var fadeTimeout;
return HtmlAudioPlayer.prototype.currentSrc = function() { HtmlAudioPlayer.prototype.currentSrc = function () {
return this._currentSrc return this._currentSrc;
}, HtmlAudioPlayer.prototype.canPlayMediaType = function(mediaType) { };
return "audio" === (mediaType || "").toLowerCase()
}, HtmlAudioPlayer.prototype.getDeviceProfile = function(item) { HtmlAudioPlayer.prototype.canPlayMediaType = function (mediaType) {
return appHost.getDeviceProfile ? appHost.getDeviceProfile(item) : getDefaultProfile()
}, HtmlAudioPlayer.prototype.currentTime = function(val) { 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; var mediaElement = this._mediaElement;
if (mediaElement) { if (mediaElement) {
if (null != val) return void(mediaElement.currentTime = val / 1e3); if (val != null) {
var currentTime = this._currentTime; mediaElement.currentTime = val / 1000;
return currentTime ? 1e3 * currentTime : 1e3 * (mediaElement.currentTime || 0) return;
} }
}, HtmlAudioPlayer.prototype.duration = function(val) {
var currentTime = this._currentTime;
if (currentTime) {
return currentTime * 1000;
}
return (mediaElement.currentTime || 0) * 1000;
}
};
HtmlAudioPlayer.prototype.duration = function (val) {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
if (mediaElement) { if (mediaElement) {
var duration = mediaElement.duration; 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; var mediaElement = this._mediaElement;
if (mediaElement) { if (mediaElement) {
var seekable = mediaElement.seekable; var seekable = mediaElement.seekable;
if (seekable && seekable.length) { if (seekable && seekable.length) {
var start = seekable.start(0),
end = seekable.end(0); var start = seekable.start(0);
return htmlMediaHelper.isValidDuration(start) || (start = 0), htmlMediaHelper.isValidDuration(end) || (end = 0), end - start > 0 var end = seekable.end(0);
if (!htmlMediaHelper.isValidDuration(start)) {
start = 0;
} }
return !1 if (!htmlMediaHelper.isValidDuration(end)) {
end = 0;
} }
}, HtmlAudioPlayer.prototype.getBufferedRanges = function() {
return (end - start) > 0;
}
return false;
}
};
HtmlAudioPlayer.prototype.getBufferedRanges = function () {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
return mediaElement ? htmlMediaHelper.getBufferedRanges(this, mediaElement) : [] if (mediaElement) {
}, HtmlAudioPlayer.prototype.pause = function() {
return htmlMediaHelper.getBufferedRanges(this, mediaElement);
}
return [];
};
HtmlAudioPlayer.prototype.pause = function () {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
mediaElement && mediaElement.pause() if (mediaElement) {
}, HtmlAudioPlayer.prototype.resume = function() { mediaElement.pause();
}
};
// This is a retry after error
HtmlAudioPlayer.prototype.resume = function () {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
mediaElement && mediaElement.play() if (mediaElement) {
}, HtmlAudioPlayer.prototype.unpause = function() { mediaElement.play();
}
};
HtmlAudioPlayer.prototype.unpause = function () {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
mediaElement && mediaElement.play() if (mediaElement) {
}, HtmlAudioPlayer.prototype.paused = function() { mediaElement.play();
}
};
HtmlAudioPlayer.prototype.paused = function () {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
return !!mediaElement && mediaElement.paused if (mediaElement) {
}, HtmlAudioPlayer.prototype.setVolume = function(val) { return mediaElement.paused;
}
return false;
};
HtmlAudioPlayer.prototype.setVolume = function (val) {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
mediaElement && (mediaElement.volume = val / 100) if (mediaElement) {
}, HtmlAudioPlayer.prototype.getVolume = function() { mediaElement.volume = val / 100;
}
};
HtmlAudioPlayer.prototype.getVolume = function () {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
if (mediaElement) return Math.min(Math.round(100 * mediaElement.volume), 100) if (mediaElement) {
}, HtmlAudioPlayer.prototype.volumeUp = function() {
this.setVolume(Math.min(this.getVolume() + 2, 100)) return Math.min(Math.round(mediaElement.volume * 100), 100);
}, HtmlAudioPlayer.prototype.volumeDown = function() { }
this.setVolume(Math.max(this.getVolume() - 2, 0)) };
}, HtmlAudioPlayer.prototype.setMute = function(mute) {
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; var mediaElement = this._mediaElement;
mediaElement && (mediaElement.muted = mute) if (mediaElement) {
}, HtmlAudioPlayer.prototype.isMuted = function() { mediaElement.muted = mute;
}
};
HtmlAudioPlayer.prototype.isMuted = function () {
var mediaElement = this._mediaElement; var mediaElement = this._mediaElement;
return !!mediaElement && mediaElement.muted if (mediaElement) {
}, HtmlAudioPlayer.prototype.destroy = function() {}, HtmlAudioPlayer 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) { define(['appSettings', 'browser', 'events'], function (appSettings, browser, events) {
"use strict"; 'use strict';
function getSavedVolume() { function getSavedVolume() {
return appSettings.get("volume") || 1 return appSettings.get("volume") || 1;
} }
function saveVolume(value) { function saveVolume(value) {
value && appSettings.set("volume", value) if (value) {
appSettings.set("volume", value);
}
} }
function getCrossOriginValue(mediaSource) { function getCrossOriginValue(mediaSource) {
return mediaSource.IsRemote ? null : "anonymous"
if (mediaSource.IsRemote) {
return null;
}
return 'anonymous';
} }
function canPlayNativeHls() { function canPlayNativeHls() {
var media = document.createElement("video"); var media = document.createElement('video');
return !(!media.canPlayType("application/x-mpegURL").replace(/no/, "") && !media.canPlayType("application/vnd.apple.mpegURL").replace(/no/, ""))
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) { function enableHlsShakaPlayer(item, mediaSource, mediaType) {
if (window.MediaSource && MediaSource.isTypeSupported) {
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
if (canPlayNativeHls()) { if (canPlayNativeHls()) {
if (browser.edge && "Video" === mediaType) return !0;
mediaSource.RunTimeTicks if (browser.edge && mediaType === 'Video') {
return true;
} }
return !0
// simple playback should use the native support
if (mediaSource.RunTimeTicks) {
//if (!browser.edge) {
//return false;
//}
} }
return !1
//return false;
}
return true;
}
return false;
} }
function enableHlsJsPlayer(runTimeTicks, mediaType) { function enableHlsJsPlayer(runTimeTicks, mediaType) {
if (null == window.MediaSource) return !1;
if (browser.iOS) return !1; if (window.MediaSource == null) {
if (browser.tizen || browser.web0s) return !1; return false;
if (canPlayNativeHls()) {
if (browser.android && "Audio" === mediaType) return !0;
if (browser.edge, runTimeTicks) return !1
}
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) { function handleHlsJsMediaError(instance, reject) {
var hlsPlayer = instance._hlsPlayer; var hlsPlayer = instance._hlsPlayer;
if (hlsPlayer) {
if (!hlsPlayer) {
return;
}
var now = Date.now(); 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 (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) { function onErrorInternal(instance, type) {
instance.destroyCustomTrack && instance.destroyCustomTrack(instance._mediaElement), events.trigger(instance, "error", [{
// Needed for video
if (instance.destroyCustomTrack) {
instance.destroyCustomTrack(instance._mediaElement);
}
events.trigger(instance, 'error', [
{
type: type type: type
}]) }]);
} }
function isValidDuration(duration) { 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;
} }
function setCurrentTimeIfNeeded(element, seconds, allowance) { return false;
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) { function seekOnPlaybackStart(instance, element, ticks) {
var seconds = (ticks || 0) / 1e7;
var seconds = (ticks || 0) / 10000000;
if (seconds) { if (seconds) {
(instance.currentSrc() || "").toLowerCase(); var src = (instance.currentSrc() || '').toLowerCase();
setCurrentTimeIfNeeded(element, seconds, 5), setTimeout(function() {
setCurrentTimeIfNeeded(element, seconds, 10) // Appending #t=xxx to the query string doesn't seem to work with HLS
}, 2500) // 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) { 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, if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file),
startTime = (options.playerStartPositionTicks || 0) / 1e4; return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) {
return playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime)), elem.src = URL.createObjectURL(playlist, {
oneTimeOnly: !0 var playlist = new Windows.Media.Playback.MediaPlaybackList();
}), Promise.resolve()
}) : (elem.src = src, Promise.resolve()) 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) { function onSuccessfulPlay(elem, onErrorFn) {
elem.addEventListener("error", onErrorFn)
elem.addEventListener('error', onErrorFn);
} }
function playWithPromise(elem, onErrorFn) { function playWithPromise(elem, onErrorFn) {
try { try {
var promise = elem.play(); var promise = elem.play();
return promise && promise.then ? promise.catch(function(e) { if (promise && promise.then) {
var errorName = (e.name || "").toLowerCase(); // Chrome now returns a promise
return "notallowederror" === errorName || "aborterror" === errorName ? (onSuccessfulPlay(elem, onErrorFn), Promise.resolve()) : Promise.reject() return promise.catch(function (e) {
}) : (onSuccessfulPlay(elem, onErrorFn), Promise.resolve())
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) { } 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) { function destroyCastPlayer(instance) {
var player = instance._castPlayer; var player = instance._castPlayer;
if (player) { if (player) {
try { try {
player.unload() player.unload();
} catch (err) { } 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; var player = instance._shakaPlayer;
if (player) { if (player) {
try { try {
player.destroy() player.destroy();
} catch (err) { } 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; var player = instance._hlsPlayer;
if (player) { if (player) {
try { try {
player.destroy() player.destroy();
} catch (err) { } 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; var player = instance._flvPlayer;
if (player) { if (player) {
try { try {
player.unload(), player.detachMediaElement(), player.destroy() player.unload();
player.detachMediaElement();
player.destroy();
} catch (err) { } catch (err) {
console.log(err) console.log(err);
} }
instance._flvPlayer = null
instance._flvPlayer = null;
} }
} }
function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) { function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
hls.on(Hls.Events.MANIFEST_PARSED, function() {
playWithPromise(elem, onErrorFn).then(resolve, function() { hls.on(Hls.Events.MANIFEST_PARSED, function () {
reject && (reject(), reject = null) playWithPromise(elem, onErrorFn).then(resolve, function () {
})
}), hls.on(Hls.Events.ERROR, function(event, data) { if (reject) {
switch (console.log("HLS Error: Type: " + data.type + " Details: " + (data.details || "") + " Fatal: " + (data.fatal || !1)), data.type) { reject();
case Hls.ErrorTypes.NETWORK_ERROR: reject = null;
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) { });
});
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: 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()); // 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:
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; break;
case Hls.ErrorTypes.MEDIA_ERROR: case Hls.ErrorTypes.MEDIA_ERROR:
console.log("fatal media error encountered, try to recover"); console.log("fatal media error encountered, try to recover");
var currentReject = reject; var currentReject = reject;
reject = null, handleHlsJsMediaError(instance, currentReject); reject = null;
handleHlsJsMediaError(instance, currentReject);
break; break;
default: default:
console.log("Cannot recover from hls error - destroy and trigger error"), hls.destroy(), reject ? (reject(), reject = null) : onErrorInternal(instance, "mediadecodeerror")
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) { 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 = { var stopInfo = {
src: instance._currentSrc 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) { function getBufferedRanges(instance, elem) {
var offset, ranges = [],
seekable = elem.buffered || [], var ranges = [];
currentPlayOptions = instance._currentPlayOptions; var seekable = elem.buffered || [];
currentPlayOptions && (offset = currentPlayOptions.transcodingOffsetTicks), offset = offset || 0;
var offset;
var currentPlayOptions = instance._currentPlayOptions;
if (currentPlayOptions) {
offset = currentPlayOptions.transcodingOffsetTicks;
}
offset = offset || 0;
for (var i = 0, length = seekable.length; i < length; i++) { for (var i = 0, length = seekable.length; i < length; i++) {
var start = seekable.start(i),
end = seekable.end(i); var start = seekable.start(i);
isValidDuration(start) || (start = 0), isValidDuration(end) ? ranges.push({ var end = seekable.end(i);
start: 1e7 * start + offset,
end: 1e7 * end + offset if (!isValidDuration(start)) {
}) : end = 0 start = 0;
} }
return ranges if (!isValidDuration(end)) {
end = 0;
continue;
} }
var recoverDecodingErrorDate, recoverSwapAudioCodecDate;
ranges.push({
start: (start * 10000000) + offset,
end: (end * 10000000) + offset
});
}
return ranges;
}
return { return {
getSavedVolume: getSavedVolume, getSavedVolume: getSavedVolume,
saveVolume: saveVolume, saveVolume: saveVolume,
@ -214,5 +464,5 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
onEndedInternal: onEndedInternal, onEndedInternal: onEndedInternal,
getCrossOriginValue: getCrossOriginValue, getCrossOriginValue: getCrossOriginValue,
getBufferedRanges: getBufferedRanges getBufferedRanges: getBufferedRanges
} };
}); });

File diff suppressed because it is too large Load diff

View file

@ -4,47 +4,43 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center; align-items: center;
-webkit-align-items: center;
align-items: center
} }
.videoPlayerContainer:not(.videoPlayerContainer-withBackdrop) { .videoPlayerContainer:not(.videoPlayerContainer-withBackdrop) {
background: #000 !important background: #000 !important;
} }
.videoPlayerContainer-withBackdrop { .videoPlayerContainer-withBackdrop {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center center; background-position: center center;
-webkit-background-size: cover;
background-size: cover; background-size: cover;
background-attachment: fixed; background-attachment: fixed;
background-color: #000 background-color: #000;
} }
.videoPlayerContainer-onTop { .videoPlayerContainer-onTop {
z-index: 1000 z-index: 1000;
} }
.htmlvideoplayer { .htmlvideoplayer {
margin: 0 !important; margin: 0 !important;
padding: 0 !important; padding: 0 !important;
width: 100%; width: 100%;
height: 100% height: 100%;
} }
.htmlvideoplayer::cue { .htmlvideoplayer::cue {
background-color: transparent; background-color: transparent;
text-shadow: .14em .14em .14em rgba(0, 0, 0, 1); text-shadow: .14em .14em .14em rgba(0, 0, 0, 1);
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
font-family: inherit font-family: inherit;
} }
.htmlvideoplayer-moveupsubtitles::-webkit-media-text-track-display { .htmlvideoplayer-moveupsubtitles::-webkit-media-text-track-display {
margin-top: -2em /*Style the text itself*/
margin-top: -2em;
} }
.videoSubtitles { .videoSubtitles {
@ -54,41 +50,25 @@
left: 0; left: 0;
right: 0; right: 0;
color: #fff; color: #fff;
font-size: 170% font-size: 170%;
} }
.videoSubtitlesInner { .videoSubtitlesInner {
max-width: 70%; max-width: 70%;
background-color: rgba(0, 0, 0, .8); background-color: rgba(0,0,0,.8);
padding: .25em; padding: .25em;
margin: auto; margin: auto;
display: inline-block 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
}
} }
@keyframes htmlvideoplayer-zoomin { @keyframes htmlvideoplayer-zoomin {
from { from {
-webkit-transform: scale3d(.2, .2, .2);
transform: scale3d(.2, .2, .2); transform: scale3d(.2, .2, .2);
opacity: .6 opacity: .6;
} }
to { to {
-webkit-transform: none;
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) { 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"; '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() { function getBaseRemoteOptions() {
var options = {}; var options = {};
return options.itemId = currentItemId, options
options.itemId = currentItemId;
return options;
} }
function reloadBrowsableImages(page, apiClient) { function reloadBrowsableImages(page, apiClient) {
loading.show(); loading.show();
var options = getBaseRemoteOptions(); var options = getBaseRemoteOptions();
options.type = browsableImageType, options.startIndex = browsableImageStartIndex, options.limit = browsableImagePageSize, options.IncludeAllLanguages = page.querySelector("#chkAllLanguages").checked;
var provider = selectedProvider || ""; options.type = browsableImageType;
provider && (options.ProviderName = provider), apiClient.getAvailableRemoteImages(options).then(function(result) { options.startIndex = browsableImageStartIndex;
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit), page.querySelector("#selectBrowsableImageType").value = browsableImageType; options.limit = browsableImagePageSize;
var providersHtml = result.Providers.map(function(p) { options.IncludeAllLanguages = page.querySelector('#chkAllLanguages').checked;
return '<option value="' + p + '">' + p + "</option>"
}), var provider = selectedProvider || '';
selectImageProvider = page.querySelector("#selectImageProvider");
selectImageProvider.innerHTML = '<option value="">' + globalize.translate("sharedcomponents#All") + "</option>" + providersHtml, selectImageProvider.value = provider, loading.hide() 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) { 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); page.querySelector('.availableImagesPaging').innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
var availableImagesList = page.querySelector(".availableImagesList");
availableImagesList.innerHTML = html, imageLoader.lazyChildren(availableImagesList); var html = '';
var btnNextPage = page.querySelector(".btnNextPage"),
btnPreviousPage = page.querySelector(".btnPreviousPage"); for (var i = 0, length = imagesResult.Images.length; i < length; i++) {
btnNextPage && btnNextPage.addEventListener("click", function() {
browsableImageStartIndex += browsableImagePageSize, reloadBrowsableImages(page, apiClient) html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
}), btnPreviousPage && btnPreviousPage.addEventListener("click", function() { }
browsableImageStartIndex -= browsableImagePageSize, reloadBrowsableImages(page, 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) { function getPagingHtml(startIndex, limit, totalRecordCount) {
var html = "",
recordsEnd = Math.min(startIndex + limit, totalRecordCount), var html = '';
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 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) { function parentWithClass(elem, className) {
for (; !elem.classList || !elem.classList.contains(className);)
if (!(elem = elem.parentNode)) return null; while (!elem.classList || !elem.classList.contains(className)) {
return elem elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
} }
function downloadRemoteImage(page, apiClient, url, type, provider) { function downloadRemoteImage(page, apiClient, url, type, provider) {
var options = getBaseRemoteOptions(); var options = getBaseRemoteOptions();
options.Type = type, options.ImageUrl = url, options.ProviderName = provider, loading.show(), apiClient.downloadRemoteImage(options).then(function() {
hasChanges = !0; options.Type = type;
var dlg = parentWithClass(page, "dialog"); options.ImageUrl = url;
dialogHelper.close(dlg) options.ProviderName = provider;
})
loading.show();
apiClient.downloadRemoteImage(options).then(function () {
hasChanges = true;
var dlg = parentWithClass(page, 'dialog');
dialogHelper.close(dlg);
});
} }
function getDisplayUrl(url, apiClient) { function getDisplayUrl(url, apiClient) {
return apiClient.getUrl("Images/Remote", { return apiClient.getUrl("Images/Remote", { imageUrl: url });
imageUrl: url
})
} }
function getRemoteImageHtml(image, imageType, apiClient) { function getRemoteImageHtml(image, imageType, apiClient) {
var tagName = layoutManager.tv ? "button" : "div",
enableFooterButtons = !layoutManager.tv, var tagName = layoutManager.tv ? 'button' : 'div';
html = "", var enableFooterButtons = !layoutManager.tv;
cssClass = "card scalableCard imageEditorCard",
cardBoxCssClass = "cardBox visualCardBox", var html = '';
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 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) { function initEditor(page, apiClient) {
page.querySelector("#selectBrowsableImageType").addEventListener("change", function() {
browsableImageType = this.value, browsableImageStartIndex = 0, selectedProvider = null, reloadBrowsableImages(page, apiClient) page.querySelector('#selectBrowsableImageType').addEventListener('change', function () {
}), page.querySelector("#selectImageProvider").addEventListener("change", function() { browsableImageType = this.value;
browsableImageStartIndex = 0, selectedProvider = this.value, reloadBrowsableImages(page, apiClient) browsableImageStartIndex = 0;
}), page.querySelector("#chkAllLanguages").addEventListener("change", function() { selectedProvider = null;
browsableImageStartIndex = 0, reloadBrowsableImages(page, apiClient)
}), page.addEventListener("click", function(e) { reloadBrowsableImages(page, apiClient);
var btnDownloadRemoteImage = parentWithClass(e.target, "btnDownloadRemoteImage"); });
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) { if (btnDownloadRemoteImage) {
var card = parentWithClass(btnDownloadRemoteImage, "card"); var card = parentWithClass(btnDownloadRemoteImage, 'card');
return void downloadRemoteImage(page, apiClient, card.getAttribute("data-imageurl"), card.getAttribute("data-imagetype"), card.getAttribute("data-imageprovider")) 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) { 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); var apiClient = connectionManager.getApiClient(serverId);
currentItemId = itemId, currentItemType = itemType;
currentItemId = itemId;
currentItemType = itemType;
var dialogOptions = { 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); 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"); dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
initEditor(editorContent, apiClient), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg) if (layoutManager.tv) {
}), reloadBrowsableImages(editorContent, apiClient) 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() { function onDialogClosed() {
var dlg = this; var dlg = this;
layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), hasChanges ? currentResolve() : currentReject()
if (layoutManager.tv) {
scrollHelper.centerFocus.off(dlg, false);
} }
var currentItemId, currentItemType, currentResolve, currentReject, selectedProvider, hasChanges = !1,
browsableImagePageSize = browser.slow ? 6 : 30, loading.hide();
browsableImageStartIndex = 0, if (hasChanges) {
browsableImageType = "Primary"; currentResolve();
} else {
currentReject();
}
}
return { return {
show: function(itemId, serverId, itemType, imageType) { 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) 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 { .imageEditor-buttons {
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
margin: 1em 0 margin: 1em 0 1em;
} }
.first-imageEditor-buttons { .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) { 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"; 'use strict';
var currentItem;
var hasChanges = false;
function getBaseRemoteOptions() { function getBaseRemoteOptions() {
var options = {}; var options = {};
return options.itemId = currentItem.Id, options
options.itemId = currentItem.Id;
return options;
} }
function reload(page, item, focusContext) { function reload(page, item, focusContext) {
loading.show(); loading.show();
var apiClient; 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) { function addListeners(container, className, eventName, fn) {
container.addEventListener(eventName, function(e) {
container.addEventListener(eventName, function (e) {
var elem = dom.parentWithClass(e.target, className); var elem = dom.parentWithClass(e.target, className);
elem && fn.call(elem, e) if (elem) {
}) fn.call(elem, e);
}
});
} }
function reloadItem(page, item, apiClient, focusContext) { 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"); currentItem = item;
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) 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) { 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) { function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
var html = "",
cssClass = "card scalableCard imageEditorCard", var html = '';
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, { var cssClass = "card scalableCard imageEditorCard";
maxWidth: imageSize var cardBoxCssClass = 'cardBox visualCardBox';
}) + "');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 + ">"
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) { function deleteImage(context, itemId, type, index, apiClient, enableConfirmation) {
var afterConfirm = function() {
apiClient.deleteItemImage(itemId, type, index).then(function() { var afterConfirm = function () {
hasChanges = !0, reload(context) 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({ confirm({
text: globalize.translate("sharedcomponents#ConfirmDeleteImage"),
confirmText: globalize.translate("sharedcomponents#Delete"), text: globalize.translate('sharedcomponents#ConfirmDeleteImage'),
primary: "cancel" confirmText: globalize.translate('sharedcomponents#Delete'),
}).then(afterConfirm) primary: 'cancel'
})
}).then(afterConfirm);
});
} }
function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) { function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) {
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function() {
hasChanges = !0, reload(context, null, focusContext) apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function () {
}, function() {
require(["alert"], function(alert) { hasChanges = true;
alert(globalize.translate("sharedcomponents#DefaultErrorMessage")) reload(context, null, focusContext);
}) }, function () {
})
require(['alert'], function (alert) {
alert(globalize.translate('sharedcomponents#DefaultErrorMessage'));
});
});
} }
function renderImages(page, item, apiClient, images, imageProviders, elem) { function renderImages(page, item, apiClient, images, imageProviders, elem) {
var html = "",
imageSize = 300, var html = '';
windowSize = dom.getWindowSize();
windowSize.innerWidth >= 1280 && (imageSize = Math.round(windowSize.innerWidth / 4)); var imageSize = 300;
for (var tagName = layoutManager.tv ? "button" : "div", enableFooterButtons = !layoutManager.tv, i = 0, length = images.length; i < length; i++) { var windowSize = dom.getWindowSize();
html += getCardHtml(images[i], i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) 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) { 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 var images = imageInfos.filter(function (i) {
}), imageProviders, page.querySelector("#images")) 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) { function renderBackdrops(page, apiClient, item, imageInfos, imageProviders) {
var images = imageInfos.filter(function(i) {
return "Backdrop" === i.ImageType var images = imageInfos.filter(function (i) {
}).sort(function(a, b) { return i.ImageType === "Backdrop";
return a.ImageIndex - b.ImageIndex
}).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) { function renderScreenshots(page, apiClient, item, imageInfos, imageProviders) {
var images = imageInfos.filter(function(i) {
return "Screenshot" === i.ImageType var images = imageInfos.filter(function (i) {
}).sort(function(a, b) { return i.ImageType === "Screenshot";
return a.ImageIndex - b.ImageIndex
}).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) { function showImageDownloader(page, imageType) {
require(["imageDownloader"], function(ImageDownloader) {
ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function() { require(['imageDownloader'], function (ImageDownloader) {
hasChanges = !0, reload(page)
}) ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function () {
})
hasChanges = true;
reload(page);
});
});
} }
function showActionSheet(context, imageCard) { function showActionSheet(context, imageCard) {
var itemId = imageCard.getAttribute("data-id"),
serverId = imageCard.getAttribute("data-serverid"), var itemId = imageCard.getAttribute('data-id');
apiClient = connectionManager.getApiClient(serverId), var serverId = imageCard.getAttribute('data-serverid');
type = imageCard.getAttribute("data-imagetype"), var apiClient = connectionManager.getApiClient(serverId);
index = parseInt(imageCard.getAttribute("data-index")),
providerCount = parseInt(imageCard.getAttribute("data-providers")), var type = imageCard.getAttribute('data-imagetype');
numImages = parseInt(imageCard.getAttribute("data-numimages")); var index = parseInt(imageCard.getAttribute('data-index'));
require(["actionsheet"], function(actionSheet) { var providerCount = parseInt(imageCard.getAttribute('data-providers'));
var numImages = parseInt(imageCard.getAttribute('data-numimages'));
require(['actionsheet'], function (actionSheet) {
var commands = []; var commands = [];
commands.push({ commands.push({
name: globalize.translate("sharedcomponents#Delete"), name: globalize.translate('sharedcomponents#Delete'),
id: "delete" id: 'delete'
}), "Backdrop" !== type && "Screenshot" !== type || (index > 0 && commands.push({ });
name: globalize.translate("sharedcomponents#MoveLeft"),
id: "moveleft" if (type === 'Backdrop' || type === 'Screenshot') {
}), index < numImages - 1 && commands.push({ if (index > 0) {
name: globalize.translate("sharedcomponents#MoveRight"), commands.push({
id: "moveright" name: globalize.translate('sharedcomponents#MoveLeft'),
})), providerCount && commands.push({ id: 'moveleft'
name: globalize.translate("sharedcomponents#Search"), });
id: "search" }
}), actionSheet.show({
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, items: commands,
positionTo: imageCard positionTo: imageCard
}).then(function(id) {
}).then(function (id) {
switch (id) { switch (id) {
case "delete":
deleteImage(context, itemId, type, index, apiClient, !1); case 'delete':
deleteImage(context, itemId, type, index, apiClient, false);
break; break;
case "search": case 'search':
showImageDownloader(context, type); showImageDownloader(context, type);
break; break;
case "moveleft": case 'moveleft':
moveImage(context, apiClient, itemId, type, index, index - 1, dom.parentWithClass(imageCard, "itemsContainer")); 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; break;
case "moveright":
moveImage(context, apiClient, itemId, type, index, index + 1, dom.parentWithClass(imageCard, "itemsContainer"))
} }
})
}) });
});
} }
function initEditor(context, options) { 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 uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
var imageType = this.getAttribute("data-imagetype"); var isFileInputSupported = appHost.supports('fileinput');
require(["imageUploader"], function(imageUploader) { 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({ imageUploader.show({
theme: options.theme, theme: options.theme,
imageType: imageType, imageType: imageType,
itemId: currentItem.Id, itemId: currentItem.Id,
serverId: currentItem.ServerId serverId: currentItem.ServerId
}).then(function(hasChanged) {
hasChanged && (hasChanges = !0, reload(context)) }).then(function (hasChanged) {
})
}) if (hasChanged) {
}), addListeners(context, "btnSearchImages", "click", function() { hasChanges = true;
showImageDownloader(context, this.getAttribute("data-imagetype")) reload(context);
}), 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"), addListeners(context, 'btnSearchImages', 'click', function () {
index = this.getAttribute("data-index"); showImageDownloader(context, this.getAttribute('data-imagetype'));
index = "null" === index ? null : parseInt(index); });
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); var apiClient = connectionManager.getApiClient(currentItem.ServerId);
deleteImage(context, currentItem.Id, type, index, apiClient, !0) deleteImage(context, currentItem.Id, type, index, apiClient, true);
}), addListeners(context, "btnMoveImage", "click", function() { });
var type = this.getAttribute("data-imagetype"),
index = this.getAttribute("data-index"), addListeners(context, 'btnMoveImage', 'click', function () {
newIndex = this.getAttribute("data-newindex"), var type = this.getAttribute('data-imagetype');
apiClient = connectionManager.getApiClient(currentItem.ServerId); var index = this.getAttribute('data-index');
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, "itemsContainer")) 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) { function showEditor(options, resolve, reject) {
var itemId = options.itemId,
serverId = options.serverId; var itemId = options.itemId;
loading.show(), require(["text!./imageeditor.template.html"], function(template) { var serverId = options.serverId;
loading.show();
require(['text!./imageeditor.template.html'], function (template) {
var apiClient = connectionManager.getApiClient(serverId); var apiClient = connectionManager.getApiClient(serverId);
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) { apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
var dialogOptions = { 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); 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() dlg.classList.add('formDialog');
}), dialogHelper.open(dlg), reload(dlg, item), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg) dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
})
}) if (layoutManager.tv) {
}) scrollHelper.centerFocus.on(dlg, false);
} }
var currentItem, hasChanges = !1;
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);
});
});
});
}
return { return {
show: function(options) { show: function (options) {
return new Promise(function(resolve, reject) {
hasChanges = !1, showEditor(options, resolve, reject) return new Promise(function (resolve, reject) {
})
} hasChanges = false;
showEditor(options, resolve, reject);
});
} }
};
}); });

View file

@ -1,18 +1,38 @@
define(["dom"], function(dom) { define(['dom'], function (dom) {
"use strict"; 'use strict';
function loadImage(elem, url) { 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) { function loadImageIntoImg(elem, url) {
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
dom.addEventListener(elem, "load", resolve, {
once: !0 dom.addEventListener(elem, 'load', resolve, {
}), elem.setAttribute("src", url) once: true
}) });
elem.setAttribute("src", url);
});
} }
return { return {
loadImage: loadImage loadImage: loadImage
} };
}); });

View file

@ -1,82 +1,255 @@
define(["lazyLoader", "imageFetcher", "layoutManager", "browser", "appSettings", "require", "css!./style"], function(lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) { define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', 'require', 'css!./style'], function (lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) {
"use strict"; 'use strict';
var requestIdleCallback = window.requestIdleCallback || function (fn) {
fn();
};
var self = {};
// seeing slow performance with firefox
var enableFade = false;
function fillImage(elem, source, enableEffects) { 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) { function fillImageElement(elem, source, enableEffects) {
imageFetcher.loadImage(elem, source).then(function() { imageFetcher.loadImage(elem, source).then(function () {
enableFade && !1 !== enableEffects && fadeIn(elem), elem.removeAttribute("data-src")
}) 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) { function getVibrantInfoFromElement(elem, url) {
return new Promise(function(resolve, reject) {
require(["vibrant"], function() { return new Promise(function (resolve, reject) {
if ("IMG" === elem.tagName) return void resolve(getVibrantInfo(elem, url));
var img = new Image; require(['vibrant'], function () {
img.onload = function() {
resolve(getVibrantInfo(img, url)) if (elem.tagName === 'IMG') {
}, img.src = url resolve(getVibrantInfo(elem, url));
}) return;
}) }
var img = new Image();
img.onload = function () {
resolve(getVibrantInfo(img, url));
};
img.src = url;
});
});
} }
function getSettingsKey(url) { function getSettingsKey(url) {
var parts = url.split("://");
url = parts[parts.length - 1], url = url.substring(url.indexOf("/") + 1), url = url.split("?")[0]; var parts = url.split('://');
return "vibrant31" + url 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) { function getCachedVibrantInfo(url) {
return appSettings.get(getSettingsKey(url))
return appSettings.get(getSettingsKey(url));
} }
function getVibrantInfo(img, url) { function getVibrantInfo(img, url) {
var value = getCachedVibrantInfo(url); var value = getCachedVibrantInfo(url);
if (value) return value; if (value) {
var vibrant = new Vibrant(img), return value;
swatches = vibrant.swatches(); }
return value = "", value += getSwatchString(swatches.DarkVibrant), appSettings.set(getSettingsKey(url), value), 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) { function getSwatchString(swatch) {
return swatch ? swatch.getHex() + "|" + swatch.getBodyTextColor() + "|" + swatch.getTitleTextColor() : "||"
if (swatch) {
return swatch.getHex() + '|' + swatch.getBodyTextColor() + '|' + swatch.getTitleTextColor();
}
return '||';
} }
function fadeIn(elem) { function fadeIn(elem) {
elem.classList.add("lazy-image-fadein")
var cssClass = 'lazy-image-fadein';
elem.classList.add(cssClass);
} }
function lazyChildren(elem) { function lazyChildren(elem) {
lazyLoader.lazyChildren(elem, fillImage)
lazyLoader.lazyChildren(elem, fillImage);
} }
function getPrimaryImageAspectRatio(items) { 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; var ratio = items[i].PrimaryImageAspectRatio || 0;
ratio && (values[values.length] = ratio)
if (!ratio) {
continue;
} }
if (!values.length) return null;
values.sort(function(a, b) { values[values.length] = ratio;
return a - b }
});
var result, half = Math.floor(values.length / 2); if (!values.length) {
result = values.length % 2 ? values[half] : (values[half - 1] + values[half]) / 2; return null;
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; // Use the median
return Math.abs(4 / 3 - result) <= .15 ? 4 / 3 : result 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) { function fillImages(elems) {
for (var i = 0, length = elems.length; i < length; i++) { 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; self.fillImages = fillImages;
return self.fillImages = fillImages, self.lazyImage = fillImage, self.lazyChildren = lazyChildren, self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio, self.getCachedVibrantInfo = getCachedVibrantInfo, self.getVibrantInfoFromElement = getVibrantInfoFromElement, self 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 { .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 { .lazy-image-fadein-fast {
-webkit-animation: lazy-image-fadein 160ms ease-in normal both; 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
}
} }
@keyframes lazy-image-fadein { @keyframes lazy-image-fadein {
from { from {
opacity: 0 opacity: 0;
} }
to { to {
opacity: 1 opacity: 1;
} }
} }
.lazy-image-fadein { .lazy-image-fadein {
opacity: 0; opacity: 0;
-webkit-animation-duration: .8s; -webkit-animation-duration: .8s;
-moz-animation-duration: .8s;
-o-animation-duration: .8s;
animation-duration: .8s; animation-duration: .8s;
-webkit-animation-name: popInAnimation; -webkit-animation-name: popInAnimation;
-moz-animation-name: popInAnimation;
-o-animation-name: popInAnimation;
animation-name: popInAnimation; animation-name: popInAnimation;
-webkit-animation-fill-mode: forwards; -webkit-animation-fill-mode: forwards;
-moz-animation-fill-mode: forwards;
-o-animation-fill-mode: forwards;
animation-fill-mode: forwards; animation-fill-mode: forwards;
-webkit-animation-timing-function: cubic-bezier(0, 0, .5, 1); -webkit-animation-timing-function: cubic-bezier(0,0,.5,1);
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);
@-webkit-keyframes popInAnimation {
0% {
opacity: 0
}
100% {
opacity: 1
}
} }
@keyframes popInAnimation { @keyframes popInAnimation {
0% { 0% {
opacity: 0 opacity: 0;
} }
100% { 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) { 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"; 'use strict';
var currentItemId;
var currentServerId;
var currentFile;
var hasChanges = false;
function onFileReaderError(evt) { function onFileReaderError(evt) {
switch (loading.hide(), evt.target.error.code) {
loading.hide();
switch (evt.target.error.code) {
case evt.target.error.NOT_FOUND_ERR: case evt.target.error.NOT_FOUND_ERR:
require(["toast"], function(toast) { require(['toast'], function (toast) {
toast(globalize.translate("sharedcomponents#MessageFileReadError")) toast(globalize.translate('sharedcomponents#MessageFileReadError'));
}); });
break; break;
case evt.target.error.ABORT_ERR: case evt.target.error.ABORT_ERR:
break; break; // noop
default: default:
require(["toast"], function(toast) { require(['toast'], function (toast) {
toast(globalize.translate("sharedcomponents#MessageFileReadError")) toast(globalize.translate('sharedcomponents#MessageFileReadError'));
}) });
break;
} }
} }
function setFiles(page, files) { function setFiles(page, files) {
var file = files[0]; var file = files[0];
if (!file || !file.type.match("image.*")) return page.querySelector("#imageOutput").innerHTML = "", page.querySelector("#fldUpload").classList.add("hide"), void(currentFile = null);
currentFile = file; if (!file || !file.type.match('image.*')) {
var reader = new FileReader; page.querySelector('#imageOutput').innerHTML = '';
reader.onerror = onFileReaderError, reader.onloadstart = function() { page.querySelector('#fldUpload').classList.add('hide');
page.querySelector("#fldUpload").classList.add("hide") currentFile = null;
}, reader.onabort = function() { return;
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)
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');
};
// 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) { function onSubmit(e) {
var file = currentFile; 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(); loading.show();
var dlg = dom.parentWithClass(this, "dialog"),
imageType = dlg.querySelector("#selectImageType").value; var dlg = dom.parentWithClass(this, 'dialog');
return connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(function() {
dlg.querySelector("#uploadImage").value = "", loading.hide(), hasChanges = !0, dialogHelper.close(dlg) var imageType = dlg.querySelector('#selectImageType').value;
}), e.preventDefault(), !1
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) { function initEditor(page) {
page.querySelector("form").addEventListener("submit", onSubmit), page.querySelector("#uploadImage").addEventListener("change", function() {
setFiles(page, this.files) page.querySelector('form').addEventListener('submit', onSubmit);
}), page.querySelector(".btnBrowse").addEventListener("click", function() {
page.querySelector("#uploadImage").click() 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) { 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 = { 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); 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) dlg.classList.add('formDialog');
}), dialogHelper.open(dlg), initEditor(dlg), dlg.querySelector("#selectImageType").value = options.imageType || "Primary", dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg) dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
})
}) if (layoutManager.tv) {
scrollHelper.centerFocus.on(dlg, false);
} }
var currentItemId, currentServerId, currentFile, hasChanges = !1;
// 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);
});
});
}
return { return {
show: function(options) { show: function (options) {
return new Promise(function(resolve, reject) {
hasChanges = !1, showEditor(options, resolve, reject) 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; border: .2em dashed currentcolor;
-webkit-border-radius: .25em;
border-radius: .25em; border-radius: .25em;
/* padding: 1.6em; */
text-align: center; text-align: center;
position: relative; position: relative;
height: 12em; height: 12em;
display: -webkit-box;
display: -webkit-flex;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center; justify-content: center;
-webkit-justify-content: center;
justify-content: center
} }

View file

@ -1,125 +1,96 @@
.itemProgressBar { .itemProgressBar {
background: #333; background: #333;
background: rgba(51, 51, 51, .8); background: rgba(51,51,51,.8);
position: relative; position: relative;
height: .28em height: .28em;
} }
.itemProgressBarForeground { .itemProgressBarForeground {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
bottom: 0 bottom: 0;
} }
.indicator { .indicator {
-webkit-border-radius: 100em;
border-radius: 100em; border-radius: 100em;
display: -webkit-flex; display: -webkit-flex;
display: -webkit-box;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
font-weight: 500; font-weight: 500;
width: 2em; width: 2em;
height: 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)
} }
.timerIndicator { .timerIndicator {
color: #CB272A color: #CB272A;
} }
.timerIndicator-inactive { .timerIndicator-inactive {
color: #888 color: #888;
} }
.indicator+.indicator { .indicator + .indicator {
margin-left: .25em margin-left: .25em;
} }
.indicatorIcon { .indicatorIcon {
width: auto; width: auto;
height: auto; height: auto;
font-size: 1.6em font-size: 1.6em;
} }
.countIndicator { .countIndicator {
border-radius: 100em; border-radius: 100em;
display: -webkit-flex;
display: flex; display: flex;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
font-weight: 500; font-weight: 500;
color: #fff; 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); 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% font-size: 88%;
} }
.playedIndicator { .playedIndicator {
border-radius: 100em; border-radius: 100em;
display: -webkit-flex;
display: flex; display: flex;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
color: #fff; 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); 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% font-size: 80%;
} }
.videoIndicator { .videoIndicator {
background: #444; background: #444;
-webkit-border-radius: 100em;
border-radius: 100em; border-radius: 100em;
display: -webkit-flex; display: -webkit-flex;
display: -webkit-box;
display: flex; display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center; justify-content: center;
color: #fff; 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, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 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%;
font-size: 88%
} }
.syncIndicator { .syncIndicator {
-webkit-border-radius: 100em; border-radius: 100em;
border-radius: 100em
} }
.emptySyncIndicator { .emptySyncIndicator {
background: #ccc; background: #ccc;
color: #333 color: #333;
} }
.missingIndicator, .missingIndicator, .unairedIndicator {
.unairedIndicator { background: #cc3333;
background: #c33;
padding: .25em .5em; padding: .25em .5em;
-webkit-border-radius: 100em;
border-radius: 100em; border-radius: 100em;
color: #fff; color: #fff;
font-size: 84%; font-size: 84%;
font-weight: 500; 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) { define(['datetime', 'itemHelper', 'css!./indicators.css', 'material-icons'], function (datetime, itemHelper) {
"use strict"; 'use strict';
function enableProgressIndicator(item) { 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) { 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) { function getAutoTimeProgressHtml(pct, options, isRecording, start, end) {
var containerClass = "itemProgressBar";
options && options.containerClass && (containerClass += " " + options.containerClass); var containerClass = 'itemProgressBar';
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>' 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) { function getProgressBarHtml(item, options) {
var pct; var pct;
if (enableProgressIndicator(item) && "Recording" !== item.Type) {
var userData = options ? options.userData || item.UserData : item.UserData; if (enableProgressIndicator(item) && item.Type !== "Recording") {
if (userData && (pct = userData.PlayedPercentage) && pct < 100) return getProgressHtml(pct, options)
var userData = options ? (options.userData || item.UserData) : item.UserData;
if (userData) {
pct = userData.PlayedPercentage;
if (pct && 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;
if ((item.Type === 'Program' || item.Type === 'Timer' || item.Type === 'Recording') && item.StartDate && item.EndDate) {
var startDate = 0;
var endDate = 1;
try { try {
startDate = datetime.parseISO8601Date(item.StartDate).getTime()
} catch (err) {} startDate = datetime.parseISO8601Date(item.StartDate).getTime();
} catch (err) {
}
try { try {
endDate = datetime.parseISO8601Date(item.EndDate).getTime()
} catch (err) {} endDate = datetime.parseISO8601Date(item.EndDate).getTime();
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) } 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 ""
return '';
} }
function enablePlayedIndicator(item) { function enablePlayedIndicator(item) {
return itemHelper.canMarkPlayed(item)
return itemHelper.canMarkPlayed(item);
} }
function getPlayedIndicator(item) { function getPlayedIndicator(item) {
if (enablePlayedIndicator(item)) { if (enablePlayedIndicator(item)) {
var userData = item.UserData || {}; 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>';
} }
return ""
if (userData.PlayedPercentage && userData.PlayedPercentage >= 100 || (userData.Played)) {
return '<div class="playedIndicator indicator"><i class="md-icon indicatorIcon">&#xE5CA;</i></div>';
}
}
return '';
} }
function getCountIndicatorHtml(count) { function getCountIndicatorHtml(count) {
return '<div class="countIndicator indicator">' + count + "</div>"
return '<div class="countIndicator indicator">' + count + '</div>';
} }
function getChildCountIndicatorHtml(item, options) { function getChildCountIndicatorHtml(item, options) {
var minCount = 0; 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) { function getTimerIndicator(item) {
var status; var status;
if ("SeriesTimer" === item.Type) return '<i class="md-icon timerIndicator indicatorIcon">&#xE062;</i>';
if (item.TimerId || item.SeriesTimerId) status = item.Status || "Cancelled"; if (item.Type === 'SeriesTimer') {
else { return '<i class="md-icon timerIndicator indicatorIcon">&#xE062;</i>';
if ("Timer" !== item.Type) return "";
status = item.Status
} }
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) { 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) { 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) { function getMissingIndicator(item) {
if ("Episode" === item.Type && "Virtual" === item.LocationType) {
if (item.PremiereDate) try { if (item.Type === 'Episode' && item.LocationType === 'Virtual') {
if (datetime.parseISO8601Date(item.PremiereDate).getTime() > (new Date).getTime()) return '<div class="unairedIndicator">Unaired</div>'
} catch (err) {} if (item.PremiereDate) {
return '<div class="missingIndicator">Missing</div>' try {
}
return "" var premiereDate = datetime.parseISO8601Date(item.PremiereDate).getTime();
if (premiereDate > new Date().getTime()) {
return '<div class="unairedIndicator">Unaired</div>';
} }
function onAutoTimeProgress() { } catch (err) {
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 + "%"
} }
}
return '<div class="missingIndicator">Missing</div>';
}
return '';
}
var ProgressBarPrototype = Object.create(HTMLDivElement.prototype); 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)) function onAutoTimeProgress() {
}, ProgressBarPrototype.detachedCallback = function() {
this.timeInterval && (clearInterval(this.timeInterval), this.timeInterval = null) var start = parseInt(this.getAttribute('data-starttime'));
}, document.registerElement("emby-progressbar", { 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, prototype: ProgressBarPrototype,
extends: "div" extends: 'div'
}), { });
return {
getProgressBarHtml: getProgressBarHtml, getProgressBarHtml: getProgressBarHtml,
getPlayedIndicatorHtml: getPlayedIndicator, getPlayedIndicatorHtml: getPlayedIndicator,
getChildCountIndicatorHtml: getChildCountIndicatorHtml, getChildCountIndicatorHtml: getChildCountIndicatorHtml,
@ -116,5 +278,5 @@ define(["datetime", "itemHelper", "css!./indicators.css", "material-icons"], fun
getSyncIndicator: getSyncIndicator, getSyncIndicator: getSyncIndicator,
getTypeIndicator: getTypeIndicator, getTypeIndicator: getTypeIndicator,
getMissingIndicator: getMissingIndicator getMissingIndicator: getMissingIndicator
} };
}); });

View file

@ -1,122 +1,176 @@
define(["connectionManager", "playbackManager", "events", "inputManager", "focusManager", "appRouter"], function(connectionManager, playbackManager, events, inputManager, focusManager, appRouter) { define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focusManager', 'appRouter'], function (connectionManager, playbackManager, events, inputManager, focusManager, appRouter) {
"use strict"; 'use strict';
var serverNotifications = {};
function notifyApp() { function notifyApp() {
inputManager.notify()
inputManager.notify();
} }
function displayMessage(cmd) { function displayMessage(cmd) {
var args = cmd.Arguments; var args = cmd.Arguments;
args.TimeoutMs ? require(["toast"], function(toast) {
toast({ if (args.TimeoutMs) {
title: args.Header,
text: args.Text require(['toast'], function (toast) {
}) toast({ title: args.Header, text: args.Text });
}) : require(["alert"], function(alert) { });
alert({
title: args.Header, }
text: args.Text else {
}) require(['alert'], function (alert) {
}) alert({ title: args.Header, text: args.Text });
});
}
} }
function displayContent(cmd, apiClient) { function displayContent(cmd, apiClient) {
playbackManager.isPlayingLocally(["Video", "Book", "Game"]) || appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId())
if (!playbackManager.isPlayingLocally(['Video', 'Book', 'Game'])) {
appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId());
}
} }
function playTrailers(apiClient, itemId) { function playTrailers(apiClient, itemId) {
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) {
playbackManager.playTrailers(item) apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
})
playbackManager.playTrailers(item);
});
} }
function processGeneralCommand(cmd, apiClient) { function processGeneralCommand(cmd, apiClient) {
// Full list
// https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs#L23
//console.log('Received command: ' + cmd.Name);
switch (cmd.Name) { switch (cmd.Name) {
case "Select":
return void inputManager.trigger("select"); case 'Select':
case "Back": inputManager.trigger('select');
return void inputManager.trigger("back"); return;
case "MoveUp": case 'Back':
return void inputManager.trigger("up"); inputManager.trigger('back');
case "MoveDown": return;
return void inputManager.trigger("down"); case 'MoveUp':
case "MoveLeft": inputManager.trigger('up');
return void inputManager.trigger("left"); return;
case "MoveRight": case 'MoveDown':
return void inputManager.trigger("right"); inputManager.trigger('down');
case "PageUp": return;
return void inputManager.trigger("pageup"); case 'MoveLeft':
case "PageDown": inputManager.trigger('left');
return void inputManager.trigger("pagedown"); return;
case "PlayTrailers": case 'MoveRight':
inputManager.trigger('right');
return;
case 'PageUp':
inputManager.trigger('pageup');
return;
case 'PageDown':
inputManager.trigger('pagedown');
return;
case 'PlayTrailers':
playTrailers(apiClient, cmd.Arguments.ItemId); playTrailers(apiClient, cmd.Arguments.ItemId);
break; break;
case "SetRepeatMode": case 'SetRepeatMode':
playbackManager.setRepeatMode(cmd.Arguments.RepeatMode); playbackManager.setRepeatMode(cmd.Arguments.RepeatMode);
break; break;
case "VolumeUp": case 'VolumeUp':
return void inputManager.trigger("volumeup"); inputManager.trigger('volumeup');
case "VolumeDown": return;
return void inputManager.trigger("volumedown"); case 'VolumeDown':
case "ChannelUp": inputManager.trigger('volumedown');
return void inputManager.trigger("channelup"); return;
case "ChannelDown": case 'ChannelUp':
return void inputManager.trigger("channeldown"); inputManager.trigger('channelup');
case "Mute": return;
return void inputManager.trigger("mute"); case 'ChannelDown':
case "Unmute": inputManager.trigger('channeldown');
return void inputManager.trigger("unmute"); return;
case "ToggleMute": case 'Mute':
return void inputManager.trigger("togglemute"); inputManager.trigger('mute');
case "SetVolume": return;
notifyApp(), playbackManager.setVolume(cmd.Arguments.Volume); case 'Unmute':
inputManager.trigger('unmute');
return;
case 'ToggleMute':
inputManager.trigger('togglemute');
return;
case 'SetVolume':
notifyApp();
playbackManager.setVolume(cmd.Arguments.Volume);
break; break;
case "SetAudioStreamIndex": case 'SetAudioStreamIndex':
notifyApp(), playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index)); notifyApp();
playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index));
break; break;
case "SetSubtitleStreamIndex": case 'SetSubtitleStreamIndex':
notifyApp(), playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index)); notifyApp();
playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index));
break; break;
case "ToggleFullscreen": case 'ToggleFullscreen':
return void inputManager.trigger("togglefullscreen"); inputManager.trigger('togglefullscreen');
case "GoHome": return;
return void inputManager.trigger("home"); case 'GoHome':
case "GoToSettings": inputManager.trigger('home');
return void inputManager.trigger("settings"); return;
case "DisplayContent": case 'GoToSettings':
inputManager.trigger('settings');
return;
case 'DisplayContent':
displayContent(cmd, apiClient); displayContent(cmd, apiClient);
break; break;
case "GoToSearch": case 'GoToSearch':
return void inputManager.trigger("search"); inputManager.trigger('search');
case "DisplayMessage": return;
case 'DisplayMessage':
displayMessage(cmd); displayMessage(cmd);
break; break;
case "ToggleOsd": case 'ToggleOsd':
case "ToggleContextMenu": // todo
case "TakeScreenShot":
case "SendKey":
break; break;
case "SendString": case 'ToggleContextMenu':
// todo
break;
case 'TakeScreenShot':
// todo
break;
case 'SendKey':
// todo
break;
case 'SendString':
// todo
focusManager.sendText(cmd.Arguments.String); focusManager.sendText(cmd.Arguments.String);
break; break;
default: default:
console.log("processGeneralCommand does not recognize: " + cmd.Name) console.log('processGeneralCommand does not recognize: ' + cmd.Name);
break;
} }
notifyApp()
notifyApp();
} }
function onMessageReceived(e, msg) { function onMessageReceived(e, msg) {
var apiClient = this; var apiClient = this;
if ("Play" === msg.MessageType) {
if (msg.MessageType === "Play") {
notifyApp(); notifyApp();
var serverId = apiClient.serverInfo().Id; var serverId = apiClient.serverInfo().Id;
"PlayNext" === msg.Data.PlayCommand ? playbackManager.queueNext({
ids: msg.Data.ItemIds, if (msg.Data.PlayCommand === "PlayNext") {
serverId: serverId playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId });
}) : "PlayLast" === msg.Data.PlayCommand ? playbackManager.queue({ }
ids: msg.Data.ItemIds, else if (msg.Data.PlayCommand === "PlayLast") {
serverId: serverId playbackManager.queue({ ids: msg.Data.ItemIds, serverId: serverId });
}) : playbackManager.play({ }
else {
playbackManager.play({
ids: msg.Data.ItemIds, ids: msg.Data.ItemIds,
startPositionTicks: msg.Data.StartPositionTicks, startPositionTicks: msg.Data.StartPositionTicks,
mediaSourceId: msg.Data.MediaSourceId, mediaSourceId: msg.Data.MediaSourceId,
@ -124,22 +178,68 @@ define(["connectionManager", "playbackManager", "events", "inputManager", "focus
subtitleStreamIndex: msg.Data.SubtitleStreamIndex, subtitleStreamIndex: msg.Data.SubtitleStreamIndex,
startIndex: msg.Data.StartIndex, startIndex: msg.Data.StartIndex,
serverId: serverId serverId: serverId
}) });
} else if ("Playstate" === msg.MessageType) "Stop" === msg.Data.Command ? inputManager.trigger("stop") : "Pause" === msg.Data.Command ? inputManager.trigger("pause") : "Unpause" === msg.Data.Command ? inputManager.trigger("play") : "PlayPause" === msg.Data.Command ? inputManager.trigger("playpause") : "Seek" === msg.Data.Command ? playbackManager.seek(msg.Data.SeekPositionTicks) : "NextTrack" === msg.Data.Command ? inputManager.trigger("next") : "PreviousTrack" === msg.Data.Command ? inputManager.trigger("previous") : notifyApp(); }
else if ("GeneralCommand" === msg.MessageType) {
}
else if (msg.MessageType === "Playstate") {
if (msg.Data.Command === 'Stop') {
inputManager.trigger('stop');
}
else if (msg.Data.Command === 'Pause') {
inputManager.trigger('pause');
}
else if (msg.Data.Command === 'Unpause') {
inputManager.trigger('play');
}
else if (msg.Data.Command === 'PlayPause') {
inputManager.trigger('playpause');
}
else if (msg.Data.Command === 'Seek') {
playbackManager.seek(msg.Data.SeekPositionTicks);
}
else if (msg.Data.Command === 'NextTrack') {
inputManager.trigger('next');
}
else if (msg.Data.Command === 'PreviousTrack') {
inputManager.trigger('previous');
} else {
notifyApp();
}
}
else if (msg.MessageType === "GeneralCommand") {
var cmd = msg.Data; var cmd = msg.Data;
processGeneralCommand(cmd, apiClient) processGeneralCommand(cmd, apiClient);
} else if ("UserDataChanged" === msg.MessageType) { }
if (msg.Data.UserId === apiClient.getCurrentUserId()) else if (msg.MessageType === "UserDataChanged") {
for (var i = 0, length = msg.Data.UserDataList.length; i < length; i++) events.trigger(serverNotifications, "UserDataChanged", [apiClient, msg.Data.UserDataList[i]])
} else events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]) if (msg.Data.UserId === apiClient.getCurrentUserId()) {
for (var i = 0, length = msg.Data.UserDataList.length; i < length; i++) {
events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]);
}
}
}
else {
events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]);
}
} }
function bindEvents(apiClient) { function bindEvents(apiClient) {
events.off(apiClient, "message", onMessageReceived), events.on(apiClient, "message", onMessageReceived)
events.off(apiClient, "message", onMessageReceived);
events.on(apiClient, "message", onMessageReceived);
} }
var serverNotifications = {};
return connectionManager.getApiClients().forEach(bindEvents), events.on(connectionManager, "apiclientcreated", function(e, newApiClient) { connectionManager.getApiClients().forEach(bindEvents);
bindEvents(newApiClient)
}), serverNotifications events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {
bindEvents(newApiClient);
});
return serverNotifications;
}); });

Some files were not shown because too many files have changed in this diff Show more