mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'master' into quickconnect
This commit is contained in:
commit
6d4478e8f2
407 changed files with 15878 additions and 12346 deletions
130
src/scripts/alphanumericshortcuts.js
Normal file
130
src/scripts/alphanumericshortcuts.js
Normal file
|
@ -0,0 +1,130 @@
|
|||
define(['dom', 'focusManager'], function (dom, focusManager) {
|
||||
'use strict';
|
||||
|
||||
var inputDisplayElement;
|
||||
var currentDisplayText = '';
|
||||
var currentDisplayTextContainer;
|
||||
|
||||
function onKeyDown(e) {
|
||||
|
||||
if (e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
if (e.shiftKey) {
|
||||
return;
|
||||
}
|
||||
if (e.altKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = e.key;
|
||||
var chr = key ? alphanumeric(key) : null;
|
||||
|
||||
if (chr) {
|
||||
|
||||
chr = chr.toString().toUpperCase();
|
||||
|
||||
if (chr.length === 1) {
|
||||
currentDisplayTextContainer = this.options.itemsContainer;
|
||||
onAlphanumericKeyPress(e, chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function alphanumeric(value) {
|
||||
var letterNumber = /^[0-9a-zA-Z]+$/;
|
||||
return value.match(letterNumber);
|
||||
}
|
||||
|
||||
function ensureInputDisplayElement() {
|
||||
if (!inputDisplayElement) {
|
||||
inputDisplayElement = document.createElement('div');
|
||||
inputDisplayElement.classList.add('alphanumeric-shortcut');
|
||||
inputDisplayElement.classList.add('hide');
|
||||
|
||||
document.body.appendChild(inputDisplayElement);
|
||||
}
|
||||
}
|
||||
|
||||
var alpanumericShortcutTimeout;
|
||||
function clearAlphaNumericShortcutTimeout() {
|
||||
if (alpanumericShortcutTimeout) {
|
||||
clearTimeout(alpanumericShortcutTimeout);
|
||||
alpanumericShortcutTimeout = null;
|
||||
}
|
||||
}
|
||||
function resetAlphaNumericShortcutTimeout() {
|
||||
clearAlphaNumericShortcutTimeout();
|
||||
alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2000);
|
||||
}
|
||||
|
||||
function onAlphanumericKeyPress(e, chr) {
|
||||
if (currentDisplayText.length >= 3) {
|
||||
return;
|
||||
}
|
||||
ensureInputDisplayElement();
|
||||
currentDisplayText += chr;
|
||||
inputDisplayElement.innerHTML = currentDisplayText;
|
||||
inputDisplayElement.classList.remove('hide');
|
||||
resetAlphaNumericShortcutTimeout();
|
||||
}
|
||||
|
||||
function onAlphanumericShortcutTimeout() {
|
||||
var value = currentDisplayText;
|
||||
var container = currentDisplayTextContainer;
|
||||
|
||||
currentDisplayText = '';
|
||||
currentDisplayTextContainer = null;
|
||||
inputDisplayElement.innerHTML = '';
|
||||
inputDisplayElement.classList.add('hide');
|
||||
clearAlphaNumericShortcutTimeout();
|
||||
selectByShortcutValue(container, value);
|
||||
}
|
||||
|
||||
function selectByShortcutValue(container, value) {
|
||||
|
||||
value = value.toUpperCase();
|
||||
|
||||
var focusElem;
|
||||
if (value === '#') {
|
||||
|
||||
focusElem = container.querySelector('*[data-prefix]');
|
||||
}
|
||||
|
||||
if (!focusElem) {
|
||||
focusElem = container.querySelector('*[data-prefix^=\'' + value + '\']');
|
||||
}
|
||||
|
||||
if (focusElem) {
|
||||
focusManager.focus(focusElem);
|
||||
}
|
||||
}
|
||||
|
||||
function AlphaNumericShortcuts(options) {
|
||||
|
||||
this.options = options;
|
||||
|
||||
var keyDownHandler = onKeyDown.bind(this);
|
||||
|
||||
dom.addEventListener(window, 'keydown', keyDownHandler, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
this.keyDownHandler = keyDownHandler;
|
||||
}
|
||||
|
||||
AlphaNumericShortcuts.prototype.destroy = function () {
|
||||
|
||||
var keyDownHandler = this.keyDownHandler;
|
||||
|
||||
if (keyDownHandler) {
|
||||
dom.removeEventListener(window, 'keydown', keyDownHandler, {
|
||||
passive: true
|
||||
});
|
||||
this.keyDownHandler = null;
|
||||
}
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return AlphaNumericShortcuts;
|
||||
});
|
|
@ -1,14 +1,14 @@
|
|||
(function() {
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
function injectScriptElement(src, onload) {
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
|
||||
var script = document.createElement("script");
|
||||
var script = document.createElement('script');
|
||||
if (self.dashboardVersion) {
|
||||
src += "?v=" + self.dashboardVersion;
|
||||
src += `?v=${self.dashboardVersion}`;
|
||||
}
|
||||
script.src = src;
|
||||
|
||||
|
@ -21,18 +21,28 @@
|
|||
|
||||
function loadSite() {
|
||||
injectScriptElement(
|
||||
"./libraries/alameda.js",
|
||||
'./libraries/alameda.js',
|
||||
function() {
|
||||
// onload of require library
|
||||
injectScriptElement("./scripts/site.js");
|
||||
injectScriptElement('./scripts/site.js');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Promise.resolve();
|
||||
} catch (ex) {
|
||||
// this checks for several cases actually, typical is
|
||||
// Promise() being missing on some legacy browser, and a funky one
|
||||
// is Promise() present but buggy on WebOS 2
|
||||
window.Promise = undefined;
|
||||
self.Promise = undefined;
|
||||
}
|
||||
|
||||
if (!self.Promise) {
|
||||
// Load Promise polyfill if they are not natively supported
|
||||
injectScriptElement(
|
||||
"./libraries/npo.js",
|
||||
'./libraries/npo.js',
|
||||
loadSite
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
define(["backdrop", "userSettings", "libraryMenu"], function (backdrop, userSettings, libraryMenu) {
|
||||
"use strict";
|
||||
define(['backdrop', 'userSettings', 'libraryMenu'], function (backdrop, userSettings, libraryMenu) {
|
||||
'use strict';
|
||||
|
||||
var cache = {};
|
||||
|
||||
function enabled() {
|
||||
return userSettings.enableBackdrops();
|
||||
}
|
||||
|
||||
function getBackdropItemIds(apiClient, userId, types, parentId) {
|
||||
var key = "backdrops2_" + userId + (types || "") + (parentId || "");
|
||||
var key = `backdrops2_${userId + (types || '') + (parentId || '')}`;
|
||||
var data = cache[key];
|
||||
|
||||
if (data) {
|
||||
console.debug("Found backdrop id list in cache. Key: " + key);
|
||||
console.debug(`Found backdrop id list in cache. Key: ${key}`);
|
||||
data = JSON.parse(data);
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
|
||||
var options = {
|
||||
SortBy: "IsFavoriteOrLiked,Random",
|
||||
SortBy: 'IsFavoriteOrLiked,Random',
|
||||
Limit: 20,
|
||||
Recursive: true,
|
||||
IncludeItemTypes: types,
|
||||
ImageTypes: "Backdrop",
|
||||
ImageTypes: 'Backdrop',
|
||||
ParentId: parentId,
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
|
@ -54,18 +56,17 @@ define(["backdrop", "userSettings", "libraryMenu"], function (backdrop, userSett
|
|||
}
|
||||
}
|
||||
|
||||
var cache = {};
|
||||
pageClassOn("pageshow", "page", function () {
|
||||
pageClassOn('pageshow', 'page', function () {
|
||||
var page = this;
|
||||
|
||||
if (!page.classList.contains("selfBackdropPage")) {
|
||||
if (page.classList.contains("backdropPage")) {
|
||||
if (!page.classList.contains('selfBackdropPage')) {
|
||||
if (page.classList.contains('backdropPage')) {
|
||||
if (enabled()) {
|
||||
var type = page.getAttribute("data-backdroptype");
|
||||
var parentId = page.classList.contains("globalBackdropPage") ? "" : libraryMenu.getTopParentId();
|
||||
var type = page.getAttribute('data-backdroptype');
|
||||
var parentId = page.classList.contains('globalBackdropPage') ? '' : libraryMenu.getTopParentId();
|
||||
showBackdrop(type, parentId);
|
||||
} else {
|
||||
page.classList.remove("backdropPage");
|
||||
page.classList.remove('backdropPage');
|
||||
backdrop.clear();
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -22,7 +22,7 @@ define([], function () {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (userAgent.indexOf('webos') !== -1) {
|
||||
if (userAgent.indexOf('web0s') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -77,10 +77,10 @@ define([], function () {
|
|||
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');
|
||||
// Check if the property is supported
|
||||
var support = (camel in el.style);
|
||||
// Assign the property and value to invoke
|
||||
// the CSS interpreter
|
||||
el.style.cssText = prop + ':' + value;
|
||||
|
@ -185,7 +185,7 @@ define([], function () {
|
|||
/(safari)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(firefox)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(msie) ([\w.]+)/.exec(ua) ||
|
||||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
||||
ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
||||
[];
|
||||
|
||||
var versionMatch = /(version)[ \/]([\w.]+)/.exec(ua);
|
||||
|
@ -196,17 +196,17 @@ define([], function () {
|
|||
/(android)/.exec(ua) ||
|
||||
[];
|
||||
|
||||
var browser = match[1] || "";
|
||||
var browser = match[1] || '';
|
||||
|
||||
if (browser === "edge") {
|
||||
platform_match = [""];
|
||||
if (browser === 'edge') {
|
||||
platform_match = [''];
|
||||
} else {
|
||||
if (ua.indexOf("windows phone") !== -1 || ua.indexOf("iemobile") !== -1) {
|
||||
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";
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ define([], function () {
|
|||
version = versionMatch[2];
|
||||
}
|
||||
|
||||
version = version || match[2] || "0";
|
||||
version = version || match[2] || '0';
|
||||
|
||||
var versionMajor = parseInt(version.split('.')[0]);
|
||||
|
||||
|
@ -230,7 +230,7 @@ define([], function () {
|
|||
return {
|
||||
browser: browser,
|
||||
version: version,
|
||||
platform: platform_match[0] || "",
|
||||
platform: platform_match[0] || '',
|
||||
versionMajor: versionMajor
|
||||
};
|
||||
};
|
||||
|
@ -250,11 +250,11 @@ define([], function () {
|
|||
browser[matched.platform] = true;
|
||||
}
|
||||
|
||||
if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf("webkit") !== -1) {
|
||||
if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
if (userAgent.toLowerCase().indexOf("playstation 4") !== -1) {
|
||||
if (userAgent.toLowerCase().indexOf('playstation 4') !== -1) {
|
||||
browser.ps4 = true;
|
||||
browser.tv = true;
|
||||
}
|
||||
|
@ -292,6 +292,7 @@ define([], function () {
|
|||
}
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0)) {
|
||||
browser.touch = true;
|
||||
}
|
||||
|
|
|
@ -311,9 +311,9 @@ define(['browser'], function (browser) {
|
|||
try {
|
||||
var isTizenUhd = webapis.productinfo.isUdPanelSupported();
|
||||
isTizenFhd = !isTizenUhd;
|
||||
console.debug("isTizenFhd = " + isTizenFhd);
|
||||
console.debug('isTizenFhd = ' + isTizenFhd);
|
||||
} catch (error) {
|
||||
console.error("isUdPanelSupported() error code = " + error.code);
|
||||
console.error('isUdPanelSupported() error code = ' + error.code);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,6 +334,7 @@ define(['browser'], function (browser) {
|
|||
|
||||
var canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, '');
|
||||
var canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, '');
|
||||
var canPlayAv1 = videoTestElement.canPlayType('video/webm; codecs="av1"').replace(/no/, '');
|
||||
var webmAudioCodecs = ['vorbis'];
|
||||
|
||||
var canPlayMkv = testCanPlayMkv(videoTestElement);
|
||||
|
@ -592,6 +593,15 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
}
|
||||
|
||||
if (canPlayAv1) {
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'webm',
|
||||
Type: 'Video',
|
||||
AudioCodec: webmAudioCodecs.join(','),
|
||||
VideoCodec: 'AV1'
|
||||
});
|
||||
}
|
||||
|
||||
profile.TranscodingProfiles = [];
|
||||
|
||||
var hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls() ? true : false;
|
||||
|
@ -887,6 +897,16 @@ define(['browser'], function (browser) {
|
|||
Method: 'External'
|
||||
});
|
||||
}
|
||||
if (options.enableSsaRender) {
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: 'ass',
|
||||
Method: 'External'
|
||||
});
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: 'ssa',
|
||||
Method: 'External'
|
||||
});
|
||||
}
|
||||
|
||||
profile.ResponseProfiles = [];
|
||||
profile.ResponseProfiles.push({
|
||||
|
|
|
@ -41,12 +41,12 @@ define(['globalize'], function (globalize) {
|
|||
}
|
||||
|
||||
// if there's a timezone, calculate it
|
||||
if (d[8] !== "Z" && d[10]) {
|
||||
if (d[8] !== 'Z' && d[10]) {
|
||||
var offset = d[10] * 60 * 60 * 1000;
|
||||
if (d[11]) {
|
||||
offset += d[11] * 60 * 1000;
|
||||
}
|
||||
if (d[9] === "-") {
|
||||
if (d[9] === '-') {
|
||||
ms -= offset;
|
||||
} else {
|
||||
ms += offset;
|
||||
|
@ -159,13 +159,13 @@ define(['globalize'], function (globalize) {
|
|||
var optionList = getOptionList(options);
|
||||
if (optionList.length === 1 && optionList[0].name === 'weekday') {
|
||||
var weekday = [];
|
||||
weekday[0] = "Sun";
|
||||
weekday[1] = "Mon";
|
||||
weekday[2] = "Tue";
|
||||
weekday[3] = "Wed";
|
||||
weekday[4] = "Thu";
|
||||
weekday[5] = "Fri";
|
||||
weekday[6] = "Sat";
|
||||
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()];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,104 +1,62 @@
|
|||
import { ar, be, bg, ca, cs, da, de, el, enGB, enUS, es, faIR, fi, fr, frCA, he, hi, hr, hu, id, it, kk, ko, lt, ms, nb, nl, pl, ptBR, pt, ro, ru, sk, sl, sv, tr, uk, vi, zhCN, zhTW } from 'date-fns/locale';
|
||||
import globalize from 'globalize';
|
||||
|
||||
export function getLocale() {
|
||||
switch (globalize.getCurrentLocale()) {
|
||||
case 'ar':
|
||||
return ar;
|
||||
case 'be-by':
|
||||
return be;
|
||||
case 'bg-bg':
|
||||
return bg;
|
||||
case 'ca':
|
||||
return ca;
|
||||
case 'cs':
|
||||
return cs;
|
||||
case 'da':
|
||||
return da;
|
||||
case 'de':
|
||||
return de;
|
||||
case 'el':
|
||||
return el;
|
||||
case 'en-gb':
|
||||
return enGB;
|
||||
case 'en-us':
|
||||
return enUS;
|
||||
case 'es':
|
||||
return es;
|
||||
case 'es-ar':
|
||||
return es;
|
||||
case 'es-mx':
|
||||
return es;
|
||||
case 'fa':
|
||||
return faIR;
|
||||
case 'fi':
|
||||
return fi;
|
||||
case 'fr':
|
||||
return fr;
|
||||
case 'fr-ca':
|
||||
return frCA;
|
||||
case 'gsw':
|
||||
return de;
|
||||
case 'he':
|
||||
return he;
|
||||
case 'hi-in':
|
||||
return hi;
|
||||
case 'hr':
|
||||
return hr;
|
||||
case 'hu':
|
||||
return hu;
|
||||
case 'id':
|
||||
return id;
|
||||
case 'it':
|
||||
return it;
|
||||
case 'kk':
|
||||
return kk;
|
||||
case 'ko':
|
||||
return ko;
|
||||
case 'lt-lt':
|
||||
return lt;
|
||||
case 'ms':
|
||||
return ms;
|
||||
case 'nb':
|
||||
return nb;
|
||||
case 'nl':
|
||||
return nl;
|
||||
case 'pl':
|
||||
return pl;
|
||||
case 'pt-br':
|
||||
return ptBR;
|
||||
case 'pt-pt':
|
||||
return pt;
|
||||
case 'ro':
|
||||
return ro;
|
||||
case 'ru':
|
||||
return ru;
|
||||
case 'sk':
|
||||
return sk;
|
||||
case 'sl-si':
|
||||
return sl;
|
||||
case 'sv':
|
||||
return sv;
|
||||
case 'tr':
|
||||
return tr;
|
||||
case 'uk':
|
||||
return uk;
|
||||
case 'vi':
|
||||
return vi;
|
||||
case 'zh-cn':
|
||||
return zhCN;
|
||||
case 'zh-hk':
|
||||
return zhCN;
|
||||
case 'zh-tw':
|
||||
return zhTW;
|
||||
default:
|
||||
return enUS;
|
||||
}
|
||||
}
|
||||
|
||||
export const localeWithSuffix = { addSuffix: true, locale: getLocale() };
|
||||
|
||||
export default {
|
||||
getLocale: getLocale,
|
||||
localeWithSuffix: localeWithSuffix
|
||||
};
|
||||
import { ar, be, bg, ca, cs, da, de, el, enGB, enUS, es, faIR, fi, fr, frCA, he, hi, hr, hu, id, it, ja, kk, ko, lt, ms, nb,
|
||||
nl, pl, ptBR, pt, ro, ru, sk, sl, sv, tr, uk, vi, zhCN, zhTW } from 'date-fns/locale';
|
||||
import globalize from 'globalize';
|
||||
|
||||
const dateLocales = (locale) => ({
|
||||
'ar': ar,
|
||||
'be-by': be,
|
||||
'bg-bg': bg,
|
||||
'ca': ca,
|
||||
'cs': cs,
|
||||
'da': da,
|
||||
'de': de,
|
||||
'el': el,
|
||||
'en-gb': enGB,
|
||||
'en-us': enUS,
|
||||
'es': es,
|
||||
'es-ar': es,
|
||||
'es-mx': es,
|
||||
'fa': faIR,
|
||||
'fi': fi,
|
||||
'fr': fr,
|
||||
'fr-ca': frCA,
|
||||
'gsw': de,
|
||||
'he': he,
|
||||
'hi-in': hi,
|
||||
'hr': hr,
|
||||
'hu': hu,
|
||||
'id': id,
|
||||
'it': it,
|
||||
'ja': ja,
|
||||
'kk': kk,
|
||||
'ko': ko,
|
||||
'lt-lt': lt,
|
||||
'ms': ms,
|
||||
'nb': nb,
|
||||
'nl': nl,
|
||||
'pl': pl,
|
||||
'pt-br': ptBR,
|
||||
'pt-pt': pt,
|
||||
'ro': ro,
|
||||
'ru': ru,
|
||||
'sk': sk,
|
||||
'sl-si': sl,
|
||||
'sv': sv,
|
||||
'tr': tr,
|
||||
'uk': uk,
|
||||
'vi': vi,
|
||||
'zh-cn': zhCN,
|
||||
'zh-hk': zhCN,
|
||||
'zh-tw': zhTW
|
||||
})[locale];
|
||||
|
||||
export function getLocale() {
|
||||
return dateLocales(globalize.getCurrentLocale()) || enUS;
|
||||
}
|
||||
|
||||
export const localeWithSuffix = { addSuffix: true, locale: getLocale() };
|
||||
|
||||
export default {
|
||||
getLocale: getLocale,
|
||||
localeWithSuffix: localeWithSuffix
|
||||
};
|
||||
|
|
278
src/scripts/dom.js
Normal file
278
src/scripts/dom.js
Normal file
|
@ -0,0 +1,278 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Useful DOM utilities.
|
||||
* @module components/dom
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns parent of element with specified attribute value.
|
||||
* @param {HTMLElement} elem - Element whose parent need to find.
|
||||
* @param {string} name - Attribute name.
|
||||
* @param {mixed} value - Attribute value.
|
||||
* @returns {HTMLElement} Parent with specified attribute value.
|
||||
*/
|
||||
export function parentWithAttribute(elem, name, value) {
|
||||
while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem || !elem.getAttribute) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parent of element with one of specified tag names.
|
||||
* @param {HTMLElement} elem - Element whose parent need to find.
|
||||
* @param {(string|Array)} tagNames - Tag name or array of tag names.
|
||||
* @returns {HTMLElement} Parent with one of specified tag names.
|
||||
*/
|
||||
export function parentWithTag(elem, tagNames) {
|
||||
// accept both string and array passed in
|
||||
if (!Array.isArray(tagNames)) {
|
||||
tagNames = [tagNames];
|
||||
}
|
||||
|
||||
while (tagNames.indexOf(elem.tagName || '') === -1) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns _true_ if class list contains one of specified names.
|
||||
* @param {DOMTokenList} classList - Class list.
|
||||
* @param {Array} classNames - Array of class names.
|
||||
* @returns {boolean} _true_ if class list contains one of specified names.
|
||||
*/
|
||||
function containsAnyClass(classList, classNames) {
|
||||
for (let i = 0, length = classNames.length; i < length; i++) {
|
||||
if (classList.contains(classNames[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parent of element with one of specified class names.
|
||||
* @param {HTMLElement} elem - Element whose parent need to find.
|
||||
* @param {(string|Array)} classNames - Class name or array of class names.
|
||||
* @returns {HTMLElement} Parent with one of specified class names.
|
||||
*/
|
||||
export function parentWithClass(elem, classNames) {
|
||||
// accept both string and array passed in
|
||||
if (!Array.isArray(classNames)) {
|
||||
classNames = [classNames];
|
||||
}
|
||||
|
||||
while (!elem.classList || !containsAnyClass(elem.classList, classNames)) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
let supportsCaptureOption = false;
|
||||
try {
|
||||
const opts = Object.defineProperty({}, 'capture', {
|
||||
// eslint-disable-next-line getter-return
|
||||
get: function () {
|
||||
supportsCaptureOption = true;
|
||||
}
|
||||
});
|
||||
window.addEventListener('test', null, opts);
|
||||
} catch (e) {
|
||||
console.debug('error checking capture support');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds event listener to specified target.
|
||||
* @param {EventTarget} target - Event target.
|
||||
* @param {string} type - Event type.
|
||||
* @param {function} handler - Event handler.
|
||||
* @param {Object} [options] - Listener options.
|
||||
*/
|
||||
export function addEventListener(target, type, handler, options) {
|
||||
let optionsOrCapture = options || {};
|
||||
if (!supportsCaptureOption) {
|
||||
optionsOrCapture = optionsOrCapture.capture;
|
||||
}
|
||||
target.addEventListener(type, handler, optionsOrCapture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes event listener from specified target.
|
||||
* @param {EventTarget} target - Event target.
|
||||
* @param {string} type - Event type.
|
||||
* @param {function} handler - Event handler.
|
||||
* @param {Object} [options] - Listener options.
|
||||
*/
|
||||
export function removeEventListener(target, type, handler, options) {
|
||||
let optionsOrCapture = options || {};
|
||||
if (!supportsCaptureOption) {
|
||||
optionsOrCapture = optionsOrCapture.capture;
|
||||
}
|
||||
target.removeEventListener(type, handler, optionsOrCapture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached window size.
|
||||
*/
|
||||
let windowSize;
|
||||
|
||||
/**
|
||||
* Flag of event listener bound.
|
||||
*/
|
||||
let windowSizeEventsBound;
|
||||
|
||||
/**
|
||||
* Resets cached window size.
|
||||
*/
|
||||
function clearWindowSize() {
|
||||
windowSize = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns window size.
|
||||
* @returns {Object} Window size.
|
||||
*/
|
||||
export function getWindowSize() {
|
||||
if (!windowSize) {
|
||||
windowSize = {
|
||||
innerHeight: window.innerHeight,
|
||||
innerWidth: window.innerWidth
|
||||
};
|
||||
|
||||
if (!windowSizeEventsBound) {
|
||||
windowSizeEventsBound = true;
|
||||
addEventListener(window, 'orientationchange', clearWindowSize, { passive: true });
|
||||
addEventListener(window, 'resize', clearWindowSize, { passive: true });
|
||||
}
|
||||
}
|
||||
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard screen widths.
|
||||
*/
|
||||
const standardWidths = [480, 720, 1280, 1440, 1920, 2560, 3840, 5120, 7680];
|
||||
|
||||
/**
|
||||
* Returns screen width.
|
||||
* @returns {number} Screen width.
|
||||
*/
|
||||
export function getScreenWidth() {
|
||||
let width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
|
||||
if (height > width) {
|
||||
width = height * (16.0 / 9.0);
|
||||
}
|
||||
|
||||
const closest = standardWidths.sort(function (a, b) {
|
||||
return Math.abs(width - a) - Math.abs(width - b);
|
||||
})[0];
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of animation end event.
|
||||
*/
|
||||
let _animationEvent;
|
||||
|
||||
/**
|
||||
* Returns name of animation end event.
|
||||
* @returns {string} Name of animation end event.
|
||||
*/
|
||||
export function whichAnimationEvent() {
|
||||
if (_animationEvent) {
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
const el = document.createElement('div');
|
||||
const animations = {
|
||||
'animation': 'animationend',
|
||||
'OAnimation': 'oAnimationEnd',
|
||||
'MozAnimation': 'animationend',
|
||||
'WebkitAnimation': 'webkitAnimationEnd'
|
||||
};
|
||||
for (let t in animations) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_animationEvent = animations[t];
|
||||
return animations[t];
|
||||
}
|
||||
}
|
||||
|
||||
_animationEvent = 'animationend';
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of animation cancel event.
|
||||
* @returns {string} Name of animation cancel event.
|
||||
*/
|
||||
export function whichAnimationCancelEvent() {
|
||||
return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of transition end event.
|
||||
*/
|
||||
let _transitionEvent;
|
||||
|
||||
/**
|
||||
* Returns name of transition end event.
|
||||
* @returns {string} Name of transition end event.
|
||||
*/
|
||||
export function whichTransitionEvent() {
|
||||
if (_transitionEvent) {
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
const el = document.createElement('div');
|
||||
const transitions = {
|
||||
'transition': 'transitionend',
|
||||
'OTransition': 'oTransitionEnd',
|
||||
'MozTransition': 'transitionend',
|
||||
'WebkitTransition': 'webkitTransitionEnd'
|
||||
};
|
||||
for (let t in transitions) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_transitionEvent = transitions[t];
|
||||
return transitions[t];
|
||||
}
|
||||
}
|
||||
|
||||
_transitionEvent = 'transitionend';
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
parentWithAttribute: parentWithAttribute,
|
||||
parentWithClass: parentWithClass,
|
||||
parentWithTag: parentWithTag,
|
||||
addEventListener: addEventListener,
|
||||
removeEventListener: removeEventListener,
|
||||
getWindowSize: getWindowSize,
|
||||
getScreenWidth: getScreenWidth,
|
||||
whichTransitionEvent: whichTransitionEvent,
|
||||
whichAnimationEvent: whichAnimationEvent,
|
||||
whichAnimationCancelEvent: whichAnimationCancelEvent
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
||||
"use strict";
|
||||
define(['datetime', 'jQuery', 'globalize', 'material-icons'], function (datetime, $, globalize) {
|
||||
'use strict';
|
||||
|
||||
function getNode(item, folderState, selected) {
|
||||
var htmlName = getNodeInnerHtml(item);
|
||||
|
@ -7,7 +7,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
id: item.Id,
|
||||
text: htmlName,
|
||||
state: {
|
||||
opened: item.IsFolder && folderState == "open",
|
||||
opened: item.IsFolder && folderState == 'open',
|
||||
selected: selected
|
||||
},
|
||||
li_attr: {
|
||||
|
@ -17,7 +17,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
};
|
||||
if (item.IsFolder) {
|
||||
node.children = [{
|
||||
text: "Loading...",
|
||||
text: 'Loading...',
|
||||
icon: false
|
||||
}];
|
||||
node.icon = false;
|
||||
|
@ -36,30 +36,30 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
function getNodeInnerHtml(item) {
|
||||
var name = item.Name;
|
||||
if (item.Number) {
|
||||
name = item.Number + " - " + name;
|
||||
name = item.Number + ' - ' + name;
|
||||
}
|
||||
if (item.IndexNumber != null && item.Type != "Season") {
|
||||
name = item.IndexNumber + " - " + name;
|
||||
if (item.IndexNumber != null && item.Type != 'Season') {
|
||||
name = item.IndexNumber + ' - ' + name;
|
||||
}
|
||||
var htmlName = "<div class='editorNode'>";
|
||||
if (item.IsFolder) {
|
||||
htmlName += '<i class="material-icons metadataSidebarIcon">folder</i>';
|
||||
} else if (item.MediaType === "Video") {
|
||||
htmlName += '<i class="material-icons metadataSidebarIcon">movie</i>';
|
||||
} else if (item.MediaType === "Audio") {
|
||||
htmlName += '<i class="material-icons metadataSidebarIcon">audiotrack</i>';
|
||||
} else if (item.Type === "TvChannel") {
|
||||
htmlName += '<i class="material-icons metadataSidebarIcon live_tv"></i>';
|
||||
} else if (item.MediaType === "Photo") {
|
||||
htmlName += '<i class="material-icons metadataSidebarIcon">photo</i>';
|
||||
} else if (item.MediaType === "Book") {
|
||||
htmlName += '<i class="material-icons metadataSidebarIcon">book</i>';
|
||||
htmlName += '<span class="material-icons metadataSidebarIcon folder"></span>';
|
||||
} else if (item.MediaType === 'Video') {
|
||||
htmlName += '<span class="material-icons metadataSidebarIcon movie"></span>';
|
||||
} else if (item.MediaType === 'Audio') {
|
||||
htmlName += '<span class="material-icons metadataSidebarIcon audiotrack"></span>';
|
||||
} else if (item.Type === 'TvChannel') {
|
||||
htmlName += '<span class="material-icons metadataSidebarIcon live_tv"></span>';
|
||||
} else if (item.MediaType === 'Photo') {
|
||||
htmlName += '<span class="material-icons metadataSidebarIcon photo"></span>';
|
||||
} else if (item.MediaType === 'Book') {
|
||||
htmlName += '<span class="material-icons metadataSidebarIcon book"></span>';
|
||||
}
|
||||
if (item.LockData) {
|
||||
htmlName += '<i class="material-icons metadataSidebarIcon">lock</i>';
|
||||
htmlName += '<span class="material-icons metadataSidebarIcon lock"></span>';
|
||||
}
|
||||
htmlName += name;
|
||||
htmlName += "</div>";
|
||||
htmlName += '</div>';
|
||||
return htmlName;
|
||||
}
|
||||
|
||||
|
@ -69,36 +69,36 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
}).then(function (result) {
|
||||
var nodes = [];
|
||||
nodes.push({
|
||||
id: "MediaFolders",
|
||||
text: Globalize.translate("HeaderMediaFolders"),
|
||||
id: 'MediaFolders',
|
||||
text: globalize.translate('HeaderMediaFolders'),
|
||||
state: {
|
||||
opened: true
|
||||
},
|
||||
li_attr: {
|
||||
itemtype: "mediafolders",
|
||||
itemtype: 'mediafolders',
|
||||
loadedFromServer: true
|
||||
},
|
||||
icon: false
|
||||
});
|
||||
if (result.TotalRecordCount) {
|
||||
nodes.push({
|
||||
id: "livetv",
|
||||
text: Globalize.translate("HeaderLiveTV"),
|
||||
id: 'livetv',
|
||||
text: globalize.translate('HeaderLiveTV'),
|
||||
state: {
|
||||
opened: false
|
||||
},
|
||||
li_attr: {
|
||||
itemtype: "livetv"
|
||||
itemtype: 'livetv'
|
||||
},
|
||||
children: [{
|
||||
text: "Loading...",
|
||||
text: 'Loading...',
|
||||
icon: false
|
||||
}],
|
||||
icon: false
|
||||
});
|
||||
}
|
||||
callback.call(scope, nodes);
|
||||
nodesToLoad.push("MediaFolders");
|
||||
nodesToLoad.push('MediaFolders');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
AddCurrentProgram: false
|
||||
}).then(function (result) {
|
||||
var nodes = result.Items.map(function (i) {
|
||||
var state = openItems.indexOf(i.Id) == -1 ? "closed" : "open";
|
||||
var state = openItems.indexOf(i.Id) == -1 ? 'closed' : 'open';
|
||||
return getNode(i, state, false);
|
||||
});
|
||||
callback(nodes);
|
||||
|
@ -116,9 +116,9 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
}
|
||||
|
||||
function loadMediaFolders(page, scope, openItems, callback) {
|
||||
ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders")).then(function (result) {
|
||||
ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders')).then(function (result) {
|
||||
var nodes = result.Items.map(function (n) {
|
||||
var state = openItems.indexOf(n.Id) == -1 ? "closed" : "open";
|
||||
var state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open';
|
||||
return getNode(n, state, false);
|
||||
});
|
||||
callback.call(scope, nodes);
|
||||
|
@ -132,21 +132,21 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
|
||||
function loadNode(page, scope, node, openItems, selectedId, currentUser, callback) {
|
||||
var id = node.id;
|
||||
if (id == "#") {
|
||||
if (id == '#') {
|
||||
loadChildrenOfRootNode(page, scope, callback);
|
||||
return;
|
||||
}
|
||||
if (id == "livetv") {
|
||||
if (id == 'livetv') {
|
||||
loadLiveTvChannels(id, openItems, callback);
|
||||
return;
|
||||
}
|
||||
if (id == "MediaFolders") {
|
||||
if (id == 'MediaFolders') {
|
||||
loadMediaFolders(page, scope, openItems, callback);
|
||||
return;
|
||||
}
|
||||
var query = {
|
||||
ParentId: id,
|
||||
Fields: "Settings",
|
||||
Fields: 'Settings',
|
||||
IsVirtualUnaired: false,
|
||||
IsMissing: false,
|
||||
EnableTotalRecordCount: false,
|
||||
|
@ -154,12 +154,12 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
EnableUserData: false
|
||||
};
|
||||
var itemtype = node.li_attr.itemtype;
|
||||
if (itemtype != "Season" && itemtype != "Series") {
|
||||
query.SortBy = "SortName";
|
||||
if (itemtype != 'Season' && itemtype != 'Series') {
|
||||
query.SortBy = 'SortName';
|
||||
}
|
||||
ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function (result) {
|
||||
var nodes = result.Items.map(function (n) {
|
||||
var state = openItems.indexOf(n.Id) == -1 ? "closed" : "open";
|
||||
var state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open';
|
||||
return getNode(n, state, n.Id == selectedId);
|
||||
});
|
||||
callback.call(scope, nodes);
|
||||
|
@ -172,14 +172,14 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
}
|
||||
|
||||
function scrollToNode(id) {
|
||||
var elem = $("#" + id)[0];
|
||||
var elem = $('#' + id)[0];
|
||||
if (elem) {
|
||||
elem.scrollIntoView();
|
||||
}
|
||||
}
|
||||
|
||||
function initializeTree(page, currentUser, openItems, selectedId) {
|
||||
require(["jstree"], function () {
|
||||
require(['jstree'], function () {
|
||||
initializeTreeInternal(page, currentUser, openItems, selectedId);
|
||||
});
|
||||
}
|
||||
|
@ -192,41 +192,41 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
serverItemType: node.li_attr.serveritemtype,
|
||||
collectionType: node.li_attr.collectiontype
|
||||
};
|
||||
if (eventData.itemType != "livetv" && eventData.itemType != "mediafolders") {
|
||||
if (eventData.itemType != 'livetv' && eventData.itemType != 'mediafolders') {
|
||||
{
|
||||
this.dispatchEvent(new CustomEvent("itemclicked", {
|
||||
this.dispatchEvent(new CustomEvent('itemclicked', {
|
||||
detail: eventData,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
||||
document.querySelector(".editPageSidebar").classList.add("editPageSidebar-withcontent");
|
||||
document.querySelector('.editPageSidebar').classList.add('editPageSidebar-withcontent');
|
||||
} else {
|
||||
document.querySelector(".editPageSidebar").classList.remove("editPageSidebar-withcontent");
|
||||
document.querySelector('.editPageSidebar').classList.remove('editPageSidebar-withcontent');
|
||||
}
|
||||
}
|
||||
|
||||
function onNodeOpen(event, data) {
|
||||
var page = $(this).parents(".page")[0];
|
||||
var page = $(this).parents('.page')[0];
|
||||
var node = data.node;
|
||||
if (node.children && node.children) {
|
||||
loadNodesToLoad(page, node);
|
||||
}
|
||||
if (node.li_attr && node.id != "#" && !node.li_attr.loadedFromServer) {
|
||||
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
||||
node.li_attr.loadedFromServer = true;
|
||||
$.jstree.reference(".libraryTree", page).load_node(node.id, loadNodeCallback);
|
||||
$.jstree.reference('.libraryTree', page).load_node(node.id, loadNodeCallback);
|
||||
}
|
||||
}
|
||||
|
||||
function onNodeLoad(event, data) {
|
||||
var page = $(this).parents(".page")[0];
|
||||
var page = $(this).parents('.page')[0];
|
||||
var node = data.node;
|
||||
if (node.children && node.children) {
|
||||
loadNodesToLoad(page, node);
|
||||
}
|
||||
if (node.li_attr && node.id != "#" && !node.li_attr.loadedFromServer) {
|
||||
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
||||
node.li_attr.loadedFromServer = true;
|
||||
$.jstree.reference(".libraryTree", page).load_node(node.id, loadNodeCallback);
|
||||
$.jstree.reference('.libraryTree', page).load_node(node.id, loadNodeCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,18 +234,18 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
nodesToLoad = [];
|
||||
selectedNodeId = null;
|
||||
$.jstree.destroy();
|
||||
$(".libraryTree", page).jstree({
|
||||
"plugins": ["wholerow"],
|
||||
$('.libraryTree', page).jstree({
|
||||
'plugins': ['wholerow'],
|
||||
core: {
|
||||
check_callback: true,
|
||||
data: function (node, callback) {
|
||||
loadNode(page, this, node, openItems, selectedId, currentUser, callback);
|
||||
},
|
||||
themes: {
|
||||
variant: "large"
|
||||
variant: 'large'
|
||||
}
|
||||
}
|
||||
}).off("select_node.jstree", onNodeSelect).on("select_node.jstree", onNodeSelect).off("open_node.jstree", onNodeOpen).on("open_node.jstree", onNodeOpen).off("load_node.jstree", onNodeLoad).on("load_node.jstree", onNodeLoad);
|
||||
}).off('select_node.jstree', onNodeSelect).on('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).on('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad).on('load_node.jstree', onNodeLoad);
|
||||
}
|
||||
|
||||
function loadNodesToLoad(page, node) {
|
||||
|
@ -256,7 +256,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
nodesToLoad = nodesToLoad.filter(function (n) {
|
||||
return n != child;
|
||||
});
|
||||
$.jstree.reference(".libraryTree", page).load_node(child, loadNodeCallback);
|
||||
$.jstree.reference('.libraryTree', page).load_node(child, loadNodeCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,14 +270,14 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
}
|
||||
|
||||
function updateEditorNode(page, item) {
|
||||
var elem = $("#" + item.Id + ">a", page)[0];
|
||||
var elem = $('#' + item.Id + '>a', page)[0];
|
||||
if (elem == null) {
|
||||
return;
|
||||
}
|
||||
$(".editorNode", elem).remove();
|
||||
$('.editorNode', elem).remove();
|
||||
$(elem).append(getNodeInnerHtml(item));
|
||||
if (item.IsFolder) {
|
||||
var tree = jQuery.jstree._reference(".libraryTree");
|
||||
var tree = jQuery.jstree._reference('.libraryTree');
|
||||
var currentNode = tree._get_node(null, false);
|
||||
tree.refresh(currentNode);
|
||||
}
|
||||
|
@ -292,15 +292,15 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
return itemId;
|
||||
}
|
||||
var url = window.location.hash || window.location.href;
|
||||
return getParameterByName("id", url);
|
||||
return getParameterByName('id', url);
|
||||
}
|
||||
var nodesToLoad = [];
|
||||
var selectedNodeId;
|
||||
$(document).on("itemsaved", ".metadataEditorPage", function (e, item) {
|
||||
$(document).on('itemsaved', '.metadataEditorPage', function (e, item) {
|
||||
updateEditorNode(this, item);
|
||||
}).on("pagebeforeshow", ".metadataEditorPage", function () {
|
||||
require(["css!assets/css/metadataeditor.css"]);
|
||||
}).on("pagebeforeshow", ".metadataEditorPage", function () {
|
||||
}).on('pagebeforeshow', '.metadataEditorPage', function () {
|
||||
require(['css!assets/css/metadataeditor.css']);
|
||||
}).on('pagebeforeshow', '.metadataEditorPage', function () {
|
||||
var page = this;
|
||||
Dashboard.getCurrentUser().then(function (user) {
|
||||
var id = getCurrentItemId();
|
||||
|
@ -315,9 +315,9 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
|||
initializeTree(page, user, []);
|
||||
}
|
||||
});
|
||||
}).on("pagebeforehide", ".metadataEditorPage", function () {
|
||||
}).on('pagebeforehide', '.metadataEditorPage', function () {
|
||||
var page = this;
|
||||
$(".libraryTree", page).off("select_node.jstree", onNodeSelect).off("open_node.jstree", onNodeOpen).off("load_node.jstree", onNodeLoad);
|
||||
$('.libraryTree', page).off('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad);
|
||||
});
|
||||
var itemId;
|
||||
window.MetadataEditor = {
|
||||
|
|
13
src/scripts/filesystem.js
Normal file
13
src/scripts/filesystem.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export function fileExists(path) {
|
||||
if (window.NativeShell && window.NativeShell.FileSystem) {
|
||||
return window.NativeShell.FileSystem.fileExists(path);
|
||||
}
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
export function directoryExists(path) {
|
||||
if (window.NativeShell && window.NativeShell.FileSystem) {
|
||||
return window.NativeShell.FileSystem.directoryExists(path);
|
||||
}
|
||||
return Promise.reject();
|
||||
}
|
410
src/scripts/gamepadtokey.js
Normal file
410
src/scripts/gamepadtokey.js
Normal file
|
@ -0,0 +1,410 @@
|
|||
// # The MIT License (MIT)
|
||||
// #
|
||||
// # Copyright (c) 2016 Microsoft. All rights reserved.
|
||||
// #
|
||||
// # Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// # of this software and associated documentation files (the "Software"), to deal
|
||||
// # in the Software without restriction, including without limitation the rights
|
||||
// # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// # copies of the Software, and to permit persons to whom the Software is
|
||||
// # furnished to do so, subject to the following conditions:
|
||||
// #
|
||||
// # The above copyright notice and this permission notice shall be included in
|
||||
// # all copies or substantial portions of the Software.
|
||||
// #
|
||||
// # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// # THE SOFTWARE.
|
||||
require(['apphost'], function (appHost) {
|
||||
'use strict';
|
||||
|
||||
var _GAMEPAD_A_BUTTON_INDEX = 0;
|
||||
var _GAMEPAD_B_BUTTON_INDEX = 1;
|
||||
var _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12;
|
||||
var _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13;
|
||||
var _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14;
|
||||
var _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15;
|
||||
var _GAMEPAD_A_KEY = 'GamepadA';
|
||||
var _GAMEPAD_B_KEY = 'GamepadB';
|
||||
var _GAMEPAD_DPAD_UP_KEY = 'GamepadDPadUp';
|
||||
var _GAMEPAD_DPAD_DOWN_KEY = 'GamepadDPadDown';
|
||||
var _GAMEPAD_DPAD_LEFT_KEY = 'GamepadDPadLeft';
|
||||
var _GAMEPAD_DPAD_RIGHT_KEY = 'GamepadDPadRight';
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = 'GamepadLeftThumbStickUp';
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = 'GamepadLeftThumbStickDown';
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = 'GamepadLeftThumbStickLeft';
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = 'GamepadLeftThumbStickRight';
|
||||
var _GAMEPAD_A_KEYCODE = 0;
|
||||
var _GAMEPAD_B_KEYCODE = 27;
|
||||
var _GAMEPAD_DPAD_UP_KEYCODE = 38;
|
||||
var _GAMEPAD_DPAD_DOWN_KEYCODE = 40;
|
||||
var _GAMEPAD_DPAD_LEFT_KEYCODE = 37;
|
||||
var _GAMEPAD_DPAD_RIGHT_KEYCODE = 39;
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE = 38;
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE = 40;
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE = 37;
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE = 39;
|
||||
var _THUMB_STICK_THRESHOLD = 0.75;
|
||||
|
||||
var _leftThumbstickUpPressed = false;
|
||||
var _leftThumbstickDownPressed = false;
|
||||
var _leftThumbstickLeftPressed = false;
|
||||
var _leftThumbstickRightPressed = false;
|
||||
var _dPadUpPressed = false;
|
||||
var _dPadDownPressed = false;
|
||||
var _dPadLeftPressed = false;
|
||||
var _dPadRightPressed = false;
|
||||
var _gamepadAPressed = false;
|
||||
var _gamepadBPressed = false;
|
||||
|
||||
// The set of buttons on the gamepad we listen for.
|
||||
var ProcessedButtons = [
|
||||
_GAMEPAD_DPAD_UP_BUTTON_INDEX,
|
||||
_GAMEPAD_DPAD_DOWN_BUTTON_INDEX,
|
||||
_GAMEPAD_DPAD_LEFT_BUTTON_INDEX,
|
||||
_GAMEPAD_DPAD_RIGHT_BUTTON_INDEX,
|
||||
_GAMEPAD_A_BUTTON_INDEX,
|
||||
_GAMEPAD_B_BUTTON_INDEX
|
||||
];
|
||||
|
||||
var _ButtonPressedState = {};
|
||||
_ButtonPressedState.getgamepadA = function () {
|
||||
return _gamepadAPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setgamepadA = function (newPressedState) {
|
||||
raiseKeyEvent(_gamepadAPressed, newPressedState, _GAMEPAD_A_KEY, _GAMEPAD_A_KEYCODE, false, true);
|
||||
_gamepadAPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getgamepadB = function () {
|
||||
return _gamepadBPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setgamepadB = function (newPressedState) {
|
||||
raiseKeyEvent(_gamepadBPressed, newPressedState, _GAMEPAD_B_KEY, _GAMEPAD_B_KEYCODE);
|
||||
_gamepadBPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getleftThumbstickUp = function () {
|
||||
return _leftThumbstickUpPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setleftThumbstickUp = function (newPressedState) {
|
||||
raiseKeyEvent(_leftThumbstickUpPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_UP_KEY, _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE, true);
|
||||
_leftThumbstickUpPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getleftThumbstickDown = function () {
|
||||
return _leftThumbstickDownPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setleftThumbstickDown = function (newPressedState) {
|
||||
raiseKeyEvent(_leftThumbstickDownPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE, true);
|
||||
_leftThumbstickDownPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getleftThumbstickLeft = function () {
|
||||
return _leftThumbstickLeftPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setleftThumbstickLeft = function (newPressedState) {
|
||||
raiseKeyEvent(_leftThumbstickLeftPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE, true);
|
||||
_leftThumbstickLeftPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getleftThumbstickRight = function () {
|
||||
return _leftThumbstickRightPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setleftThumbstickRight = function (newPressedState) {
|
||||
raiseKeyEvent(_leftThumbstickRightPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE, true);
|
||||
_leftThumbstickRightPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getdPadUp = function () {
|
||||
return _dPadUpPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setdPadUp = function (newPressedState) {
|
||||
raiseKeyEvent(_dPadUpPressed, newPressedState, _GAMEPAD_DPAD_UP_KEY, _GAMEPAD_DPAD_UP_KEYCODE, true);
|
||||
_dPadUpPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getdPadDown = function () {
|
||||
return _dPadDownPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setdPadDown = function (newPressedState) {
|
||||
raiseKeyEvent(_dPadDownPressed, newPressedState, _GAMEPAD_DPAD_DOWN_KEY, _GAMEPAD_DPAD_DOWN_KEYCODE, true);
|
||||
_dPadDownPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getdPadLeft = function () {
|
||||
return _dPadLeftPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setdPadLeft = function (newPressedState) {
|
||||
raiseKeyEvent(_dPadLeftPressed, newPressedState, _GAMEPAD_DPAD_LEFT_KEY, _GAMEPAD_DPAD_LEFT_KEYCODE, true);
|
||||
_dPadLeftPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getdPadRight = function () {
|
||||
return _dPadRightPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setdPadRight = function (newPressedState) {
|
||||
raiseKeyEvent(_dPadRightPressed, newPressedState, _GAMEPAD_DPAD_RIGHT_KEY, _GAMEPAD_DPAD_RIGHT_KEYCODE, true);
|
||||
_dPadRightPressed = newPressedState;
|
||||
};
|
||||
|
||||
var times = {};
|
||||
|
||||
function throttle(key) {
|
||||
var time = times[key] || 0;
|
||||
var now = new Date().getTime();
|
||||
|
||||
if ((now - time) >= 200) {
|
||||
//times[key] = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function resetThrottle(key) {
|
||||
times[key] = new Date().getTime();
|
||||
}
|
||||
|
||||
var isElectron = navigator.userAgent.toLowerCase().indexOf('electron') !== -1;
|
||||
function allowInput() {
|
||||
|
||||
// This would be nice but always seems to return true with electron
|
||||
if (!isElectron && document.hidden) { /* eslint-disable-line compat/compat */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (appHost.getWindowState() === 'Minimized') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function raiseEvent(name, key, keyCode) {
|
||||
|
||||
if (!allowInput()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent(name, true, true);
|
||||
event.key = key;
|
||||
event.keyCode = keyCode;
|
||||
(document.activeElement || document.body).dispatchEvent(event);
|
||||
}
|
||||
|
||||
function clickElement(elem) {
|
||||
|
||||
if (!allowInput()) {
|
||||
return;
|
||||
}
|
||||
|
||||
elem.click();
|
||||
}
|
||||
|
||||
function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRepeatKeyDown, clickonKeyUp) {
|
||||
|
||||
// No-op if oldPressedState === newPressedState
|
||||
if (newPressedState === true) {
|
||||
|
||||
// button down
|
||||
var fire = false;
|
||||
|
||||
// always fire if this is the initial down press
|
||||
if (oldPressedState === false) {
|
||||
fire = true;
|
||||
resetThrottle(key);
|
||||
} else if (enableRepeatKeyDown) {
|
||||
fire = throttle(key);
|
||||
}
|
||||
|
||||
if (fire && keyCode) {
|
||||
raiseEvent('keydown', key, keyCode);
|
||||
}
|
||||
|
||||
} else if (newPressedState === false && oldPressedState === true) {
|
||||
|
||||
resetThrottle(key);
|
||||
|
||||
// button up
|
||||
if (keyCode) {
|
||||
raiseEvent('keyup', key, keyCode);
|
||||
}
|
||||
if (clickonKeyUp) {
|
||||
clickElement(document.activeElement || window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var inputLoopTimer;
|
||||
function runInputLoop() {
|
||||
// Get the latest gamepad state.
|
||||
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
|
||||
for (var i = 0, len = gamepads.length; i < len; i++) {
|
||||
var gamepad = gamepads[i];
|
||||
if (!gamepad) {
|
||||
continue;
|
||||
}
|
||||
// Iterate through the axes
|
||||
var axes = gamepad.axes;
|
||||
var leftStickX = axes[0];
|
||||
var leftStickY = axes[1];
|
||||
if (leftStickX > _THUMB_STICK_THRESHOLD) { // Right
|
||||
_ButtonPressedState.setleftThumbstickRight(true);
|
||||
} else if (leftStickX < -_THUMB_STICK_THRESHOLD) { // Left
|
||||
_ButtonPressedState.setleftThumbstickLeft(true);
|
||||
} else if (leftStickY < -_THUMB_STICK_THRESHOLD) { // Up
|
||||
_ButtonPressedState.setleftThumbstickUp(true);
|
||||
} else if (leftStickY > _THUMB_STICK_THRESHOLD) { // Down
|
||||
_ButtonPressedState.setleftThumbstickDown(true);
|
||||
} else {
|
||||
_ButtonPressedState.setleftThumbstickLeft(false);
|
||||
_ButtonPressedState.setleftThumbstickRight(false);
|
||||
_ButtonPressedState.setleftThumbstickUp(false);
|
||||
_ButtonPressedState.setleftThumbstickDown(false);
|
||||
}
|
||||
// Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed.
|
||||
var buttons = gamepad.buttons;
|
||||
for (var j = 0, len = buttons.length; j < len; j++) {
|
||||
if (ProcessedButtons.indexOf(j) !== -1) {
|
||||
if (buttons[j].pressed) {
|
||||
switch (j) {
|
||||
case _GAMEPAD_DPAD_UP_BUTTON_INDEX:
|
||||
_ButtonPressedState.setdPadUp(true);
|
||||
break;
|
||||
case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX:
|
||||
_ButtonPressedState.setdPadDown(true);
|
||||
break;
|
||||
case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX:
|
||||
_ButtonPressedState.setdPadLeft(true);
|
||||
break;
|
||||
case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX:
|
||||
_ButtonPressedState.setdPadRight(true);
|
||||
break;
|
||||
case _GAMEPAD_A_BUTTON_INDEX:
|
||||
_ButtonPressedState.setgamepadA(true);
|
||||
break;
|
||||
case _GAMEPAD_B_BUTTON_INDEX:
|
||||
_ButtonPressedState.setgamepadB(true);
|
||||
break;
|
||||
default:
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (j) {
|
||||
case _GAMEPAD_DPAD_UP_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getdPadUp()) {
|
||||
_ButtonPressedState.setdPadUp(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getdPadDown()) {
|
||||
_ButtonPressedState.setdPadDown(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getdPadLeft()) {
|
||||
_ButtonPressedState.setdPadLeft(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getdPadRight()) {
|
||||
_ButtonPressedState.setdPadRight(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_A_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getgamepadA()) {
|
||||
_ButtonPressedState.setgamepadA(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_B_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getgamepadB()) {
|
||||
_ButtonPressedState.setgamepadB(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Schedule the next one
|
||||
inputLoopTimer = requestAnimationFrame(runInputLoop);
|
||||
}
|
||||
|
||||
function startInputLoop() {
|
||||
if (!inputLoopTimer) {
|
||||
runInputLoop();
|
||||
}
|
||||
}
|
||||
|
||||
function stopInputLoop() {
|
||||
cancelAnimationFrame(inputLoopTimer);
|
||||
inputLoopTimer = undefined;
|
||||
}
|
||||
|
||||
function isGamepadConnected() {
|
||||
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
|
||||
for (var i = 0, len = gamepads.length; i < len; i++) {
|
||||
var gamepad = gamepads[i];
|
||||
if (gamepad && gamepad.connected) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function onFocusOrGamepadAttach(e) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (isGamepadConnected() && document.hasFocus()) {
|
||||
console.log('Gamepad connected! Starting input loop');
|
||||
startInputLoop();
|
||||
}
|
||||
}
|
||||
|
||||
function onFocusOrGamepadDetach(e) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (!isGamepadConnected() || !document.hasFocus()) {
|
||||
console.log('Gamepad disconnected! No other gamepads are connected, stopping input loop');
|
||||
stopInputLoop();
|
||||
} else {
|
||||
console.log('Gamepad disconnected! There are gamepads still connected.');
|
||||
}
|
||||
}
|
||||
|
||||
// Event listeners for any change in gamepads' state.
|
||||
window.addEventListener('gamepaddisconnected', onFocusOrGamepadDetach);
|
||||
window.addEventListener('gamepadconnected', onFocusOrGamepadAttach);
|
||||
window.addEventListener('blur', onFocusOrGamepadDetach);
|
||||
window.addEventListener('focus', onFocusOrGamepadAttach);
|
||||
|
||||
onFocusOrGamepadAttach();
|
||||
|
||||
// The gamepadInputEmulation is a string property that exists in JavaScript UWAs and in WebViews in UWAs.
|
||||
// It won't exist in Win8.1 style apps or browsers.
|
||||
if (window.navigator && typeof window.navigator.gamepadInputEmulation === 'string') {
|
||||
// We want the gamepad to provide gamepad VK keyboard events rather than moving a
|
||||
// mouse like cursor. Set to "keyboard", the gamepad will provide such keyboard events
|
||||
// and provide input to the DOM navigator.getGamepads API.
|
||||
window.navigator.gamepadInputEmulation = 'gamepad';
|
||||
}
|
||||
|
||||
});
|
|
@ -3,72 +3,73 @@
|
|||
import browser from 'browser';
|
||||
|
||||
export function getDeviceIcon(device) {
|
||||
var baseUrl = "assets/img/devices/";
|
||||
var baseUrl = 'assets/img/devices/';
|
||||
switch (device.AppName || device.Client) {
|
||||
case "Samsung Smart TV":
|
||||
return baseUrl + "samsung.svg";
|
||||
case "Xbox One":
|
||||
return baseUrl + "xbox.svg";
|
||||
case "Sony PS4":
|
||||
return baseUrl + "playstation.svg";
|
||||
case "Kodi":
|
||||
return baseUrl + "kodi.svg";
|
||||
case "Jellyfin Android":
|
||||
return baseUrl + "android.svg";
|
||||
case "Jellyfin Web":
|
||||
case 'Samsung Smart TV':
|
||||
return baseUrl + 'samsung.svg';
|
||||
case 'Xbox One':
|
||||
return baseUrl + 'xbox.svg';
|
||||
case 'Sony PS4':
|
||||
return baseUrl + 'playstation.svg';
|
||||
case 'Kodi':
|
||||
return baseUrl + 'kodi.svg';
|
||||
case 'Jellyfin Android':
|
||||
case 'Android TV':
|
||||
return baseUrl + 'android.svg';
|
||||
case 'Jellyfin Web':
|
||||
switch (device.Name || device.DeviceName) {
|
||||
case "Opera":
|
||||
case "Opera TV":
|
||||
case "Opera Android":
|
||||
return baseUrl + "opera.svg";
|
||||
case "Chrome":
|
||||
case "Chrome Android":
|
||||
return baseUrl + "chrome.svg";
|
||||
case "Firefox":
|
||||
case "Firefox Android":
|
||||
return baseUrl + "firefox.svg";
|
||||
case "Safari":
|
||||
case "Safari iPad":
|
||||
case "Safari iPhone":
|
||||
return baseUrl + "safari.svg";
|
||||
case "Edge":
|
||||
return baseUrl + "edge.svg";
|
||||
case "Internet Explorer":
|
||||
return baseUrl + "msie.svg";
|
||||
case 'Opera':
|
||||
case 'Opera TV':
|
||||
case 'Opera Android':
|
||||
return baseUrl + 'opera.svg';
|
||||
case 'Chrome':
|
||||
case 'Chrome Android':
|
||||
return baseUrl + 'chrome.svg';
|
||||
case 'Firefox':
|
||||
case 'Firefox Android':
|
||||
return baseUrl + 'firefox.svg';
|
||||
case 'Safari':
|
||||
case 'Safari iPad':
|
||||
case 'Safari iPhone':
|
||||
return baseUrl + 'safari.svg';
|
||||
case 'Edge':
|
||||
return baseUrl + 'edge.svg';
|
||||
case 'Internet Explorer':
|
||||
return baseUrl + 'msie.svg';
|
||||
default:
|
||||
return baseUrl + "html5.svg";
|
||||
return baseUrl + 'html5.svg';
|
||||
}
|
||||
default:
|
||||
return baseUrl + "other.svg";
|
||||
return baseUrl + 'other.svg';
|
||||
}
|
||||
}
|
||||
|
||||
export function getLibraryIcon(library) {
|
||||
switch (library) {
|
||||
case "movies":
|
||||
return "video_library";
|
||||
case "music":
|
||||
return "library_music";
|
||||
case "photos":
|
||||
return "photo_library";
|
||||
case "livetv":
|
||||
return "live_tv";
|
||||
case "tvshows":
|
||||
return "tv";
|
||||
case "trailers":
|
||||
return "local_movies";
|
||||
case "homevideos":
|
||||
return "photo_library";
|
||||
case "musicvideos":
|
||||
return "music_video";
|
||||
case "books":
|
||||
return "library_books";
|
||||
case "channels":
|
||||
return "videocam";
|
||||
case "playlists":
|
||||
return "view_list";
|
||||
case 'movies':
|
||||
return 'video_library';
|
||||
case 'music':
|
||||
return 'library_music';
|
||||
case 'photos':
|
||||
return 'photo_library';
|
||||
case 'livetv':
|
||||
return 'live_tv';
|
||||
case 'tvshows':
|
||||
return 'tv';
|
||||
case 'trailers':
|
||||
return 'local_movies';
|
||||
case 'homevideos':
|
||||
return 'photo_library';
|
||||
case 'musicvideos':
|
||||
return 'music_video';
|
||||
case 'books':
|
||||
return 'library_books';
|
||||
case 'channels':
|
||||
return 'videocam';
|
||||
case 'playlists':
|
||||
return 'view_list';
|
||||
default:
|
||||
return "folder";
|
||||
return 'folder';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,44 +1,49 @@
|
|||
define(['playbackManager', 'focusManager', 'appRouter', 'dom', 'apphost'], function (playbackManager, focusManager, appRouter, dom, appHost) {
|
||||
'use strict';
|
||||
import playbackManager from 'playbackManager';
|
||||
import focusManager from 'focusManager';
|
||||
import appRouter from 'appRouter';
|
||||
import dom from 'dom';
|
||||
import appHost from 'apphost';
|
||||
|
||||
var lastInputTime = new Date().getTime();
|
||||
/* eslint-disable indent */
|
||||
|
||||
function notify() {
|
||||
let lastInputTime = new Date().getTime();
|
||||
|
||||
export function notify() {
|
||||
lastInputTime = new Date().getTime();
|
||||
handleCommand('unknown');
|
||||
}
|
||||
|
||||
function notifyMouseMove() {
|
||||
export function notifyMouseMove() {
|
||||
lastInputTime = new Date().getTime();
|
||||
}
|
||||
|
||||
function idleTime() {
|
||||
export function idleTime() {
|
||||
return new Date().getTime() - lastInputTime;
|
||||
}
|
||||
|
||||
function select(sourceElement) {
|
||||
export function select(sourceElement) {
|
||||
sourceElement.click();
|
||||
}
|
||||
|
||||
var eventListenerCount = 0;
|
||||
function on(scope, fn) {
|
||||
let eventListenerCount = 0;
|
||||
export function on(scope, fn) {
|
||||
eventListenerCount++;
|
||||
dom.addEventListener(scope, 'command', fn, {});
|
||||
}
|
||||
|
||||
function off(scope, fn) {
|
||||
export function off(scope, fn) {
|
||||
if (eventListenerCount) {
|
||||
eventListenerCount--;
|
||||
}
|
||||
dom.removeEventListener(scope, 'command', fn, {});
|
||||
}
|
||||
|
||||
var commandTimes = {};
|
||||
let commandTimes = {};
|
||||
|
||||
function checkCommandTime(command) {
|
||||
|
||||
var last = commandTimes[command] || 0;
|
||||
var now = new Date().getTime();
|
||||
const last = commandTimes[command] || 0;
|
||||
const now = new Date().getTime();
|
||||
|
||||
if ((now - last) < 1000) {
|
||||
return false;
|
||||
|
@ -48,11 +53,11 @@ define(['playbackManager', 'focusManager', 'appRouter', 'dom', 'apphost'], funct
|
|||
return true;
|
||||
}
|
||||
|
||||
function handleCommand(name, options) {
|
||||
export function handleCommand(commandName, options) {
|
||||
|
||||
lastInputTime = new Date().getTime();
|
||||
|
||||
var sourceElement = (options ? options.sourceElement : null);
|
||||
let sourceElement = (options ? options.sourceElement : null);
|
||||
|
||||
if (sourceElement) {
|
||||
sourceElement = focusManager.focusableParent(sourceElement);
|
||||
|
@ -61,7 +66,7 @@ define(['playbackManager', 'focusManager', 'appRouter', 'dom', 'apphost'], funct
|
|||
if (!sourceElement) {
|
||||
sourceElement = document.activeElement || window;
|
||||
|
||||
var dlg = document.querySelector('.dialogContainer .dialog.opened');
|
||||
const dlg = document.querySelector('.dialogContainer .dialog.opened');
|
||||
|
||||
if (dlg && (!sourceElement || !dlg.contains(sourceElement))) {
|
||||
sourceElement = dlg;
|
||||
|
@ -69,183 +74,182 @@ define(['playbackManager', 'focusManager', 'appRouter', 'dom', 'apphost'], funct
|
|||
}
|
||||
|
||||
if (eventListenerCount) {
|
||||
var customEvent = new CustomEvent("command", {
|
||||
const customEvent = new CustomEvent('command', {
|
||||
detail: {
|
||||
command: name
|
||||
command: commandName
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
|
||||
var eventResult = sourceElement.dispatchEvent(customEvent);
|
||||
const eventResult = sourceElement.dispatchEvent(customEvent);
|
||||
if (!eventResult) {
|
||||
// event cancelled
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (name) {
|
||||
case 'up':
|
||||
const keyActions = (command) => ({
|
||||
'up': () => {
|
||||
focusManager.moveUp(sourceElement);
|
||||
break;
|
||||
case 'down':
|
||||
},
|
||||
'down': () => {
|
||||
focusManager.moveDown(sourceElement);
|
||||
break;
|
||||
case 'left':
|
||||
},
|
||||
'left': () => {
|
||||
focusManager.moveLeft(sourceElement);
|
||||
break;
|
||||
case 'right':
|
||||
},
|
||||
'right': () => {
|
||||
focusManager.moveRight(sourceElement);
|
||||
break;
|
||||
case 'home':
|
||||
},
|
||||
'home': () => {
|
||||
appRouter.goHome();
|
||||
break;
|
||||
case 'settings':
|
||||
},
|
||||
'settings': () => {
|
||||
appRouter.showSettings();
|
||||
break;
|
||||
case 'back':
|
||||
},
|
||||
'back': () => {
|
||||
if (appRouter.canGoBack()) {
|
||||
appRouter.back();
|
||||
} else if (appHost.supports('exit')) {
|
||||
appHost.exit();
|
||||
}
|
||||
break;
|
||||
case 'forward':
|
||||
break;
|
||||
case 'select':
|
||||
},
|
||||
'select': () => {
|
||||
select(sourceElement);
|
||||
break;
|
||||
case 'pageup':
|
||||
break;
|
||||
case 'pagedown':
|
||||
break;
|
||||
case 'end':
|
||||
break;
|
||||
case 'menu':
|
||||
break;
|
||||
case 'info':
|
||||
break;
|
||||
case 'nextchapter':
|
||||
},
|
||||
'nextchapter': () => {
|
||||
playbackManager.nextChapter();
|
||||
break;
|
||||
case 'next':
|
||||
case 'nexttrack':
|
||||
},
|
||||
'next': () => {
|
||||
playbackManager.nextTrack();
|
||||
break;
|
||||
case 'previous':
|
||||
case 'previoustrack':
|
||||
},
|
||||
'nexttrack': () => {
|
||||
playbackManager.nextTrack();
|
||||
},
|
||||
'previous': () => {
|
||||
playbackManager.previousTrack();
|
||||
break;
|
||||
case 'previouschapter':
|
||||
},
|
||||
'previoustrack': () => {
|
||||
playbackManager.previousTrack();
|
||||
},
|
||||
'previouschapter': () => {
|
||||
playbackManager.previousChapter();
|
||||
break;
|
||||
case 'guide':
|
||||
},
|
||||
'guide': () => {
|
||||
appRouter.showGuide();
|
||||
break;
|
||||
case 'recordedtv':
|
||||
},
|
||||
'recordedtv': () => {
|
||||
appRouter.showRecordedTV();
|
||||
break;
|
||||
case 'record':
|
||||
break;
|
||||
case 'livetv':
|
||||
},
|
||||
'livetv': () => {
|
||||
appRouter.showLiveTV();
|
||||
break;
|
||||
case 'mute':
|
||||
},
|
||||
'mute': () => {
|
||||
playbackManager.setMute(true);
|
||||
break;
|
||||
case 'unmute':
|
||||
},
|
||||
'unmute': () => {
|
||||
playbackManager.setMute(false);
|
||||
break;
|
||||
case 'togglemute':
|
||||
},
|
||||
'togglemute': () => {
|
||||
playbackManager.toggleMute();
|
||||
break;
|
||||
case 'channelup':
|
||||
},
|
||||
'channelup': () => {
|
||||
playbackManager.channelUp();
|
||||
break;
|
||||
case 'channeldown':
|
||||
},
|
||||
'channeldown': () => {
|
||||
playbackManager.channelDown();
|
||||
break;
|
||||
case 'volumedown':
|
||||
},
|
||||
'volumedown': () => {
|
||||
playbackManager.volumeDown();
|
||||
break;
|
||||
case 'volumeup':
|
||||
},
|
||||
'volumeup': () => {
|
||||
playbackManager.volumeUp();
|
||||
break;
|
||||
case 'play':
|
||||
},
|
||||
'play': () => {
|
||||
playbackManager.unpause();
|
||||
break;
|
||||
case 'pause':
|
||||
},
|
||||
'pause': () => {
|
||||
playbackManager.pause();
|
||||
break;
|
||||
case 'playpause':
|
||||
},
|
||||
'playpause': () => {
|
||||
playbackManager.playPause();
|
||||
break;
|
||||
case 'stop':
|
||||
},
|
||||
'stop': () => {
|
||||
if (checkCommandTime('stop')) {
|
||||
playbackManager.stop();
|
||||
}
|
||||
break;
|
||||
case 'changezoom':
|
||||
},
|
||||
'changezoom': () => {
|
||||
playbackManager.toggleAspectRatio();
|
||||
break;
|
||||
case 'changeaudiotrack':
|
||||
},
|
||||
'changeaudiotrack': () => {
|
||||
playbackManager.changeAudioStream();
|
||||
break;
|
||||
case 'changesubtitletrack':
|
||||
},
|
||||
'changesubtitletrack': () => {
|
||||
playbackManager.changeSubtitleStream();
|
||||
break;
|
||||
case 'search':
|
||||
},
|
||||
'search': () => {
|
||||
appRouter.showSearch();
|
||||
break;
|
||||
case 'favorites':
|
||||
},
|
||||
'favorites': () => {
|
||||
appRouter.showFavorites();
|
||||
break;
|
||||
case 'fastforward':
|
||||
},
|
||||
'fastforward': () => {
|
||||
playbackManager.fastForward();
|
||||
break;
|
||||
case 'rewind':
|
||||
},
|
||||
'rewind': () => {
|
||||
playbackManager.rewind();
|
||||
break;
|
||||
case 'togglefullscreen':
|
||||
},
|
||||
'togglefullscreen': () => {
|
||||
playbackManager.toggleFullscreen();
|
||||
break;
|
||||
case 'disabledisplaymirror':
|
||||
},
|
||||
'disabledisplaymirror': () => {
|
||||
playbackManager.enableDisplayMirroring(false);
|
||||
break;
|
||||
case 'enabledisplaymirror':
|
||||
},
|
||||
'enabledisplaymirror': () => {
|
||||
playbackManager.enableDisplayMirroring(true);
|
||||
break;
|
||||
case 'toggledisplaymirror':
|
||||
},
|
||||
'toggledisplaymirror': () => {
|
||||
playbackManager.toggleDisplayMirroring();
|
||||
break;
|
||||
case 'nowplaying':
|
||||
},
|
||||
'nowplaying': () => {
|
||||
appRouter.showNowPlaying();
|
||||
break;
|
||||
case 'repeatnone':
|
||||
},
|
||||
'repeatnone': () => {
|
||||
playbackManager.setRepeatMode('RepeatNone');
|
||||
break;
|
||||
case 'repeatall':
|
||||
},
|
||||
'repeatall': () => {
|
||||
playbackManager.setRepeatMode('RepeatAll');
|
||||
break;
|
||||
case 'repeatone':
|
||||
},
|
||||
'repeatone': () => {
|
||||
playbackManager.setRepeatMode('RepeatOne');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})[command];
|
||||
|
||||
const action = keyActions(commandName);
|
||||
if (action !== undefined) {
|
||||
action.call();
|
||||
} else {
|
||||
console.debug(`inputManager: tried to process command with no action assigned: ${commandName}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Alias for backward compatibility
|
||||
export const trigger = handleCommand;
|
||||
|
||||
dom.addEventListener(document, 'click', notify, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
return {
|
||||
trigger: handleCommand,
|
||||
handle: handleCommand,
|
||||
notify: notify,
|
||||
notifyMouseMove: notifyMouseMove,
|
||||
idleTime: idleTime,
|
||||
on: on,
|
||||
off: off
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
trigger: handleCommand,
|
||||
handle: handleCommand,
|
||||
notify: notify,
|
||||
notifyMouseMove: notifyMouseMove,
|
||||
idleTime: idleTime,
|
||||
on: on,
|
||||
off: off
|
||||
};
|
||||
|
|
|
@ -1,105 +1,105 @@
|
|||
define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryBrowser", "emby-itemscontainer", "emby-button"], function (connectionManager, listView, cardBuilder, imageLoader, libraryBrowser) {
|
||||
"use strict";
|
||||
define(['connectionManager', 'listView', 'cardBuilder', 'imageLoader', 'libraryBrowser', 'globalize', 'emby-itemscontainer', 'emby-button'], function (connectionManager, listView, cardBuilder, imageLoader, libraryBrowser, globalize) {
|
||||
'use strict';
|
||||
|
||||
function renderItems(page, item) {
|
||||
var sections = [];
|
||||
|
||||
if (item.ArtistCount) {
|
||||
sections.push({
|
||||
name: Globalize.translate("TabArtists"),
|
||||
type: "MusicArtist"
|
||||
name: globalize.translate('TabArtists'),
|
||||
type: 'MusicArtist'
|
||||
});
|
||||
}
|
||||
|
||||
if (item.ProgramCount && "Person" == item.Type) {
|
||||
if (item.ProgramCount && 'Person' == item.Type) {
|
||||
sections.push({
|
||||
name: Globalize.translate("HeaderUpcomingOnTV"),
|
||||
type: "Program"
|
||||
name: globalize.translate('HeaderUpcomingOnTV'),
|
||||
type: 'Program'
|
||||
});
|
||||
}
|
||||
|
||||
if (item.MovieCount) {
|
||||
sections.push({
|
||||
name: Globalize.translate("TabMovies"),
|
||||
type: "Movie"
|
||||
name: globalize.translate('TabMovies'),
|
||||
type: 'Movie'
|
||||
});
|
||||
}
|
||||
|
||||
if (item.SeriesCount) {
|
||||
sections.push({
|
||||
name: Globalize.translate("TabShows"),
|
||||
type: "Series"
|
||||
name: globalize.translate('TabShows'),
|
||||
type: 'Series'
|
||||
});
|
||||
}
|
||||
|
||||
if (item.EpisodeCount) {
|
||||
sections.push({
|
||||
name: Globalize.translate("TabEpisodes"),
|
||||
type: "Episode"
|
||||
name: globalize.translate('TabEpisodes'),
|
||||
type: 'Episode'
|
||||
});
|
||||
}
|
||||
|
||||
if (item.TrailerCount) {
|
||||
sections.push({
|
||||
name: Globalize.translate("TabTrailers"),
|
||||
type: "Trailer"
|
||||
name: globalize.translate('TabTrailers'),
|
||||
type: 'Trailer'
|
||||
});
|
||||
}
|
||||
|
||||
if (item.AlbumCount) {
|
||||
sections.push({
|
||||
name: Globalize.translate("TabAlbums"),
|
||||
type: "MusicAlbum"
|
||||
name: globalize.translate('TabAlbums'),
|
||||
type: 'MusicAlbum'
|
||||
});
|
||||
}
|
||||
|
||||
if (item.MusicVideoCount) {
|
||||
sections.push({
|
||||
name: Globalize.translate("TabMusicVideos"),
|
||||
type: "MusicVideo"
|
||||
name: globalize.translate('TabMusicVideos'),
|
||||
type: 'MusicVideo'
|
||||
});
|
||||
}
|
||||
|
||||
var elem = page.querySelector("#childrenContent");
|
||||
var elem = page.querySelector('#childrenContent');
|
||||
elem.innerHTML = sections.map(function (section) {
|
||||
var html = "";
|
||||
var sectionClass = "verticalSection";
|
||||
var html = '';
|
||||
var sectionClass = 'verticalSection';
|
||||
|
||||
if ("Audio" === section.type) {
|
||||
sectionClass += " verticalSection-extrabottompadding";
|
||||
if ('Audio' === section.type) {
|
||||
sectionClass += ' verticalSection-extrabottompadding';
|
||||
}
|
||||
|
||||
html += '<div class="' + sectionClass + '" data-type="' + section.type + '">';
|
||||
html += '<div class="sectionTitleContainer sectionTitleContainer-cards">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">';
|
||||
html += section.name;
|
||||
html += "</h2>";
|
||||
html += '<a is="emby-linkbutton" href="#" class="clearLink hide" style="margin-left:1em;vertical-align:middle;"><button is="emby-button" type="button" class="raised more raised-mini noIcon">' + Globalize.translate("ButtonMore") + "</button></a>";
|
||||
html += "</div>";
|
||||
html += '</h2>';
|
||||
html += '<a is="emby-linkbutton" href="#" class="clearLink hide" style="margin-left:1em;vertical-align:middle;"><button is="emby-button" type="button" class="raised more raised-mini noIcon">' + globalize.translate('ButtonMore') + '</button></a>';
|
||||
html += '</div>';
|
||||
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right">';
|
||||
html += "</div>";
|
||||
return html += "</div>";
|
||||
}).join("");
|
||||
var sectionElems = elem.querySelectorAll(".verticalSection");
|
||||
html += '</div>';
|
||||
return html += '</div>';
|
||||
}).join('');
|
||||
var sectionElems = elem.querySelectorAll('.verticalSection');
|
||||
|
||||
for (var i = 0, length = sectionElems.length; i < length; i++) {
|
||||
renderSection(page, item, sectionElems[i], sectionElems[i].getAttribute("data-type"));
|
||||
renderSection(page, item, sectionElems[i], sectionElems[i].getAttribute('data-type'));
|
||||
}
|
||||
}
|
||||
|
||||
function renderSection(page, item, element, type) {
|
||||
switch (type) {
|
||||
case "Program":
|
||||
case 'Program':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "Program",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'Program',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
Limit: 10,
|
||||
SortBy: "StartDate"
|
||||
SortBy: 'StartDate'
|
||||
}, {
|
||||
shape: "overflowBackdrop",
|
||||
shape: 'overflowBackdrop',
|
||||
showTitle: true,
|
||||
centerText: true,
|
||||
overlayMoreButton: true,
|
||||
|
@ -111,17 +111,17 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB
|
|||
});
|
||||
break;
|
||||
|
||||
case "Movie":
|
||||
case 'Movie':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "Movie",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'Movie',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
Limit: 10,
|
||||
SortBy: "SortName"
|
||||
SortBy: 'SortName'
|
||||
}, {
|
||||
shape: "overflowPortrait",
|
||||
shape: 'overflowPortrait',
|
||||
showTitle: true,
|
||||
centerText: true,
|
||||
overlayMoreButton: true,
|
||||
|
@ -130,68 +130,68 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB
|
|||
});
|
||||
break;
|
||||
|
||||
case "MusicVideo":
|
||||
case 'MusicVideo':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "MusicVideo",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'MusicVideo',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
Limit: 10,
|
||||
SortBy: "SortName"
|
||||
SortBy: 'SortName'
|
||||
}, {
|
||||
shape: "overflowPortrait",
|
||||
shape: 'overflowPortrait',
|
||||
showTitle: true,
|
||||
centerText: true,
|
||||
overlayPlayButton: true
|
||||
});
|
||||
break;
|
||||
|
||||
case "Trailer":
|
||||
case 'Trailer':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "Trailer",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'Trailer',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
Limit: 10,
|
||||
SortBy: "SortName"
|
||||
SortBy: 'SortName'
|
||||
}, {
|
||||
shape: "overflowPortrait",
|
||||
shape: 'overflowPortrait',
|
||||
showTitle: true,
|
||||
centerText: true,
|
||||
overlayPlayButton: true
|
||||
});
|
||||
break;
|
||||
|
||||
case "Series":
|
||||
case 'Series':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "Series",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'Series',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
Limit: 10,
|
||||
SortBy: "SortName"
|
||||
SortBy: 'SortName'
|
||||
}, {
|
||||
shape: "overflowPortrait",
|
||||
shape: 'overflowPortrait',
|
||||
showTitle: true,
|
||||
centerText: true,
|
||||
overlayMoreButton: true
|
||||
});
|
||||
break;
|
||||
|
||||
case "MusicAlbum":
|
||||
case 'MusicAlbum':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "MusicAlbum",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
SortOrder: "Descending",
|
||||
SortBy: "ProductionYear,Sortname"
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'MusicAlbum',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
SortOrder: 'Descending',
|
||||
SortBy: 'ProductionYear,Sortname'
|
||||
}, {
|
||||
shape: "overflowSquare",
|
||||
shape: 'overflowSquare',
|
||||
playFromHere: true,
|
||||
showTitle: true,
|
||||
showYear: true,
|
||||
|
@ -201,17 +201,17 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB
|
|||
});
|
||||
break;
|
||||
|
||||
case "MusicArtist":
|
||||
case 'MusicArtist':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "MusicArtist",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'MusicArtist',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
Limit: 8,
|
||||
SortBy: "SortName"
|
||||
SortBy: 'SortName'
|
||||
}, {
|
||||
shape: "overflowSquare",
|
||||
shape: 'overflowSquare',
|
||||
playFromHere: true,
|
||||
showTitle: true,
|
||||
showParentTitle: true,
|
||||
|
@ -221,17 +221,17 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB
|
|||
});
|
||||
break;
|
||||
|
||||
case "Episode":
|
||||
case 'Episode':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "Episode",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'Episode',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
Limit: 6,
|
||||
SortBy: "SortName"
|
||||
SortBy: 'SortName'
|
||||
}, {
|
||||
shape: "overflowBackdrop",
|
||||
shape: 'overflowBackdrop',
|
||||
showTitle: true,
|
||||
showParentTitle: true,
|
||||
centerText: true,
|
||||
|
@ -239,17 +239,17 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB
|
|||
});
|
||||
break;
|
||||
|
||||
case "Audio":
|
||||
case 'Audio':
|
||||
loadItems(element, item, type, {
|
||||
MediaTypes: "",
|
||||
IncludeItemTypes: "Audio",
|
||||
PersonTypes: "",
|
||||
ArtistIds: "",
|
||||
AlbumArtistIds: "",
|
||||
SortBy: "AlbumArtist,Album,SortName"
|
||||
MediaTypes: '',
|
||||
IncludeItemTypes: 'Audio',
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
SortBy: 'AlbumArtist,Album,SortName'
|
||||
}, {
|
||||
playFromHere: true,
|
||||
action: "playallfromhere",
|
||||
action: 'playallfromhere',
|
||||
smallIcon: true,
|
||||
artist: true
|
||||
});
|
||||
|
@ -259,27 +259,27 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB
|
|||
function loadItems(element, item, type, query, listOptions) {
|
||||
query = getQuery(query, item);
|
||||
getItemsFunction(query, item)(query.StartIndex, query.Limit, query.Fields).then(function (result) {
|
||||
var html = "";
|
||||
var html = '';
|
||||
|
||||
if (query.Limit && result.TotalRecordCount > query.Limit) {
|
||||
var link = element.querySelector("a");
|
||||
link.classList.remove("hide");
|
||||
link.setAttribute("href", getMoreItemsHref(item, type));
|
||||
var link = element.querySelector('a');
|
||||
link.classList.remove('hide');
|
||||
link.setAttribute('href', getMoreItemsHref(item, type));
|
||||
} else {
|
||||
element.querySelector("a").classList.add("hide");
|
||||
element.querySelector('a').classList.add('hide');
|
||||
}
|
||||
|
||||
listOptions.items = result.Items;
|
||||
var itemsContainer = element.querySelector(".itemsContainer");
|
||||
var itemsContainer = element.querySelector('.itemsContainer');
|
||||
|
||||
if ("Audio" == type) {
|
||||
if ('Audio' == type) {
|
||||
html = listView.getListViewHtml(listOptions);
|
||||
itemsContainer.classList.remove("vertical-wrap");
|
||||
itemsContainer.classList.add("vertical-list");
|
||||
itemsContainer.classList.remove('vertical-wrap');
|
||||
itemsContainer.classList.add('vertical-list');
|
||||
} else {
|
||||
html = cardBuilder.getCardsHtml(listOptions);
|
||||
itemsContainer.classList.add("vertical-wrap");
|
||||
itemsContainer.classList.remove("vertical-list");
|
||||
itemsContainer.classList.add('vertical-wrap');
|
||||
itemsContainer.classList.remove('vertical-list');
|
||||
}
|
||||
|
||||
itemsContainer.innerHTML = html;
|
||||
|
@ -288,51 +288,51 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB
|
|||
}
|
||||
|
||||
function getMoreItemsHref(item, type) {
|
||||
if ("Genre" == item.Type) {
|
||||
return "list.html?type=" + type + "&genreId=" + item.Id + "&serverId=" + item.ServerId;
|
||||
if ('Genre' == item.Type) {
|
||||
return 'list.html?type=' + type + '&genreId=' + item.Id + '&serverId=' + item.ServerId;
|
||||
}
|
||||
|
||||
if ("MusicGenre" == item.Type) {
|
||||
return "list.html?type=" + type + "&musicGenreId=" + item.Id + "&serverId=" + item.ServerId;
|
||||
if ('MusicGenre' == item.Type) {
|
||||
return 'list.html?type=' + type + '&musicGenreId=' + item.Id + '&serverId=' + item.ServerId;
|
||||
}
|
||||
|
||||
if ("Studio" == item.Type) {
|
||||
return "list.html?type=" + type + "&studioId=" + item.Id + "&serverId=" + item.ServerId;
|
||||
if ('Studio' == item.Type) {
|
||||
return 'list.html?type=' + type + '&studioId=' + item.Id + '&serverId=' + item.ServerId;
|
||||
}
|
||||
|
||||
if ("MusicArtist" == item.Type) {
|
||||
return "list.html?type=" + type + "&artistId=" + item.Id + "&serverId=" + item.ServerId;
|
||||
if ('MusicArtist' == item.Type) {
|
||||
return 'list.html?type=' + type + '&artistId=' + item.Id + '&serverId=' + item.ServerId;
|
||||
}
|
||||
|
||||
if ("Person" == item.Type) {
|
||||
return "list.html?type=" + type + "&personId=" + item.Id + "&serverId=" + item.ServerId;
|
||||
if ('Person' == item.Type) {
|
||||
return 'list.html?type=' + type + '&personId=' + item.Id + '&serverId=' + item.ServerId;
|
||||
}
|
||||
|
||||
return "list.html?type=" + type + "&parentId=" + item.Id + "&serverId=" + item.ServerId;
|
||||
return 'list.html?type=' + type + '&parentId=' + item.Id + '&serverId=' + item.ServerId;
|
||||
}
|
||||
|
||||
function addCurrentItemToQuery(query, item) {
|
||||
if (item.Type == "Person") {
|
||||
if (item.Type == 'Person') {
|
||||
query.PersonIds = item.Id;
|
||||
} else if (item.Type == "Genre") {
|
||||
} else if (item.Type == 'Genre') {
|
||||
query.Genres = item.Name;
|
||||
} else if (item.Type == "MusicGenre") {
|
||||
} else if (item.Type == 'MusicGenre') {
|
||||
query.Genres = item.Name;
|
||||
} else if (item.Type == "GameGenre") {
|
||||
} else if (item.Type == 'GameGenre') {
|
||||
query.Genres = item.Name;
|
||||
} else if (item.Type == "Studio") {
|
||||
} else if (item.Type == 'Studio') {
|
||||
query.StudioIds = item.Id;
|
||||
} else if (item.Type == "MusicArtist") {
|
||||
} else if (item.Type == 'MusicArtist') {
|
||||
query.AlbumArtistIds = item.Id;
|
||||
}
|
||||
}
|
||||
|
||||
function getQuery(options, item) {
|
||||
var query = {
|
||||
SortOrder: "Ascending",
|
||||
IncludeItemTypes: "",
|
||||
SortOrder: 'Ascending',
|
||||
IncludeItemTypes: '',
|
||||
Recursive: true,
|
||||
Fields: "AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio,BasicSyncInfo",
|
||||
Fields: 'AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio,BasicSyncInfo',
|
||||
Limit: 100,
|
||||
StartIndex: 0,
|
||||
CollapseBoxSetItems: false
|
||||
|
@ -349,12 +349,12 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB
|
|||
query.Limit = limit;
|
||||
|
||||
if (fields) {
|
||||
query.Fields += "," + fields;
|
||||
query.Fields += ',' + fields;
|
||||
}
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
if ("MusicArtist" === query.IncludeItemTypes) {
|
||||
if ('MusicArtist' === query.IncludeItemTypes) {
|
||||
query.IncludeItemTypes = null;
|
||||
return apiClient.getAlbumArtists(apiClient.getCurrentUserId(), query);
|
||||
}
|
||||
|
|
170
src/scripts/keyboardnavigation.js
Normal file
170
src/scripts/keyboardnavigation.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
* Module for performing keyboard navigation.
|
||||
* @module components/input/keyboardnavigation
|
||||
*/
|
||||
|
||||
import inputManager from 'inputManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
|
||||
/**
|
||||
* Key name mapping.
|
||||
*/
|
||||
const KeyNames = {
|
||||
13: 'Enter',
|
||||
19: 'Pause',
|
||||
27: 'Escape',
|
||||
32: 'Space',
|
||||
37: 'ArrowLeft',
|
||||
38: 'ArrowUp',
|
||||
39: 'ArrowRight',
|
||||
40: 'ArrowDown',
|
||||
// MediaRewind (Tizen/WebOS)
|
||||
412: 'MediaRewind',
|
||||
// MediaStop (Tizen/WebOS)
|
||||
413: 'MediaStop',
|
||||
// MediaPlay (Tizen/WebOS)
|
||||
415: 'MediaPlay',
|
||||
// MediaFastForward (Tizen/WebOS)
|
||||
417: 'MediaFastForward',
|
||||
// Back (WebOS)
|
||||
461: 'Back',
|
||||
// Back (Tizen)
|
||||
10009: 'Back',
|
||||
// MediaTrackPrevious (Tizen)
|
||||
10232: 'MediaTrackPrevious',
|
||||
// MediaTrackNext (Tizen)
|
||||
10233: 'MediaTrackNext',
|
||||
// MediaPlayPause (Tizen)
|
||||
10252: 'MediaPlayPause'
|
||||
};
|
||||
|
||||
/**
|
||||
* Keys used for keyboard navigation.
|
||||
*/
|
||||
const NavigationKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
|
||||
|
||||
let hasFieldKey = false;
|
||||
try {
|
||||
hasFieldKey = 'key' in new KeyboardEvent('keydown');
|
||||
} catch (e) {
|
||||
console.error("error checking 'key' field");
|
||||
}
|
||||
|
||||
if (!hasFieldKey) {
|
||||
// Add [a..z]
|
||||
for (let i = 65; i <= 90; i++) {
|
||||
KeyNames[i] = String.fromCharCode(i).toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns key name from event.
|
||||
*
|
||||
* @param {KeyboardEvent} event - Keyboard event.
|
||||
* @return {string} Key name.
|
||||
*/
|
||||
export function getKeyName(event) {
|
||||
return KeyNames[event.keyCode] || event.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns _true_ if key is used for navigation.
|
||||
*
|
||||
* @param {string} key - Key name.
|
||||
* @return {boolean} _true_ if key is used for navigation.
|
||||
*/
|
||||
export function isNavigationKey(key) {
|
||||
return NavigationKeys.indexOf(key) != -1;
|
||||
}
|
||||
|
||||
export function enable() {
|
||||
document.addEventListener('keydown', function (e) {
|
||||
const key = getKeyName(e);
|
||||
|
||||
// Ignore navigation keys for non-TV
|
||||
if (!layoutManager.tv && isNavigationKey(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let capture = true;
|
||||
|
||||
switch (key) {
|
||||
case 'ArrowLeft':
|
||||
inputManager.handle('left');
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
inputManager.handle('up');
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
inputManager.handle('right');
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
inputManager.handle('down');
|
||||
break;
|
||||
|
||||
case 'Back':
|
||||
inputManager.handle('back');
|
||||
break;
|
||||
|
||||
case 'Escape':
|
||||
if (layoutManager.tv) {
|
||||
inputManager.handle('back');
|
||||
} else {
|
||||
capture = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'MediaPlay':
|
||||
inputManager.handle('play');
|
||||
break;
|
||||
case 'Pause':
|
||||
inputManager.handle('pause');
|
||||
break;
|
||||
case 'MediaPlayPause':
|
||||
inputManager.handle('playpause');
|
||||
break;
|
||||
case 'MediaRewind':
|
||||
inputManager.handle('rewind');
|
||||
break;
|
||||
case 'MediaFastForward':
|
||||
inputManager.handle('fastforward');
|
||||
break;
|
||||
case 'MediaStop':
|
||||
inputManager.handle('stop');
|
||||
break;
|
||||
case 'MediaTrackPrevious':
|
||||
inputManager.handle('previoustrack');
|
||||
break;
|
||||
case 'MediaTrackNext':
|
||||
inputManager.handle('nexttrack');
|
||||
break;
|
||||
|
||||
default:
|
||||
capture = false;
|
||||
}
|
||||
|
||||
if (capture) {
|
||||
console.debug('disabling default event handling');
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Gamepad initialisation. No script is required if no gamepads are present at init time, saving a bit of resources.
|
||||
// Whenever the gamepad is connected, we hand all the control of the gamepad to gamepadtokey.js by removing the event handler
|
||||
function attachGamepadScript(e) {
|
||||
console.log('Gamepad connected! Attaching gamepadtokey.js script');
|
||||
window.removeEventListener('gamepadconnected', attachGamepadScript);
|
||||
require(['scripts/gamepadtokey']);
|
||||
}
|
||||
|
||||
// No need to check for gamepads manually at load time, the eventhandler will be fired for that
|
||||
if (navigator.getGamepads) { /* eslint-disable-line compat/compat */
|
||||
window.addEventListener('gamepadconnected', attachGamepadScript);
|
||||
}
|
||||
|
||||
export default {
|
||||
enable: enable,
|
||||
getKeyName: getKeyName,
|
||||
isNavigationKey: isNavigationKey
|
||||
};
|
|
@ -1,9 +1,9 @@
|
|||
define(["userSettings"], function (userSettings) {
|
||||
"use strict";
|
||||
define(['userSettings', 'globalize'], function (userSettings, globalize) {
|
||||
'use strict';
|
||||
|
||||
var libraryBrowser = {
|
||||
getSavedQueryKey: function (modifier) {
|
||||
return window.location.href.split("#")[0] + (modifier || "");
|
||||
return window.location.href.split('#')[0] + (modifier || '');
|
||||
},
|
||||
loadSavedQueryValues: function (key, query) {
|
||||
var values = userSettings.get(key);
|
||||
|
@ -29,34 +29,34 @@ define(["userSettings"], function (userSettings) {
|
|||
userSettings.set(key, JSON.stringify(values));
|
||||
},
|
||||
saveViewSetting: function (key, value) {
|
||||
userSettings.set(key + "-_view", value);
|
||||
userSettings.set(key + '-_view', value);
|
||||
},
|
||||
getSavedView: function (key) {
|
||||
return userSettings.get(key + "-_view");
|
||||
return userSettings.get(key + '-_view');
|
||||
},
|
||||
showLayoutMenu: function (button, currentLayout, views) {
|
||||
var dispatchEvent = true;
|
||||
|
||||
if (!views) {
|
||||
dispatchEvent = false;
|
||||
views = button.getAttribute("data-layouts");
|
||||
views = views ? views.split(",") : ["List", "Poster", "PosterCard", "Thumb", "ThumbCard"];
|
||||
views = button.getAttribute('data-layouts');
|
||||
views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard'];
|
||||
}
|
||||
|
||||
var menuItems = views.map(function (v) {
|
||||
return {
|
||||
name: Globalize.translate("Option" + v),
|
||||
name: globalize.translate('Option' + v),
|
||||
id: v,
|
||||
selected: currentLayout == v
|
||||
};
|
||||
});
|
||||
|
||||
require(["actionsheet"], function (actionsheet) {
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
actionsheet.show({
|
||||
items: menuItems,
|
||||
positionTo: button,
|
||||
callback: function (id) {
|
||||
button.dispatchEvent(new CustomEvent("layoutchange", {
|
||||
button.dispatchEvent(new CustomEvent('layoutchange', {
|
||||
detail: {
|
||||
viewStyle: id
|
||||
},
|
||||
|
@ -66,7 +66,7 @@ define(["userSettings"], function (userSettings) {
|
|||
|
||||
if (!dispatchEvent) {
|
||||
if (window.$) {
|
||||
$(button).trigger("layoutchange", [id]);
|
||||
$(button).trigger('layoutchange', [id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,49 +77,49 @@ define(["userSettings"], function (userSettings) {
|
|||
var startIndex = options.startIndex;
|
||||
var limit = options.limit;
|
||||
var totalRecordCount = options.totalRecordCount;
|
||||
var html = "";
|
||||
var html = '';
|
||||
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
var showControls = limit < totalRecordCount;
|
||||
|
||||
if (html += '<div class="listPaging">', showControls) {
|
||||
html += '<span style="vertical-align:middle;">';
|
||||
html += Globalize.translate("ListPaging", (totalRecordCount ? startIndex + 1 : 0), recordsEnd, totalRecordCount);
|
||||
html += "</span>";
|
||||
html += globalize.translate('ListPaging', (totalRecordCount ? startIndex + 1 : 0), recordsEnd, totalRecordCount);
|
||||
html += '</span>';
|
||||
}
|
||||
|
||||
if (showControls || options.viewButton || options.filterButton || options.sortButton || options.addLayoutButton) {
|
||||
html += '<div style="display:inline-block;">';
|
||||
|
||||
if (showControls) {
|
||||
html += '<button is="paper-icon-button-light" class="btnPreviousPage autoSize" ' + (startIndex ? "" : "disabled") + '><i class="material-icons arrow_back"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnNextPage autoSize" ' + (startIndex + limit >= totalRecordCount ? "disabled" : "") + '><i class="material-icons arrow_forward"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnPreviousPage autoSize" ' + (startIndex ? '' : 'disabled') + '><span class="material-icons arrow_back"></span></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnNextPage autoSize" ' + (startIndex + limit >= totalRecordCount ? 'disabled' : '') + '><span class="material-icons arrow_forward"></span></button>';
|
||||
}
|
||||
|
||||
if (options.addLayoutButton) {
|
||||
html += '<button is="paper-icon-button-light" title="' + Globalize.translate("ButtonSelectView") + '" class="btnChangeLayout autoSize" data-layouts="' + (options.layouts || "") + '" onclick="LibraryBrowser.showLayoutMenu(this, \'' + (options.currentLayout || "") + '\');"><i class="material-icons view_comfy"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" title="' + globalize.translate('ButtonSelectView') + '" class="btnChangeLayout autoSize" data-layouts="' + (options.layouts || '') + '" onclick="LibraryBrowser.showLayoutMenu(this, \'' + (options.currentLayout || '') + '\');"><span class="material-icons view_comfy"></span></button>';
|
||||
}
|
||||
|
||||
if (options.sortButton) {
|
||||
html += '<button is="paper-icon-button-light" class="btnSort autoSize" title="' + Globalize.translate("ButtonSort") + '"><i class="material-icons sort_by_alpha"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnSort autoSize" title="' + globalize.translate('ButtonSort') + '"><span class="material-icons sort_by_alpha"></span></button>';
|
||||
}
|
||||
|
||||
if (options.filterButton) {
|
||||
html += '<button is="paper-icon-button-light" class="btnFilter autoSize" title="' + Globalize.translate("ButtonFilter") + '"><i class="material-icons filter_list"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnFilter autoSize" title="' + globalize.translate('ButtonFilter') + '"><span class="material-icons filter_list"></span></button>';
|
||||
}
|
||||
|
||||
html += "</div>";
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
return html += "</div>";
|
||||
return html += '</div>';
|
||||
},
|
||||
showSortMenu: function (options) {
|
||||
require(["dialogHelper", "emby-radio"], function (dialogHelper) {
|
||||
require(['dialogHelper', 'emby-radio'], function (dialogHelper) {
|
||||
function onSortByChange() {
|
||||
var newValue = this.value;
|
||||
|
||||
if (this.checked) {
|
||||
var changed = options.query.SortBy != newValue;
|
||||
options.query.SortBy = newValue.replace("_", ",");
|
||||
options.query.SortBy = newValue.replace('_', ',');
|
||||
options.query.StartIndex = 0;
|
||||
|
||||
if (options.callback && changed) {
|
||||
|
@ -148,48 +148,48 @@ define(["userSettings"], function (userSettings) {
|
|||
entryAnimationDuration: 160,
|
||||
exitAnimationDuration: 200
|
||||
});
|
||||
dlg.classList.add("ui-body-a");
|
||||
dlg.classList.add("background-theme-a");
|
||||
dlg.classList.add("formDialog");
|
||||
var html = "";
|
||||
dlg.classList.add('ui-body-a');
|
||||
dlg.classList.add('background-theme-a');
|
||||
dlg.classList.add('formDialog');
|
||||
var html = '';
|
||||
html += '<div style="margin:0;padding:1.25em 1.5em 1.5em;">';
|
||||
html += '<h2 style="margin:0 0 .5em;">';
|
||||
html += Globalize.translate("HeaderSortBy");
|
||||
html += "</h2>";
|
||||
html += globalize.translate('HeaderSortBy');
|
||||
html += '</h2>';
|
||||
var i;
|
||||
var length;
|
||||
var isChecked;
|
||||
html += '<div>';
|
||||
for (i = 0, length = options.items.length; i < length; i++) {
|
||||
var option = options.items[i];
|
||||
var radioValue = option.id.replace(",", "_");
|
||||
isChecked = (options.query.SortBy || "").replace(",", "_") == radioValue ? " checked" : "";
|
||||
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortBy" data-id="' + option.id + '" value="' + radioValue + '" class="menuSortBy" ' + isChecked + " /><span>" + option.name + "</span></label>";
|
||||
var radioValue = option.id.replace(',', '_');
|
||||
isChecked = (options.query.SortBy || '').replace(',', '_') == radioValue ? ' checked' : '';
|
||||
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortBy" data-id="' + option.id + '" value="' + radioValue + '" class="menuSortBy" ' + isChecked + ' /><span>' + option.name + '</span></label>';
|
||||
}
|
||||
|
||||
html += "</div>";
|
||||
html += '</div>';
|
||||
html += '<h2 style="margin: 1em 0 .5em;">';
|
||||
html += Globalize.translate("HeaderSortOrder");
|
||||
html += "</h2>";
|
||||
html += "<div>";
|
||||
isChecked = "Ascending" == options.query.SortOrder ? " checked" : "";
|
||||
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortOrder" value="Ascending" class="menuSortOrder" ' + isChecked + " /><span>" + Globalize.translate("OptionAscending") + "</span></label>";
|
||||
isChecked = "Descending" == options.query.SortOrder ? " checked" : "";
|
||||
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortOrder" value="Descending" class="menuSortOrder" ' + isChecked + " /><span>" + Globalize.translate("OptionDescending") + "</span></label>";
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
html += globalize.translate('HeaderSortOrder');
|
||||
html += '</h2>';
|
||||
html += '<div>';
|
||||
isChecked = 'Ascending' == options.query.SortOrder ? ' checked' : '';
|
||||
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortOrder" value="Ascending" class="menuSortOrder" ' + isChecked + ' /><span>' + globalize.translate('OptionAscending') + '</span></label>';
|
||||
isChecked = 'Descending' == options.query.SortOrder ? ' checked' : '';
|
||||
html += '<label class="radio-label-block"><input type="radio" is="emby-radio" name="SortOrder" value="Descending" class="menuSortOrder" ' + isChecked + ' /><span>' + globalize.translate('OptionDescending') + '</span></label>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
dlg.innerHTML = html;
|
||||
dialogHelper.open(dlg);
|
||||
var sortBys = dlg.querySelectorAll(".menuSortBy");
|
||||
var sortBys = dlg.querySelectorAll('.menuSortBy');
|
||||
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
sortBys[i].addEventListener("change", onSortByChange);
|
||||
sortBys[i].addEventListener('change', onSortByChange);
|
||||
}
|
||||
|
||||
var sortOrders = dlg.querySelectorAll(".menuSortOrder");
|
||||
var sortOrders = dlg.querySelectorAll('.menuSortOrder');
|
||||
|
||||
for (i = 0, length = sortOrders.length; i < length; i++) {
|
||||
sortOrders[i].addEventListener("change", onSortOrderChange);
|
||||
sortOrders[i].addEventListener('change', onSortOrderChange);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,12 @@
|
|||
define(["layoutManager", "datetime", "cardBuilder", "apphost"], function (layoutManager, datetime, cardBuilder, appHost) {
|
||||
"use strict";
|
||||
define(['layoutManager', 'datetime', 'cardBuilder', 'apphost'], function (layoutManager, datetime, cardBuilder, appHost) {
|
||||
'use strict';
|
||||
|
||||
function enableScrollX() {
|
||||
return !layoutManager.desktop;
|
||||
}
|
||||
|
||||
function getBackdropShape() {
|
||||
return enableScrollX() ? "overflowBackdrop" : "backdrop";
|
||||
return enableScrollX() ? 'overflowBackdrop' : 'backdrop';
|
||||
}
|
||||
|
||||
function getTimersHtml(timers, options) {
|
||||
|
@ -14,27 +14,27 @@ define(["layoutManager", "datetime", "cardBuilder", "apphost"], function (layout
|
|||
var i;
|
||||
var length;
|
||||
var items = timers.map(function (t) {
|
||||
t.Type = "Timer";
|
||||
t.Type = 'Timer';
|
||||
return t;
|
||||
});
|
||||
var groups = [];
|
||||
var currentGroupName = "";
|
||||
var currentGroupName = '';
|
||||
var currentGroup = [];
|
||||
|
||||
for (i = 0, length = items.length; i < length; i++) {
|
||||
var item = items[i];
|
||||
var dateText = "";
|
||||
var dateText = '';
|
||||
|
||||
if (options.indexByDate !== false && item.StartDate) {
|
||||
try {
|
||||
var premiereDate = datetime.parseISO8601Date(item.StartDate, true);
|
||||
dateText = datetime.toLocaleDateString(premiereDate, {
|
||||
weekday: "long",
|
||||
month: "short",
|
||||
day: "numeric"
|
||||
weekday: 'long',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("error parsing premiereDate:" + item.StartDate + "; error: " + err);
|
||||
console.error('error parsing premiereDate:' + item.StartDate + '; error: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,23 +60,23 @@ define(["layoutManager", "datetime", "cardBuilder", "apphost"], function (layout
|
|||
});
|
||||
}
|
||||
|
||||
var html = "";
|
||||
var html = '';
|
||||
|
||||
for (i = 0, length = groups.length; i < length; i++) {
|
||||
var group = groups[i];
|
||||
var supportsImageAnalysis = appHost.supports("imageanalysis");
|
||||
var supportsImageAnalysis = appHost.supports('imageanalysis');
|
||||
var cardLayout = appHost.preferVisualCards || supportsImageAnalysis;
|
||||
|
||||
cardLayout = true;
|
||||
if (group.name) {
|
||||
html += '<div class="verticalSection">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + group.name + "</h2>";
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + group.name + '</h2>';
|
||||
}
|
||||
if (enableScrollX()) {
|
||||
var scrollXClass = "scrollX hiddenScrollX";
|
||||
var scrollXClass = 'scrollX hiddenScrollX';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollXClass += " smoothScrollX";
|
||||
scrollXClass += ' smoothScrollX';
|
||||
}
|
||||
|
||||
html += '<div is="emby-itemscontainer" class="itemsContainer ' + scrollXClass + ' padded-left padded-right">';
|
||||
|
@ -86,26 +86,26 @@ define(["layoutManager", "datetime", "cardBuilder", "apphost"], function (layout
|
|||
|
||||
html += cardBuilder.getCardsHtml({
|
||||
items: group.items,
|
||||
shape: cardLayout ? getBackdropShape() : enableScrollX() ? "autoOverflow" : "autoVertical",
|
||||
shape: cardLayout ? getBackdropShape() : enableScrollX() ? 'autoOverflow' : 'autoVertical',
|
||||
showParentTitleOrTitle: true,
|
||||
showAirTime: true,
|
||||
showAirEndTime: true,
|
||||
showChannelName: !cardLayout,
|
||||
cardLayout: cardLayout,
|
||||
centerText: !cardLayout,
|
||||
action: "edit",
|
||||
cardFooterAside: "none",
|
||||
preferThumb: !!cardLayout || "auto",
|
||||
defaultShape: cardLayout ? null : "portrait",
|
||||
action: 'edit',
|
||||
cardFooterAside: 'none',
|
||||
preferThumb: !!cardLayout || 'auto',
|
||||
defaultShape: cardLayout ? null : 'portrait',
|
||||
coverImage: true,
|
||||
allowBottomPadding: false,
|
||||
overlayText: false,
|
||||
showChannelLogo: cardLayout
|
||||
});
|
||||
html += "</div>";
|
||||
html += '</div>';
|
||||
|
||||
if (group.name) {
|
||||
html += "</div>";
|
||||
html += '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
169
src/scripts/mouseManager.js
Normal file
169
src/scripts/mouseManager.js
Normal file
|
@ -0,0 +1,169 @@
|
|||
define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'dom'], function (inputManager, focusManager, browser, layoutManager, events, dom) {
|
||||
'use strict';
|
||||
|
||||
var self = {};
|
||||
|
||||
var lastMouseInputTime = new Date().getTime();
|
||||
var isMouseIdle;
|
||||
|
||||
function mouseIdleTime() {
|
||||
return new Date().getTime() - lastMouseInputTime;
|
||||
}
|
||||
|
||||
function notifyApp() {
|
||||
|
||||
inputManager.notifyMouseMove();
|
||||
}
|
||||
|
||||
function removeIdleClasses() {
|
||||
|
||||
var classList = document.body.classList;
|
||||
|
||||
classList.remove('mouseIdle');
|
||||
classList.remove('mouseIdle-tv');
|
||||
}
|
||||
|
||||
function addIdleClasses() {
|
||||
|
||||
var classList = document.body.classList;
|
||||
|
||||
classList.add('mouseIdle');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
classList.add('mouseIdle-tv');
|
||||
}
|
||||
}
|
||||
|
||||
var lastPointerMoveData;
|
||||
function onPointerMove(e) {
|
||||
|
||||
var eventX = e.screenX;
|
||||
var eventY = e.screenY;
|
||||
|
||||
// if coord don't exist how could it move
|
||||
if (typeof eventX === 'undefined' && typeof eventY === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = lastPointerMoveData;
|
||||
if (!obj) {
|
||||
lastPointerMoveData = {
|
||||
x: eventX,
|
||||
y: eventY
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// if coord are same, it didn't move
|
||||
if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
obj.x = eventX;
|
||||
obj.y = eventY;
|
||||
|
||||
lastMouseInputTime = new Date().getTime();
|
||||
notifyApp();
|
||||
|
||||
if (isMouseIdle) {
|
||||
isMouseIdle = false;
|
||||
removeIdleClasses();
|
||||
events.trigger(self, 'mouseactive');
|
||||
}
|
||||
}
|
||||
|
||||
function onPointerEnter(e) {
|
||||
|
||||
var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
|
||||
|
||||
if (pointerType === 'mouse') {
|
||||
if (!isMouseIdle) {
|
||||
var parent = focusManager.focusableParent(e.target);
|
||||
if (parent) {
|
||||
focusManager.focus(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function enableFocusWithMouse() {
|
||||
|
||||
if (!layoutManager.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (browser.web0s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (browser.tv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function onMouseInterval() {
|
||||
|
||||
if (!isMouseIdle && mouseIdleTime() >= 5000) {
|
||||
isMouseIdle = true;
|
||||
addIdleClasses();
|
||||
events.trigger(self, 'mouseidle');
|
||||
}
|
||||
}
|
||||
|
||||
var mouseInterval;
|
||||
function startMouseInterval() {
|
||||
|
||||
if (!mouseInterval) {
|
||||
mouseInterval = setInterval(onMouseInterval, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function stopMouseInterval() {
|
||||
|
||||
var interval = mouseInterval;
|
||||
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
mouseInterval = null;
|
||||
}
|
||||
|
||||
removeIdleClasses();
|
||||
}
|
||||
|
||||
function initMouse() {
|
||||
|
||||
stopMouseInterval();
|
||||
|
||||
dom.removeEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
if (!layoutManager.mobile) {
|
||||
startMouseInterval();
|
||||
|
||||
dom.addEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
dom.removeEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
|
||||
if (enableFocusWithMouse()) {
|
||||
dom.addEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initMouse();
|
||||
|
||||
events.on(layoutManager, 'modechange', initMouse);
|
||||
|
||||
return self;
|
||||
});
|
|
@ -1,14 +1,14 @@
|
|||
define(["listView"], function (listView) {
|
||||
"use strict";
|
||||
define(['listView'], function (listView) {
|
||||
'use strict';
|
||||
|
||||
function getFetchPlaylistItemsFn(itemId) {
|
||||
return function () {
|
||||
var query = {
|
||||
Fields: "PrimaryImageAspectRatio,UserData",
|
||||
EnableImageTypes: "Primary,Backdrop,Banner,Thumb",
|
||||
Fields: 'PrimaryImageAspectRatio,UserData',
|
||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
||||
UserId: ApiClient.getCurrentUserId()
|
||||
};
|
||||
return ApiClient.getJSON(ApiClient.getUrl("Playlists/" + itemId + "/Items", query));
|
||||
return ApiClient.getJSON(ApiClient.getUrl(`Playlists/${itemId}/Items`, query));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ define(["listView"], function (listView) {
|
|||
showIndex: false,
|
||||
showRemoveFromPlaylist: true,
|
||||
playFromHere: true,
|
||||
action: "playallfromhere",
|
||||
action: 'playallfromhere',
|
||||
smallIcon: true,
|
||||
dragHandle: true,
|
||||
playlistId: itemId
|
||||
|
@ -28,9 +28,9 @@ define(["listView"], function (listView) {
|
|||
}
|
||||
|
||||
function init(page, item) {
|
||||
var elem = page.querySelector("#childrenContent .itemsContainer");
|
||||
elem.classList.add("vertical-list");
|
||||
elem.classList.remove("vertical-wrap");
|
||||
var elem = page.querySelector('#childrenContent .itemsContainer');
|
||||
elem.classList.add('vertical-list');
|
||||
elem.classList.remove('vertical-wrap');
|
||||
elem.enableDragReordering(true);
|
||||
elem.fetchData = getFetchPlaylistItemsFn(item.Id);
|
||||
elem.getItemsHtml = getItemsHtmlFn(item.Id);
|
||||
|
@ -43,8 +43,8 @@ define(["listView"], function (listView) {
|
|||
init(page, item);
|
||||
}
|
||||
|
||||
page.querySelector("#childrenContent").classList.add("verticalSection-extrabottompadding");
|
||||
page.querySelector("#childrenContent .itemsContainer").refreshItems();
|
||||
page.querySelector('#childrenContent').classList.add('verticalSection-extrabottompadding');
|
||||
page.querySelector('#childrenContent .itemsContainer').refreshItems();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", "apphost", "imageLoader", "emby-itemscontainer"], function (loading, listView, cardBuilder, libraryMenu, libraryBrowser, appHost, imageLoader) {
|
||||
"use strict";
|
||||
define(['loading', 'listView', 'cardBuilder', 'libraryMenu', 'libraryBrowser', 'apphost', 'imageLoader', 'userSettings', 'emby-itemscontainer'], function (loading, listView, cardBuilder, libraryMenu, libraryBrowser, appHost, imageLoader, userSettings) {
|
||||
'use strict';
|
||||
|
||||
return function (view, params) {
|
||||
function getPageData(context) {
|
||||
|
@ -9,16 +9,20 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", "
|
|||
if (!pageData) {
|
||||
pageData = data[key] = {
|
||||
query: {
|
||||
SortBy: "SortName",
|
||||
SortOrder: "Ascending",
|
||||
IncludeItemTypes: "Playlist",
|
||||
SortBy: 'SortName',
|
||||
SortOrder: 'Ascending',
|
||||
IncludeItemTypes: 'Playlist',
|
||||
Recursive: true,
|
||||
Fields: "PrimaryImageAspectRatio,SortName,CumulativeRunTimeTicks,CanDelete",
|
||||
StartIndex: 0,
|
||||
Limit: 100
|
||||
Fields: 'PrimaryImageAspectRatio,SortName,CumulativeRunTimeTicks,CanDelete',
|
||||
StartIndex: 0
|
||||
},
|
||||
view: libraryBrowser.getSavedView(key) || "Poster"
|
||||
view: libraryBrowser.getSavedView(key) || 'Poster'
|
||||
};
|
||||
|
||||
if (userSettings.libraryPageSize() > 0) {
|
||||
pageData.query['Limit'] = userSettings.libraryPageSize();
|
||||
}
|
||||
|
||||
pageData.query.ParentId = libraryMenu.getTopParentId();
|
||||
libraryBrowser.loadSavedQueryValues(key, pageData.query);
|
||||
}
|
||||
|
@ -48,17 +52,17 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", "
|
|||
|
||||
function onViewStyleChange() {
|
||||
var viewStyle = getPageData(view).view;
|
||||
var itemsContainer = view.querySelector(".itemsContainer");
|
||||
var itemsContainer = view.querySelector('.itemsContainer');
|
||||
|
||||
if ("List" == viewStyle) {
|
||||
itemsContainer.classList.add("vertical-list");
|
||||
itemsContainer.classList.remove("vertical-wrap");
|
||||
if ('List' == viewStyle) {
|
||||
itemsContainer.classList.add('vertical-list');
|
||||
itemsContainer.classList.remove('vertical-wrap');
|
||||
} else {
|
||||
itemsContainer.classList.remove("vertical-list");
|
||||
itemsContainer.classList.add("vertical-wrap");
|
||||
itemsContainer.classList.remove('vertical-list');
|
||||
itemsContainer.classList.add('vertical-wrap');
|
||||
}
|
||||
|
||||
itemsContainer.innerHTML = "";
|
||||
itemsContainer.innerHTML = '';
|
||||
}
|
||||
|
||||
function reloadItems() {
|
||||
|
@ -70,9 +74,9 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", "
|
|||
var result = responses[0];
|
||||
responses[1];
|
||||
window.scrollTo(0, 0);
|
||||
var html = "";
|
||||
var html = '';
|
||||
var viewStyle = getPageData(view).view;
|
||||
view.querySelector(".listTopPaging").innerHTML = libraryBrowser.getQueryPagingHtml({
|
||||
view.querySelector('.listTopPaging').innerHTML = libraryBrowser.getQueryPagingHtml({
|
||||
startIndex: query.StartIndex,
|
||||
limit: query.Limit,
|
||||
totalRecordCount: result.TotalRecordCount,
|
||||
|
@ -80,37 +84,37 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", "
|
|||
showLimit: false,
|
||||
updatePageSizeSetting: false,
|
||||
addLayoutButton: true,
|
||||
layouts: "List,Poster,PosterCard,Thumb,ThumbCard",
|
||||
layouts: 'List,Poster,PosterCard,Thumb,ThumbCard',
|
||||
currentLayout: viewStyle
|
||||
});
|
||||
|
||||
if (result.TotalRecordCount) {
|
||||
if (viewStyle == "List") {
|
||||
if (viewStyle == 'List') {
|
||||
html = listView.getListViewHtml({
|
||||
items: result.Items,
|
||||
sortBy: query.SortBy
|
||||
});
|
||||
} else if (viewStyle == "PosterCard") {
|
||||
} else if (viewStyle == 'PosterCard') {
|
||||
html = cardBuilder.getCardsHtml({
|
||||
items: result.Items,
|
||||
shape: "square",
|
||||
shape: 'square',
|
||||
coverImage: true,
|
||||
showTitle: true,
|
||||
cardLayout: true
|
||||
});
|
||||
} else if (viewStyle == "Thumb") {
|
||||
} else if (viewStyle == 'Thumb') {
|
||||
html = cardBuilder.getCardsHtml({
|
||||
items: result.Items,
|
||||
shape: "backdrop",
|
||||
shape: 'backdrop',
|
||||
showTitle: true,
|
||||
centerText: true,
|
||||
preferThumb: true,
|
||||
overlayPlayButton: true
|
||||
});
|
||||
} else if (viewStyle == "ThumbCard") {
|
||||
} else if (viewStyle == 'ThumbCard') {
|
||||
html = cardBuilder.getCardsHtml({
|
||||
items: result.Items,
|
||||
shape: "backdrop",
|
||||
shape: 'backdrop',
|
||||
showTitle: true,
|
||||
preferThumb: true,
|
||||
cardLayout: true
|
||||
|
@ -118,43 +122,47 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", "
|
|||
} else {
|
||||
html = cardBuilder.getCardsHtml({
|
||||
items: result.Items,
|
||||
shape: "square",
|
||||
shape: 'square',
|
||||
showTitle: true,
|
||||
coverImage: true,
|
||||
centerText: true,
|
||||
overlayPlayButton: true
|
||||
});
|
||||
}
|
||||
view.querySelector(".noItemsMessage").classList.add("hide");
|
||||
view.querySelector('.noItemsMessage').classList.add('hide');
|
||||
} else {
|
||||
view.querySelector(".noItemsMessage").classList.remove("hide");
|
||||
view.querySelector('.noItemsMessage').classList.remove('hide');
|
||||
}
|
||||
|
||||
var elem = view.querySelector(".itemsContainer");
|
||||
var elem = view.querySelector('.itemsContainer');
|
||||
elem.innerHTML = html;
|
||||
imageLoader.lazyChildren(elem);
|
||||
var btnNextPage = view.querySelector(".btnNextPage");
|
||||
var btnNextPage = view.querySelector('.btnNextPage');
|
||||
|
||||
if (btnNextPage) {
|
||||
btnNextPage.addEventListener("click", function () {
|
||||
query.StartIndex += query.Limit;
|
||||
btnNextPage.addEventListener('click', function () {
|
||||
if (userSettings.libraryPageSize() > 0) {
|
||||
query.StartIndex += query.Limit;
|
||||
}
|
||||
reloadItems();
|
||||
});
|
||||
}
|
||||
|
||||
var btnPreviousPage = view.querySelector(".btnPreviousPage");
|
||||
var btnPreviousPage = view.querySelector('.btnPreviousPage');
|
||||
|
||||
if (btnPreviousPage) {
|
||||
btnPreviousPage.addEventListener("click", function () {
|
||||
query.StartIndex -= query.Limit;
|
||||
btnPreviousPage.addEventListener('click', function () {
|
||||
if (userSettings.libraryPageSize() > 0) {
|
||||
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
|
||||
}
|
||||
reloadItems();
|
||||
});
|
||||
}
|
||||
|
||||
var btnChangeLayout = view.querySelector(".btnChangeLayout");
|
||||
var btnChangeLayout = view.querySelector('.btnChangeLayout');
|
||||
|
||||
if (btnChangeLayout) {
|
||||
btnChangeLayout.addEventListener("layoutchange", function (e) {
|
||||
btnChangeLayout.addEventListener('layoutchange', function (e) {
|
||||
var layout = e.detail.viewStyle;
|
||||
getPageData(view).view = layout;
|
||||
libraryBrowser.saveViewSetting(getSavedQueryKey(view), layout);
|
||||
|
@ -169,11 +177,11 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", "
|
|||
}
|
||||
|
||||
var data = {};
|
||||
view.addEventListener("viewbeforeshow", function () {
|
||||
view.addEventListener('viewbeforeshow', function () {
|
||||
reloadItems();
|
||||
});
|
||||
view.querySelector(".btnNewPlaylist").addEventListener("click", function () {
|
||||
require(["playlistEditor"], function (playlistEditor) {
|
||||
view.querySelector('.btnNewPlaylist').addEventListener('click', function () {
|
||||
require(['playlistEditor'], function (playlistEditor) {
|
||||
var serverId = ApiClient.serverInfo().Id;
|
||||
new playlistEditor().show({
|
||||
items: [],
|
||||
|
|
|
@ -1,451 +1,447 @@
|
|||
define([
|
||||
"jQuery",
|
||||
"emby-button",
|
||||
"emby-input",
|
||||
"scripts/livetvcomponents",
|
||||
"paper-icon-button-light",
|
||||
"emby-itemscontainer",
|
||||
"emby-collapse",
|
||||
"emby-select",
|
||||
"livetvcss",
|
||||
"emby-checkbox",
|
||||
"emby-slider",
|
||||
"listViewStyle",
|
||||
"dashboardcss",
|
||||
"detailtablecss"], function () {
|
||||
'jQuery',
|
||||
'emby-button',
|
||||
'emby-input',
|
||||
'scripts/livetvcomponents',
|
||||
'paper-icon-button-light',
|
||||
'emby-itemscontainer',
|
||||
'emby-collapse',
|
||||
'emby-select',
|
||||
'livetvcss',
|
||||
'emby-checkbox',
|
||||
'emby-slider',
|
||||
'listViewStyle',
|
||||
'dashboardcss',
|
||||
'detailtablecss'], function () {
|
||||
|
||||
function defineRoute(newRoute) {
|
||||
var path = newRoute.path;
|
||||
console.debug("defining route: " + path);
|
||||
newRoute.dictionary = "core";
|
||||
console.debug('defining route: ' + path);
|
||||
newRoute.dictionary = 'core';
|
||||
Emby.Page.addRoute(path, newRoute);
|
||||
}
|
||||
|
||||
console.debug("defining core routes");
|
||||
console.debug('defining core routes');
|
||||
|
||||
defineRoute({
|
||||
path: "/addplugin.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dashboard/plugins/add"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/mypreferencesmenu.html",
|
||||
autoFocus: false,
|
||||
transition: "fade",
|
||||
controller: "user/menu"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/myprofile.html",
|
||||
autoFocus: false,
|
||||
transition: "fade",
|
||||
controller: "user/profile"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/addserver.html",
|
||||
path: '/addserver.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: "auth/addserver"
|
||||
controller: 'auth/addserver'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/mypreferencesdisplay.html",
|
||||
path: '/selectserver.html',
|
||||
autoFocus: false,
|
||||
transition: "fade",
|
||||
controller: "user/display"
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'auth/selectserver',
|
||||
type: 'selectserver'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/mypreferenceshome.html",
|
||||
autoFocus: false,
|
||||
transition: "fade",
|
||||
controller: "user/home"
|
||||
path: '/forgotpassword.html',
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'auth/forgotpassword'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/mypreferencesplayback.html",
|
||||
path: '/forgotpasswordpin.html',
|
||||
autoFocus: false,
|
||||
transition: "fade",
|
||||
controller: "user/playback"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/mypreferencessubtitles.html",
|
||||
autoFocus: false,
|
||||
transition: "fade",
|
||||
controller: "user/subtitles"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/myPreferencesQuickConnect.html",
|
||||
autoFocus: false,
|
||||
transition: "fade",
|
||||
controller: "user/quickConnect"
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'auth/forgotpasswordpin'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: "/dashboard.html",
|
||||
path: '/addplugin.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dashboard/dashboard"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/add'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/dashboardgeneral.html",
|
||||
controller: "dashboard/general",
|
||||
path: '/mypreferencesmenu.html',
|
||||
autoFocus: false,
|
||||
roles: "admin"
|
||||
transition: 'fade',
|
||||
controller: 'user/menu'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/networking.html",
|
||||
path: '/myprofile.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dashboard/networking"
|
||||
transition: 'fade',
|
||||
controller: 'user/profile'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/devices.html",
|
||||
path: '/mypreferencesdisplay.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "devices"
|
||||
transition: 'fade',
|
||||
controller: 'user/display'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/device.html",
|
||||
path: '/myPreferencesQuickConnect.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "device"
|
||||
transition: 'fade',
|
||||
controller: 'user/quickConnect'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: '/mypreferenceshome.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/home'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/quickConnect.html",
|
||||
path: '/mypreferencesplayback.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
transition: 'fade',
|
||||
controller: 'user/playback'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/mypreferencessubtitles.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/subtitles'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: '/dashboard.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/dashboard'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/dashboardgeneral.html',
|
||||
controller: 'dashboard/general',
|
||||
autoFocus: false,
|
||||
roles: 'admin'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/networking.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/networking'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/devices.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/devices/devices'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/device.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/devices/device'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/quickConnect.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: "quickConnect"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/dlnaprofile.html",
|
||||
path: '/dlnaprofile.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dlnaprofile"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/dlna/dlnaprofile'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/dlnaprofiles.html",
|
||||
path: '/dlnaprofiles.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dlnaprofiles"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/dlna/dlnaprofiles'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/dlnasettings.html",
|
||||
path: '/dlnasettings.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dlnasettings"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/dlna/dlnasettings'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/edititemmetadata.html",
|
||||
controller: "edititemmetadata",
|
||||
path: '/edititemmetadata.html',
|
||||
controller: 'edititemmetadata',
|
||||
autoFocus: false
|
||||
});
|
||||
defineRoute({
|
||||
path: "/encodingsettings.html",
|
||||
path: '/encodingsettings.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "encodingsettings"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/encodingsettings'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/forgotpassword.html",
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: "auth/forgotpassword"
|
||||
path: '/home.html',
|
||||
autoFocus: false,
|
||||
controller: 'home',
|
||||
transition: 'fade',
|
||||
type: 'home'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/forgotpasswordpin.html",
|
||||
path: '/list.html',
|
||||
autoFocus: false,
|
||||
controller: 'list',
|
||||
transition: 'fade'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/itemdetails.html',
|
||||
controller: 'itemdetailpage',
|
||||
autoFocus: false,
|
||||
transition: 'fade'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/library.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/medialibrarypage'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/librarydisplay.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/librarydisplay'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/livetv.html',
|
||||
controller: 'livetv/livetvsuggested',
|
||||
autoFocus: false,
|
||||
transition: 'fade'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/livetvguideprovider.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'livetvguideprovider'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/livetvsettings.html',
|
||||
autoFocus: false,
|
||||
controller: 'livetvsettings'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/livetvstatus.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'livetvstatus'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/livetvtuner.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'livetvtuner'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/log.html',
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/logs'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/login.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: "auth/forgotpasswordpin"
|
||||
controller: 'auth/login',
|
||||
type: 'login'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/home.html",
|
||||
path: '/metadataimages.html',
|
||||
autoFocus: false,
|
||||
controller: "home",
|
||||
transition: "fade",
|
||||
type: "home"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/metadataimagespage'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/list.html",
|
||||
path: '/metadatanfo.html',
|
||||
autoFocus: false,
|
||||
controller: "list",
|
||||
transition: "fade"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/metadatanfo'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/index.html",
|
||||
path: '/movies.html',
|
||||
autoFocus: false,
|
||||
isDefaultRoute: true
|
||||
controller: 'movies/moviesrecommended',
|
||||
transition: 'fade'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/itemdetails.html",
|
||||
controller: "itemdetailpage",
|
||||
path: '/music.html',
|
||||
controller: 'music/musicrecommended',
|
||||
autoFocus: false,
|
||||
transition: "fade"
|
||||
transition: 'fade'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/library.html",
|
||||
path: '/notificationsetting.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "medialibrarypage"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/notifications/notification'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/librarydisplay.html",
|
||||
path: '/notificationsettings.html',
|
||||
controller: 'dashboard/notifications/notifications',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "librarydisplay"
|
||||
roles: 'admin'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/librarysettings.html",
|
||||
path: '/playbackconfiguration.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "librarysettings"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/playbackconfiguration'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/livetv.html",
|
||||
controller: "livetv/livetvsuggested",
|
||||
path: '/availableplugins.html',
|
||||
autoFocus: false,
|
||||
transition: "fade"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/available'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/livetvguideprovider.html",
|
||||
path: '/installedplugins.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "livetvguideprovider"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/installed'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/livetvsettings.html",
|
||||
path: '/scheduledtask.html',
|
||||
autoFocus: false,
|
||||
controller: "livetvsettings"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/scheduledtasks/scheduledtask'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/livetvstatus.html",
|
||||
path: '/scheduledtasks.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "livetvstatus"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/scheduledtasks/scheduledtasks'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/livetvtuner.html",
|
||||
path: '/search.html',
|
||||
controller: 'searchpage'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/serveractivity.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "livetvtuner"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/serveractivity'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/log.html",
|
||||
roles: "admin",
|
||||
controller: "dashboard/logs"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/login.html",
|
||||
path: '/apikeys.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: "auth/login",
|
||||
type: "login"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/apikeys'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/metadataimages.html",
|
||||
path: '/streamingsettings.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "metadataimagespage"
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/streamingsettings'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/metadatanfo.html",
|
||||
path: '/tv.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "metadatanfo"
|
||||
controller: 'shows/tvrecommended',
|
||||
transition: 'fade'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/movies.html",
|
||||
path: '/useredit.html',
|
||||
autoFocus: false,
|
||||
controller: "movies/moviesrecommended",
|
||||
transition: "fade"
|
||||
roles: 'admin',
|
||||
controller: 'useredit'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/music.html",
|
||||
controller: "music/musicrecommended",
|
||||
path: '/userlibraryaccess.html',
|
||||
autoFocus: false,
|
||||
transition: "fade"
|
||||
roles: 'admin',
|
||||
controller: 'userlibraryaccess'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/notificationsetting.html",
|
||||
path: '/usernew.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dashboard/notifications/notification"
|
||||
roles: 'admin',
|
||||
controller: 'usernew'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/notificationsettings.html",
|
||||
controller: "dashboard/notifications/notifications",
|
||||
path: '/userparentalcontrol.html',
|
||||
autoFocus: false,
|
||||
roles: "admin"
|
||||
roles: 'admin',
|
||||
controller: 'userparentalcontrol'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/nowplaying.html",
|
||||
controller: "playback/nowplaying",
|
||||
path: '/userpassword.html',
|
||||
autoFocus: false,
|
||||
transition: "fade",
|
||||
fullscreen: true,
|
||||
supportsThemeMedia: true,
|
||||
enableMediaControl: false
|
||||
controller: 'userpasswordpage'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/playbackconfiguration.html",
|
||||
path: '/userprofiles.html',
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "playbackconfiguration"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/availableplugins.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dashboard/plugins/available"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/installedplugins.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dashboard/plugins/installed"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/scheduledtask.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dashboard/scheduledtasks/scheduledtask"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/scheduledtasks.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "dashboard/scheduledtasks/scheduledtasks"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/search.html",
|
||||
controller: "searchpage"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/selectserver.html",
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: "auth/selectserver",
|
||||
type: "selectserver"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/serveractivity.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "serveractivity"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/apikeys.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "apikeys"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/streamingsettings.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "streamingsettings"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/tv.html",
|
||||
autoFocus: false,
|
||||
controller: "shows/tvrecommended",
|
||||
transition: "fade"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/useredit.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "useredit"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/userlibraryaccess.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "userlibraryaccess"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/usernew.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "usernew"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/userparentalcontrol.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "userparentalcontrol"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/userpassword.html",
|
||||
autoFocus: false,
|
||||
controller: "userpasswordpage"
|
||||
});
|
||||
defineRoute({
|
||||
path: "/userprofiles.html",
|
||||
autoFocus: false,
|
||||
roles: "admin",
|
||||
controller: "userprofilespage"
|
||||
roles: 'admin',
|
||||
controller: 'userprofilespage'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: "/wizardremoteaccess.html",
|
||||
path: '/wizardremoteaccess.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: "wizard/remoteaccess"
|
||||
controller: 'wizard/remoteaccess'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/wizardfinish.html",
|
||||
path: '/wizardfinish.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: "wizard/finish"
|
||||
controller: 'wizard/finish'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/wizardlibrary.html",
|
||||
path: '/wizardlibrary.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: "medialibrarypage"
|
||||
controller: 'medialibrarypage'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/wizardsettings.html",
|
||||
path: '/wizardsettings.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: "wizard/settings"
|
||||
controller: 'wizard/settings'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/wizardstart.html",
|
||||
path: '/wizardstart.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: "wizard/start"
|
||||
controller: 'wizard/start'
|
||||
});
|
||||
defineRoute({
|
||||
path: "/wizarduser.html",
|
||||
controller: "wizard/user",
|
||||
path: '/wizarduser.html',
|
||||
controller: 'wizard/user',
|
||||
autoFocus: false,
|
||||
anonymous: true
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: "/videoosd.html",
|
||||
transition: "fade",
|
||||
controller: "playback/videoosd",
|
||||
path: '/videoosd.html',
|
||||
transition: 'fade',
|
||||
controller: 'playback/videoosd',
|
||||
autoFocus: false,
|
||||
type: "video-osd",
|
||||
type: 'video-osd',
|
||||
supportsThemeMedia: true,
|
||||
fullscreen: true,
|
||||
enableMediaControl: false
|
||||
});
|
||||
defineRoute({
|
||||
path: "/configurationpage",
|
||||
path: '/nowplaying.html',
|
||||
controller: 'playback/nowplaying',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
fullscreen: true,
|
||||
supportsThemeMedia: true,
|
||||
enableMediaControl: false
|
||||
});
|
||||
defineRoute({
|
||||
path: '/configurationpage',
|
||||
autoFocus: false,
|
||||
enableCache: false,
|
||||
enableContentQueryString: true,
|
||||
roles: "admin"
|
||||
roles: 'admin'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: "/",
|
||||
path: '/',
|
||||
isDefaultRoute: true,
|
||||
autoFocus: false
|
||||
});
|
||||
defineRoute({
|
||||
path: '/index.html',
|
||||
autoFocus: false,
|
||||
isDefaultRoute: true
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
define(["searchFields", "searchResults", "events"], function (SearchFields, SearchResults, events) {
|
||||
"use strict";
|
||||
define(['searchFields', 'searchResults', 'events'], function (SearchFields, SearchResults, events) {
|
||||
'use strict';
|
||||
|
||||
function init(instance, tabContent, options) {
|
||||
tabContent.innerHTML = '<div class="padded-left padded-right searchFields"></div><div class="searchResults padded-top" style="padding-top:1.5em;"></div>';
|
||||
instance.searchFields = new SearchFields({
|
||||
element: tabContent.querySelector(".searchFields")
|
||||
element: tabContent.querySelector('.searchFields')
|
||||
});
|
||||
instance.searchResults = new SearchResults({
|
||||
element: tabContent.querySelector(".searchResults"),
|
||||
element: tabContent.querySelector('.searchResults'),
|
||||
serverId: ApiClient.serverId(),
|
||||
parentId: options.parentId,
|
||||
collectionType: options.collectionType
|
||||
});
|
||||
events.on(instance.searchFields, "search", function (e, value) {
|
||||
events.on(instance.searchFields, 'search', function (e, value) {
|
||||
instance.searchResults.search(value);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function enableAutoLogin(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
this.set('enableAutoLogin', val.toString());
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function enableSystemExternalPlayers(val) {
|
||||
if (val !== null) {
|
||||
if (val !== undefined) {
|
||||
this.set('enableSystemExternalPlayers', val.toString());
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ import events from 'events';
|
|||
|
||||
export function enableAutomaticBitrateDetection(isInNetwork, mediaType, val) {
|
||||
var key = 'enableautobitratebitrate-' + mediaType + '-' + isInNetwork;
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
val = true;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ import events from 'events';
|
|||
|
||||
export function maxStreamingBitrate(isInNetwork, mediaType, val) {
|
||||
var key = 'maxbitrate-' + mediaType + '-' + isInNetwork;
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
// nothing to do, this is always a max value
|
||||
} else {
|
||||
|
@ -72,7 +72,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function maxChromecastBitrate(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
this.set('chromecastBitrate1', val);
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function syncOnlyOnWifi(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
this.set('syncOnlyOnWifi', val.toString());
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function syncPath(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
this.set('syncPath', val);
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function cameraUploadServers(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
this.set('cameraUploadServers', val.join(','));
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function runAtStartup(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
this.set('runatstartup', val.toString());
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function enableCinemaMode(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableCinemaMode', val.toString(), false);
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function enableNextVideoInfoOverlay(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableNextVideoInfoOverlay', val.toString());
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function enableThemeSongs(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableThemeSongs', val.toString(), false);
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function enableThemeVideos(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableThemeVideos', val.toString(), false);
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function enableFastFadein(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('fastFadein', val.toString(), false);
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function enableBackdrops(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableBackdrops', val.toString(), false);
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function language(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('language', val.toString(), false);
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function dateTimeLocale(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('datetimelocale', val.toString(), false);
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function skipBackLength(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('skipBackLength', val.toString());
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function skipForwardLength(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('skipForwardLength', val.toString());
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function dashboardTheme(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('dashboardTheme', val);
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function skin(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('skin', val, false);
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function theme(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('appTheme', val, false);
|
||||
}
|
||||
|
||||
|
@ -194,15 +194,29 @@ import events from 'events';
|
|||
}
|
||||
|
||||
export function screensaver(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('screensaver', val, false);
|
||||
}
|
||||
|
||||
return this.get('screensaver', false);
|
||||
}
|
||||
|
||||
export function libraryPageSize(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('libraryPageSize', parseInt(val, 10), false);
|
||||
}
|
||||
|
||||
var libraryPageSize = parseInt(this.get('libraryPageSize', false), 10);
|
||||
if (libraryPageSize === 0) {
|
||||
// Explicitly return 0 to avoid returning 100 because 0 is falsy.
|
||||
return 0;
|
||||
} else {
|
||||
return libraryPageSize || 100;
|
||||
}
|
||||
}
|
||||
|
||||
export function soundEffects(val) {
|
||||
if (val != null) {
|
||||
if (val !== undefined) {
|
||||
return this.set('soundeffects', val, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ let data;
|
|||
|
||||
function getConfig() {
|
||||
if (data) return Promise.resolve(data);
|
||||
return fetch("/config.json?nocache=" + new Date().getUTCMilliseconds()).then(function (response) {
|
||||
return fetch('/config.json?nocache=' + new Date().getUTCMilliseconds()).then(function (response) {
|
||||
data = response.json();
|
||||
return data;
|
||||
});
|
||||
|
@ -11,5 +11,8 @@ function getConfig() {
|
|||
export function enableMultiServer() {
|
||||
return getConfig().then(config => {
|
||||
return config.multiserver;
|
||||
}).catch(error => {
|
||||
console.log('cannot get web config:', error);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
define(["events", "userSettings", "serverNotifications", "connectionManager", "emby-button"], function (events, userSettings, serverNotifications, connectionManager) {
|
||||
"use strict";
|
||||
define(['events', 'userSettings', 'serverNotifications', 'connectionManager', 'globalize', 'emby-button'], function (events, userSettings, serverNotifications, connectionManager, globalize) {
|
||||
'use strict';
|
||||
|
||||
return function (options) {
|
||||
function pollTasks() {
|
||||
|
@ -26,12 +26,12 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e
|
|||
}
|
||||
|
||||
if (task.State == 'Idle') {
|
||||
button.removeAttribute("disabled");
|
||||
button.removeAttribute('disabled');
|
||||
} else {
|
||||
button.setAttribute("disabled", "disabled");
|
||||
button.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
|
||||
button.setAttribute("data-taskid", task.Id);
|
||||
button.setAttribute('data-taskid', task.Id);
|
||||
var progress = (task.CurrentProgressPercentage || 0).toFixed(1);
|
||||
|
||||
if (options.progressElem) {
|
||||
|
@ -47,12 +47,12 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e
|
|||
if (options.lastResultElem) {
|
||||
var lastResult = task.LastExecutionResult ? task.LastExecutionResult.Status : '';
|
||||
|
||||
if (lastResult == "Failed") {
|
||||
options.lastResultElem.html('<span style="color:#FF0000;">(' + Globalize.translate('LabelFailed') + ')</span>');
|
||||
} else if (lastResult == "Cancelled") {
|
||||
options.lastResultElem.html('<span style="color:#0026FF;">(' + Globalize.translate('LabelCancelled') + ')</span>');
|
||||
} else if (lastResult == "Aborted") {
|
||||
options.lastResultElem.html('<span style="color:#FF0000;">' + Globalize.translate('LabelAbortedByServerShutdown') + '</span>');
|
||||
if (lastResult == 'Failed') {
|
||||
options.lastResultElem.html('<span style="color:#FF0000;">(' + globalize.translate('LabelFailed') + ')</span>');
|
||||
} else if (lastResult == 'Cancelled') {
|
||||
options.lastResultElem.html('<span style="color:#0026FF;">(' + globalize.translate('LabelCancelled') + ')</span>');
|
||||
} else if (lastResult == 'Aborted') {
|
||||
options.lastResultElem.html('<span style="color:#FF0000;">' + globalize.translate('LabelAbortedByServerShutdown') + '</span>');
|
||||
} else {
|
||||
options.lastResultElem.html(lastResult);
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e
|
|||
}
|
||||
|
||||
function onButtonClick() {
|
||||
onScheduledTaskMessageConfirmed(this.getAttribute("data-taskid"));
|
||||
onScheduledTaskMessageConfirmed(this.getAttribute('data-taskid'));
|
||||
}
|
||||
|
||||
function onScheduledTasksUpdate(e, apiClient, info) {
|
||||
|
@ -89,12 +89,12 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e
|
|||
if (pollInterval) {
|
||||
clearInterval(pollInterval);
|
||||
}
|
||||
apiClient.sendMessage("ScheduledTasksInfoStart", "1000,1000");
|
||||
apiClient.sendMessage('ScheduledTasksInfoStart', '1000,1000');
|
||||
pollInterval = setInterval(onPollIntervalFired, 5000);
|
||||
}
|
||||
|
||||
function stopInterval() {
|
||||
connectionManager.getApiClient(serverId).sendMessage("ScheduledTasksInfoStop");
|
||||
connectionManager.getApiClient(serverId).sendMessage('ScheduledTasksInfoStop');
|
||||
|
||||
if (pollInterval) {
|
||||
clearInterval(pollInterval);
|
||||
|
@ -102,18 +102,18 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e
|
|||
}
|
||||
|
||||
if (options.panel) {
|
||||
options.panel.classList.add("hide");
|
||||
options.panel.classList.add('hide');
|
||||
}
|
||||
|
||||
if (options.mode == 'off') {
|
||||
button.removeEventListener("click", onButtonClick);
|
||||
events.off(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate);
|
||||
button.removeEventListener('click', onButtonClick);
|
||||
events.off(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate);
|
||||
stopInterval();
|
||||
} else {
|
||||
button.addEventListener("click", onButtonClick);
|
||||
button.addEventListener('click', onButtonClick);
|
||||
pollTasks();
|
||||
startInterval();
|
||||
events.on(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate);
|
||||
events.on(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
define(["userSettings", "skinManager", "connectionManager", "events"], function (userSettings, skinManager, connectionManager, events) {
|
||||
"use strict";
|
||||
define(['userSettings', 'skinManager', 'connectionManager', 'events'], function (userSettings, skinManager, connectionManager, events) {
|
||||
'use strict';
|
||||
|
||||
var currentViewType;
|
||||
pageClassOn("viewbeforeshow", "page", function () {
|
||||
pageClassOn('viewbeforeshow', 'page', function () {
|
||||
var classList = this.classList;
|
||||
var viewType = classList.contains("type-interior") || classList.contains("wizardPage") ? "a" : "b";
|
||||
var viewType = classList.contains('type-interior') || classList.contains('wizardPage') ? 'a' : 'b';
|
||||
|
||||
if (viewType !== currentViewType) {
|
||||
currentViewType = viewType;
|
||||
var theme;
|
||||
var context;
|
||||
|
||||
if ("a" === viewType) {
|
||||
if ('a' === viewType) {
|
||||
theme = userSettings.dashboardTheme();
|
||||
context = "serverdashboard";
|
||||
context = 'serverdashboard';
|
||||
} else {
|
||||
theme = userSettings.theme();
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ define(["userSettings", "skinManager", "connectionManager", "events"], function
|
|||
skinManager.setTheme(theme, context);
|
||||
}
|
||||
});
|
||||
events.on(connectionManager, "localusersignedin", function (e, user) {
|
||||
events.on(connectionManager, 'localusersignedin', function (e, user) {
|
||||
currentViewType = null;
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue