mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge remote-tracking branch 'upstream/master' into fix-subtitle-line-spacing
Conflicts: src/components/subtitlesettings/subtitleappearancehelper.js src/plugins/htmlVideoPlayer/plugin.js
This commit is contained in:
commit
48886918d3
278 changed files with 2125 additions and 5109 deletions
|
@ -6,7 +6,6 @@ let currentDisplayText = '';
|
|||
let currentDisplayTextContainer;
|
||||
|
||||
function onKeyDown(e) {
|
||||
|
||||
if (e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
|
@ -21,7 +20,6 @@ function onKeyDown(e) {
|
|||
let chr = key ? alphanumeric(key) : null;
|
||||
|
||||
if (chr) {
|
||||
|
||||
chr = chr.toString().toUpperCase();
|
||||
|
||||
if (chr.length === 1) {
|
||||
|
@ -82,12 +80,10 @@ function onAlphanumericShortcutTimeout() {
|
|||
}
|
||||
|
||||
function selectByShortcutValue(container, value) {
|
||||
|
||||
value = value.toUpperCase();
|
||||
|
||||
let focusElem;
|
||||
if (value === '#') {
|
||||
|
||||
focusElem = container.querySelector('*[data-prefix]');
|
||||
}
|
||||
|
||||
|
@ -102,7 +98,6 @@ function selectByShortcutValue(container, value) {
|
|||
|
||||
class AlphaNumericShortcuts {
|
||||
constructor(options) {
|
||||
|
||||
this.options = options;
|
||||
|
||||
const keyDownHandler = onKeyDown.bind(this);
|
||||
|
@ -114,7 +109,6 @@ class AlphaNumericShortcuts {
|
|||
this.keyDownHandler = keyDownHandler;
|
||||
}
|
||||
destroy() {
|
||||
|
||||
const keyDownHandler = this.keyDownHandler;
|
||||
|
||||
if (keyDownHandler) {
|
||||
|
|
|
@ -2,7 +2,6 @@ define([], function () {
|
|||
'use strict';
|
||||
|
||||
function isTv() {
|
||||
|
||||
// This is going to be really difficult to get right
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
|
@ -50,7 +49,6 @@ define([], function () {
|
|||
}
|
||||
|
||||
function hasKeyboard(browser) {
|
||||
|
||||
if (browser.touch) {
|
||||
return true;
|
||||
}
|
||||
|
@ -101,10 +99,7 @@ define([], function () {
|
|||
}
|
||||
|
||||
var animation = false;
|
||||
var animationstring = 'animation';
|
||||
var keyframeprefix = '';
|
||||
var domPrefixes = ['Webkit', 'O', 'Moz'];
|
||||
var pfx = '';
|
||||
var elm = document.createElement('div');
|
||||
|
||||
if (elm.style.animationName !== undefined) {
|
||||
|
@ -114,9 +109,6 @@ define([], function () {
|
|||
if (animation === false && allowPrefix) {
|
||||
for (var i = 0; i < domPrefixes.length; i++) {
|
||||
if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
|
||||
pfx = domPrefixes[i];
|
||||
animationstring = pfx + 'Animation';
|
||||
keyframeprefix = '-' + pfx.toLowerCase() + '-';
|
||||
animation = true;
|
||||
break;
|
||||
}
|
||||
|
@ -135,7 +127,10 @@ define([], function () {
|
|||
var uaMatch = function (ua) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(edge)[ \/]([\w.]+)/.exec(ua) ||
|
||||
var match = /(edg)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(edga)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(edgios)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(edge)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(opera)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(opr)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
||||
|
@ -198,7 +193,9 @@ define([], function () {
|
|||
browser[matched.platform] = true;
|
||||
}
|
||||
|
||||
if (!browser.chrome && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
||||
browser.edgeChromium = browser.edg || browser.edga || browser.edgios;
|
||||
|
||||
if (!browser.chrome && !browser.edgeChromium && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
|
@ -259,7 +256,5 @@ define([], function () {
|
|||
}
|
||||
}
|
||||
|
||||
browser.chromecast = browser.chrome && userAgent.toLowerCase().indexOf('crkey') !== -1;
|
||||
|
||||
return browser;
|
||||
});
|
||||
|
|
|
@ -144,6 +144,10 @@ define(['browser'], function (browser) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (browser.edgeChromium && browser.windows) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
return true;
|
||||
}
|
||||
|
@ -210,7 +214,7 @@ define(['browser'], function (browser) {
|
|||
supported = browser.tizen;
|
||||
break;
|
||||
case 'mov':
|
||||
supported = browser.tizen || browser.web0s || browser.chrome || browser.edgeUwp;
|
||||
supported = browser.tizen || browser.web0s || browser.chrome || browser.edgeChromium || browser.edgeUwp;
|
||||
videoCodecs.push('h264');
|
||||
break;
|
||||
case 'm2ts':
|
||||
|
@ -323,7 +327,6 @@ define(['browser'], function (browser) {
|
|||
// Otherwise with HLS and mp3 audio we're seeing some browsers
|
||||
// safari is lying
|
||||
if (supportsAc3(videoTestElement)) {
|
||||
|
||||
videoAudioCodecs.push('ac3');
|
||||
|
||||
var eAc3 = supportsEac3(videoTestElement);
|
||||
|
@ -505,7 +508,6 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
|
||||
['opus', 'mp3', 'mp2', 'aac', 'flac', 'alac', 'webma', 'wma', 'wav', 'ogg', 'oga'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
|
||||
|
||||
if (audioFormat === 'mp2') {
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'mp2,mp3',
|
||||
|
@ -703,40 +705,35 @@ define(['browser'], function (browser) {
|
|||
|
||||
if (browser.tizen ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) {
|
||||
|
||||
// These tests are passing in safari, but playback is failing
|
||||
if (!browser.safari && !browser.iOS && !browser.web0s && !browser.edge && !browser.mobile) {
|
||||
h264Profiles += '|high 10';
|
||||
}
|
||||
}
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'Video',
|
||||
Codec: 'h264',
|
||||
Conditions: [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsAnamorphic',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'EqualsAny',
|
||||
Property: 'VideoProfile',
|
||||
Value: h264Profiles,
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: maxH264Level.toString(),
|
||||
IsRequired: false
|
||||
}
|
||||
]
|
||||
});
|
||||
const h264CodecProfileConditions = [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsAnamorphic',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'EqualsAny',
|
||||
Property: 'VideoProfile',
|
||||
Value: h264Profiles,
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: maxH264Level.toString(),
|
||||
IsRequired: false
|
||||
}
|
||||
];
|
||||
|
||||
if (!browser.edgeUwp && !browser.tizen && !browser.web0s) {
|
||||
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsInterlaced',
|
||||
Value: 'true',
|
||||
|
@ -745,7 +742,7 @@ define(['browser'], function (browser) {
|
|||
}
|
||||
|
||||
if (maxVideoWidth) {
|
||||
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'Width',
|
||||
Value: maxVideoWidth.toString(),
|
||||
|
@ -758,7 +755,7 @@ define(['browser'], function (browser) {
|
|||
var h264MaxVideoBitrate = globalMaxVideoBitrate;
|
||||
|
||||
if (h264MaxVideoBitrate) {
|
||||
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoBitrate',
|
||||
Value: h264MaxVideoBitrate,
|
||||
|
@ -766,6 +763,33 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
}
|
||||
|
||||
// On iOS 12.x, for TS container max h264 level is 4.2
|
||||
if (browser.iOS && browser.iOSVersion < 13) {
|
||||
const codecProfile = {
|
||||
Type: 'Video',
|
||||
Codec: 'h264',
|
||||
Container: 'ts',
|
||||
Conditions: h264CodecProfileConditions.filter((condition) => {
|
||||
return condition.Property !== 'VideoLevel';
|
||||
})
|
||||
};
|
||||
|
||||
codecProfile.Conditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: '42',
|
||||
IsRequired: false
|
||||
});
|
||||
|
||||
profile.CodecProfiles.push(codecProfile);
|
||||
}
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'Video',
|
||||
Codec: 'h264',
|
||||
Conditions: h264CodecProfileConditions
|
||||
});
|
||||
|
||||
var globalVideoConditions = [];
|
||||
|
||||
if (globalMaxVideoBitrate) {
|
||||
|
|
|
@ -3,7 +3,6 @@ import globalize from 'globalize';
|
|||
/* eslint-disable indent */
|
||||
|
||||
export function parseISO8601Date(s, toLocal) {
|
||||
|
||||
// parenthese matches:
|
||||
// year month day hours minutes seconds
|
||||
// dotmilliseconds
|
||||
|
@ -20,7 +19,6 @@ import globalize from 'globalize';
|
|||
// "00", "00", ".000", "Z", undefined, undefined, undefined]
|
||||
|
||||
if (!d) {
|
||||
|
||||
throw "Couldn't parse ISO 8601 date string '" + s + "'";
|
||||
}
|
||||
|
||||
|
@ -106,7 +104,6 @@ import globalize from 'globalize';
|
|||
}();
|
||||
|
||||
function getOptionList(options) {
|
||||
|
||||
const list = [];
|
||||
|
||||
for (const i in options) {
|
||||
|
@ -120,7 +117,6 @@ import globalize from 'globalize';
|
|||
}
|
||||
|
||||
export function toLocaleString(date, options) {
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
|
@ -128,7 +124,6 @@ import globalize from 'globalize';
|
|||
options = options || {};
|
||||
|
||||
if (toLocaleTimeStringSupportsLocales) {
|
||||
|
||||
const currentLocale = globalize.getCurrentDateTimeLocale();
|
||||
|
||||
if (currentLocale) {
|
||||
|
@ -140,7 +135,6 @@ import globalize from 'globalize';
|
|||
}
|
||||
|
||||
export function toLocaleDateString(date, options) {
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
|
@ -148,7 +142,6 @@ import globalize from 'globalize';
|
|||
options = options || {};
|
||||
|
||||
if (toLocaleTimeStringSupportsLocales) {
|
||||
|
||||
const currentLocale = globalize.getCurrentDateTimeLocale();
|
||||
|
||||
if (currentLocale) {
|
||||
|
@ -174,7 +167,6 @@ import globalize from 'globalize';
|
|||
}
|
||||
|
||||
export function toLocaleTimeString(date, options) {
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
|
@ -182,7 +174,6 @@ import globalize from 'globalize';
|
|||
options = options || {};
|
||||
|
||||
if (toLocaleTimeStringSupportsLocales) {
|
||||
|
||||
const currentLocale = globalize.getCurrentDateTimeLocale();
|
||||
|
||||
if (currentLocale) {
|
||||
|
@ -194,16 +185,13 @@ import globalize from 'globalize';
|
|||
}
|
||||
|
||||
export function getDisplayTime(date) {
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
|
||||
if ((typeof date).toString().toLowerCase() === 'string') {
|
||||
try {
|
||||
|
||||
date = parseISO8601Date(date, true);
|
||||
|
||||
} catch (err) {
|
||||
return date;
|
||||
}
|
||||
|
@ -223,7 +211,6 @@ import globalize from 'globalize';
|
|||
const timeLower = time.toLowerCase();
|
||||
|
||||
if (timeLower.indexOf('am') !== -1 || timeLower.indexOf('pm') !== -1) {
|
||||
|
||||
time = timeLower;
|
||||
let hour = date.getHours() % 12;
|
||||
const suffix = date.getHours() > 11 ? 'pm' : 'am';
|
||||
|
@ -239,12 +226,10 @@ import globalize from 'globalize';
|
|||
minutes = ':' + minutes;
|
||||
time = hour + minutes + suffix;
|
||||
} else {
|
||||
|
||||
const timeParts = time.split(':');
|
||||
|
||||
// Trim off seconds
|
||||
if (timeParts.length > 2) {
|
||||
|
||||
// setting to 2 also handles '21:00:28 GMT+9:30'
|
||||
timeParts.length = 2;
|
||||
time = timeParts.join(':');
|
||||
|
@ -255,7 +240,6 @@ import globalize from 'globalize';
|
|||
}
|
||||
|
||||
export function isRelativeDay(date, offsetInDays) {
|
||||
|
||||
if (!date) {
|
||||
throw new Error('date cannot be null');
|
||||
}
|
||||
|
|
|
@ -4,9 +4,7 @@ import appRouter from 'appRouter';
|
|||
import globalize from 'globalize';
|
||||
|
||||
function alertText(options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(options).then(resolve, resolve);
|
||||
});
|
||||
|
@ -14,7 +12,6 @@ function alertText(options) {
|
|||
}
|
||||
|
||||
export function deleteItem(options) {
|
||||
|
||||
const item = options.item;
|
||||
const parentId = item.SeasonId || item.SeriesId || item.ParentId;
|
||||
|
||||
|
@ -28,9 +25,7 @@ export function deleteItem(options) {
|
|||
primary: 'delete'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
return apiClient.deleteItem(item.Id).then(function () {
|
||||
|
||||
if (options.navigate) {
|
||||
if (parentId) {
|
||||
appRouter.showItem(parentId, item.ServerId);
|
||||
|
@ -39,7 +34,6 @@ export function deleteItem(options) {
|
|||
}
|
||||
}
|
||||
}, function (err) {
|
||||
|
||||
let result = function () {
|
||||
return Promise.reject(err);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import datetime from 'datetime';
|
||||
import $ from 'jQuery';
|
||||
import globalize from 'globalize';
|
||||
import 'material-icons';
|
||||
|
@ -303,6 +302,7 @@ import 'material-icons';
|
|||
$(document).on('itemsaved', '.metadataEditorPage', function (e, item) {
|
||||
updateEditorNode(this, item);
|
||||
}).on('pagebeforeshow', '.metadataEditorPage', function () {
|
||||
/* eslint-disable-next-line no-unused-expressions */
|
||||
import('css!assets/css/metadataeditor.css');
|
||||
}).on('pagebeforeshow', '.metadataEditorPage', function () {
|
||||
var page = this;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import multiDownload from 'multi-download';
|
||||
|
||||
export function download(items) {
|
||||
|
||||
if (window.NativeShell) {
|
||||
items.map(function (item) {
|
||||
window.NativeShell.downloadFile(item);
|
||||
|
|
|
@ -182,7 +182,6 @@ require(['apphost'], function (appHost) {
|
|||
|
||||
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;
|
||||
|
@ -196,7 +195,6 @@ require(['apphost'], function (appHost) {
|
|||
}
|
||||
|
||||
function raiseEvent(name, key, keyCode) {
|
||||
|
||||
if (!allowInput()) {
|
||||
return;
|
||||
}
|
||||
|
@ -209,7 +207,6 @@ require(['apphost'], function (appHost) {
|
|||
}
|
||||
|
||||
function clickElement(elem) {
|
||||
|
||||
if (!allowInput()) {
|
||||
return;
|
||||
}
|
||||
|
@ -218,10 +215,8 @@ require(['apphost'], function (appHost) {
|
|||
}
|
||||
|
||||
function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRepeatKeyDown, clickonKeyUp) {
|
||||
|
||||
// No-op if oldPressedState === newPressedState
|
||||
if (newPressedState === true) {
|
||||
|
||||
// button down
|
||||
var fire = false;
|
||||
|
||||
|
@ -236,9 +231,7 @@ require(['apphost'], function (appHost) {
|
|||
if (fire && keyCode) {
|
||||
raiseEvent('keydown', key, keyCode);
|
||||
}
|
||||
|
||||
} else if (newPressedState === false && oldPressedState === true) {
|
||||
|
||||
resetThrottle(key);
|
||||
|
||||
// button up
|
||||
|
@ -406,5 +399,4 @@ require(['apphost'], function (appHost) {
|
|||
// and provide input to the DOM navigator.getGamepads API.
|
||||
window.navigator.gamepadInputEmulation = 'gamepad';
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
import browser from 'browser';
|
||||
/* eslint-disable indent */
|
||||
|
||||
export function getDeviceIcon(device) {
|
||||
var baseUrl = 'assets/img/devices/';
|
||||
|
@ -32,6 +31,11 @@ import browser from 'browser';
|
|||
case 'Safari iPad':
|
||||
case 'Safari iPhone':
|
||||
return baseUrl + 'safari.svg';
|
||||
case 'Edge Chromium':
|
||||
case 'Edge Chromium Android':
|
||||
case 'Edge Chromium iPad':
|
||||
case 'Edge Chromium iPhone':
|
||||
return baseUrl + 'edgechromium.svg';
|
||||
case 'Edge':
|
||||
return baseUrl + 'edge.svg';
|
||||
case 'Internet Explorer':
|
||||
|
|
|
@ -41,7 +41,6 @@ import appHost from 'apphost';
|
|||
let commandTimes = {};
|
||||
|
||||
function checkCommandTime(command) {
|
||||
|
||||
const last = commandTimes[command] || 0;
|
||||
const now = new Date().getTime();
|
||||
|
||||
|
@ -54,7 +53,6 @@ import appHost from 'apphost';
|
|||
}
|
||||
|
||||
export function handleCommand(commandName, options) {
|
||||
|
||||
lastInputTime = new Date().getTime();
|
||||
|
||||
let sourceElement = (options ? options.sourceElement : null);
|
||||
|
|
|
@ -155,6 +155,7 @@ export function enable() {
|
|||
function attachGamepadScript(e) {
|
||||
console.log('Gamepad connected! Attaching gamepadtokey.js script');
|
||||
window.removeEventListener('gamepadconnected', attachGamepadScript);
|
||||
/* eslint-disable-next-line no-unused-expressions */
|
||||
import('scripts/gamepadtokey');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,199 +1,216 @@
|
|||
define(['userSettings', 'globalize'], function (userSettings, globalize) {
|
||||
'use strict';
|
||||
import * as userSettings from 'userSettings';
|
||||
import globalize from 'globalize';
|
||||
|
||||
var libraryBrowser = {
|
||||
getSavedQueryKey: function (modifier) {
|
||||
return window.location.href.split('#')[0] + (modifier || '');
|
||||
},
|
||||
loadSavedQueryValues: function (key, query) {
|
||||
var values = userSettings.get(key);
|
||||
export function getSavedQueryKey(modifier) {
|
||||
return window.location.href.split('#')[0] + (modifier || '');
|
||||
}
|
||||
|
||||
if (values) {
|
||||
values = JSON.parse(values);
|
||||
return Object.assign(query, values);
|
||||
}
|
||||
export function loadSavedQueryValues(key, query) {
|
||||
var values = userSettings.get(key);
|
||||
|
||||
return query;
|
||||
},
|
||||
saveQueryValues: function (key, query) {
|
||||
var values = {};
|
||||
if (values) {
|
||||
values = JSON.parse(values);
|
||||
return Object.assign(query, values);
|
||||
}
|
||||
|
||||
if (query.SortBy) {
|
||||
values.SortBy = query.SortBy;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
if (query.SortOrder) {
|
||||
values.SortOrder = query.SortOrder;
|
||||
}
|
||||
export function saveQueryValues(key, query) {
|
||||
var values = {};
|
||||
|
||||
userSettings.set(key, JSON.stringify(values));
|
||||
},
|
||||
saveViewSetting: function (key, value) {
|
||||
userSettings.set(key + '-_view', value);
|
||||
},
|
||||
getSavedView: function (key) {
|
||||
return userSettings.get(key + '-_view');
|
||||
},
|
||||
showLayoutMenu: function (button, currentLayout, views) {
|
||||
var dispatchEvent = true;
|
||||
if (query.SortBy) {
|
||||
values.SortBy = query.SortBy;
|
||||
}
|
||||
|
||||
if (!views) {
|
||||
dispatchEvent = false;
|
||||
views = button.getAttribute('data-layouts');
|
||||
views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard'];
|
||||
}
|
||||
if (query.SortOrder) {
|
||||
values.SortOrder = query.SortOrder;
|
||||
}
|
||||
|
||||
var menuItems = views.map(function (v) {
|
||||
return {
|
||||
name: globalize.translate('Option' + v),
|
||||
id: v,
|
||||
selected: currentLayout == v
|
||||
};
|
||||
});
|
||||
userSettings.set(key, JSON.stringify(values));
|
||||
}
|
||||
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
actionsheet.show({
|
||||
items: menuItems,
|
||||
positionTo: button,
|
||||
callback: function (id) {
|
||||
button.dispatchEvent(new CustomEvent('layoutchange', {
|
||||
detail: {
|
||||
viewStyle: id
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
export function saveViewSetting (key, value) {
|
||||
userSettings.set(key + '-_view', value);
|
||||
}
|
||||
|
||||
if (!dispatchEvent) {
|
||||
if (window.$) {
|
||||
$(button).trigger('layoutchange', [id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
getQueryPagingHtml: function (options) {
|
||||
var startIndex = options.startIndex;
|
||||
var limit = options.limit;
|
||||
var totalRecordCount = options.totalRecordCount;
|
||||
var html = '';
|
||||
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
var showControls = limit < totalRecordCount;
|
||||
export function getSavedView (key) {
|
||||
return userSettings.get(key + '-_view');
|
||||
}
|
||||
|
||||
if (html += '<div class="listPaging">', showControls) {
|
||||
html += '<span style="vertical-align:middle;">';
|
||||
html += globalize.translate('ListPaging', (totalRecordCount ? startIndex + 1 : 0), recordsEnd, totalRecordCount);
|
||||
html += '</span>';
|
||||
}
|
||||
export function showLayoutMenu (button, currentLayout, views) {
|
||||
var dispatchEvent = true;
|
||||
|
||||
if (showControls || options.viewButton || options.filterButton || options.sortButton || options.addLayoutButton) {
|
||||
html += '<div style="display:inline-block;">';
|
||||
if (!views) {
|
||||
dispatchEvent = false;
|
||||
views = button.getAttribute('data-layouts');
|
||||
views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard'];
|
||||
}
|
||||
|
||||
if (showControls) {
|
||||
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>';
|
||||
}
|
||||
var menuItems = views.map(function (v) {
|
||||
return {
|
||||
name: globalize.translate('Option' + v),
|
||||
id: v,
|
||||
selected: currentLayout == v
|
||||
};
|
||||
});
|
||||
|
||||
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 || '') + '\');"><span class="material-icons view_comfy"></span></button>';
|
||||
}
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
actionsheet.show({
|
||||
items: menuItems,
|
||||
positionTo: button,
|
||||
callback: function (id) {
|
||||
button.dispatchEvent(new CustomEvent('layoutchange', {
|
||||
detail: {
|
||||
viewStyle: id
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
|
||||
if (options.sortButton) {
|
||||
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') + '"><span class="material-icons filter_list"></span></button>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
return html += '</div>';
|
||||
},
|
||||
showSortMenu: function (options) {
|
||||
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.StartIndex = 0;
|
||||
|
||||
if (options.callback && changed) {
|
||||
options.callback();
|
||||
}
|
||||
if (!dispatchEvent) {
|
||||
if (window.$) {
|
||||
$(button).trigger('layoutchange', [id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onSortOrderChange() {
|
||||
var newValue = this.value;
|
||||
export function getQueryPagingHtml (options) {
|
||||
var startIndex = options.startIndex;
|
||||
var limit = options.limit;
|
||||
var totalRecordCount = options.totalRecordCount;
|
||||
var html = '';
|
||||
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
var showControls = limit < totalRecordCount;
|
||||
|
||||
if (this.checked) {
|
||||
var changed = options.query.SortOrder != newValue;
|
||||
options.query.SortOrder = newValue;
|
||||
options.query.StartIndex = 0;
|
||||
if (html += '<div class="listPaging">', showControls) {
|
||||
html += '<span style="vertical-align:middle;">';
|
||||
html += globalize.translate('ListPaging', (totalRecordCount ? startIndex + 1 : 0), recordsEnd, totalRecordCount);
|
||||
html += '</span>';
|
||||
}
|
||||
|
||||
if (options.callback && changed) {
|
||||
options.callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (showControls || options.viewButton || options.filterButton || options.sortButton || options.addLayoutButton) {
|
||||
html += '<div style="display:inline-block;">';
|
||||
|
||||
var dlg = dialogHelper.createDialog({
|
||||
removeOnClose: true,
|
||||
modal: false,
|
||||
entryAnimationDuration: 160,
|
||||
exitAnimationDuration: 200
|
||||
});
|
||||
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>';
|
||||
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>';
|
||||
}
|
||||
|
||||
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>';
|
||||
dlg.innerHTML = html;
|
||||
dialogHelper.open(dlg);
|
||||
var sortBys = dlg.querySelectorAll('.menuSortBy');
|
||||
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
sortBys[i].addEventListener('change', onSortByChange);
|
||||
}
|
||||
|
||||
var sortOrders = dlg.querySelectorAll('.menuSortOrder');
|
||||
|
||||
for (i = 0, length = sortOrders.length; i < length; i++) {
|
||||
sortOrders[i].addEventListener('change', onSortOrderChange);
|
||||
}
|
||||
});
|
||||
if (showControls) {
|
||||
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>';
|
||||
}
|
||||
};
|
||||
window.LibraryBrowser = libraryBrowser;
|
||||
return libraryBrowser;
|
||||
});
|
||||
|
||||
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 || '') + '\');"><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') + '"><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') + '"><span class="material-icons filter_list"></span></button>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
return html += '</div>';
|
||||
}
|
||||
|
||||
export function showSortMenu (options) {
|
||||
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.StartIndex = 0;
|
||||
|
||||
if (options.callback && changed) {
|
||||
options.callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onSortOrderChange() {
|
||||
var newValue = this.value;
|
||||
|
||||
if (this.checked) {
|
||||
var changed = options.query.SortOrder != newValue;
|
||||
options.query.SortOrder = newValue;
|
||||
options.query.StartIndex = 0;
|
||||
|
||||
if (options.callback && changed) {
|
||||
options.callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog({
|
||||
removeOnClose: true,
|
||||
modal: false,
|
||||
entryAnimationDuration: 160,
|
||||
exitAnimationDuration: 200
|
||||
});
|
||||
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>';
|
||||
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>';
|
||||
}
|
||||
|
||||
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>';
|
||||
dlg.innerHTML = html;
|
||||
dialogHelper.open(dlg);
|
||||
var sortBys = dlg.querySelectorAll('.menuSortBy');
|
||||
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
sortBys[i].addEventListener('change', onSortByChange);
|
||||
}
|
||||
|
||||
var sortOrders = dlg.querySelectorAll('.menuSortOrder');
|
||||
|
||||
for (i = 0, length = sortOrders.length; i < length; i++) {
|
||||
sortOrders[i].addEventListener('change', onSortOrderChange);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const libraryBrowser = {
|
||||
getSavedQueryKey,
|
||||
loadSavedQueryValues,
|
||||
saveQueryValues,
|
||||
saveViewSetting,
|
||||
getSavedView,
|
||||
showLayoutMenu,
|
||||
getQueryPagingHtml,
|
||||
showSortMenu
|
||||
};
|
||||
|
||||
window.LibraryBrowser = libraryBrowser;
|
||||
|
||||
export default libraryBrowser;
|
||||
|
|
|
@ -229,7 +229,6 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
|||
|
||||
function openMainDrawer() {
|
||||
navDrawerInstance.open();
|
||||
lastOpenTime = new Date().getTime();
|
||||
}
|
||||
|
||||
function onMainDrawerOpened() {
|
||||
|
@ -575,15 +574,12 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
|||
}
|
||||
|
||||
function updateLibraryMenu(user) {
|
||||
// FIXME: Potential equivalent might be
|
||||
// showBySelector(".lnkSyncToOtherDevices", !!user.Policy.EnableContentDownloading);
|
||||
if (!user) {
|
||||
showBySelector('.libraryMenuDownloads', false);
|
||||
showBySelector('.lnkSyncToOtherDevices', false);
|
||||
return void showBySelector('.userMenuOptions', false);
|
||||
}
|
||||
|
||||
// FIXME: Potentially the same as above
|
||||
if (user.Policy.EnableContentDownloading) {
|
||||
showBySelector('.lnkSyncToOtherDevices', true);
|
||||
} else {
|
||||
|
@ -838,7 +834,6 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
|||
var enableLibraryNavDrawerHome = !layoutManager.tv;
|
||||
var skinHeader = document.querySelector('.skinHeader');
|
||||
var requiresUserRefresh = true;
|
||||
var lastOpenTime = new Date().getTime();
|
||||
window.LibraryMenu = {
|
||||
getTopParentId: getTopParentId,
|
||||
onHardwareMenuButtonClick: function () {
|
||||
|
|
|
@ -64,10 +64,7 @@ define(['layoutManager', 'datetime', 'cardBuilder', 'apphost'], function (layout
|
|||
|
||||
for (i = 0, length = groups.length; i < length; i++) {
|
||||
var group = groups[i];
|
||||
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>';
|
||||
|
@ -86,21 +83,21 @@ define(['layoutManager', 'datetime', 'cardBuilder', 'apphost'], function (layout
|
|||
|
||||
html += cardBuilder.getCardsHtml({
|
||||
items: group.items,
|
||||
shape: cardLayout ? getBackdropShape() : enableScrollX() ? 'autoOverflow' : 'autoVertical',
|
||||
shape: getBackdropShape(),
|
||||
showParentTitleOrTitle: true,
|
||||
showAirTime: true,
|
||||
showAirEndTime: true,
|
||||
showChannelName: !cardLayout,
|
||||
cardLayout: cardLayout,
|
||||
centerText: !cardLayout,
|
||||
showChannelName: false,
|
||||
cardLayout: true,
|
||||
centerText: false,
|
||||
action: 'edit',
|
||||
cardFooterAside: 'none',
|
||||
preferThumb: !!cardLayout || 'auto',
|
||||
defaultShape: cardLayout ? null : 'portrait',
|
||||
preferThumb: true,
|
||||
defaultShape: null,
|
||||
coverImage: true,
|
||||
allowBottomPadding: false,
|
||||
overlayText: false,
|
||||
showChannelLogo: cardLayout
|
||||
showChannelLogo: true
|
||||
});
|
||||
html += '</div>';
|
||||
|
||||
|
|
|
@ -11,12 +11,10 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
}
|
||||
|
||||
function notifyApp() {
|
||||
|
||||
inputManager.notifyMouseMove();
|
||||
}
|
||||
|
||||
function removeIdleClasses() {
|
||||
|
||||
var classList = document.body.classList;
|
||||
|
||||
classList.remove('mouseIdle');
|
||||
|
@ -24,7 +22,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
}
|
||||
|
||||
function addIdleClasses() {
|
||||
|
||||
var classList = document.body.classList;
|
||||
|
||||
classList.add('mouseIdle');
|
||||
|
@ -36,7 +33,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
|
||||
var lastPointerMoveData;
|
||||
function onPointerMove(e) {
|
||||
|
||||
var eventX = e.screenX;
|
||||
var eventY = e.screenY;
|
||||
|
||||
|
@ -73,7 +69,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
}
|
||||
|
||||
function onPointerEnter(e) {
|
||||
|
||||
var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
|
||||
|
||||
if (pointerType === 'mouse') {
|
||||
|
@ -87,7 +82,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
}
|
||||
|
||||
function enableFocusWithMouse() {
|
||||
|
||||
if (!layoutManager.tv) {
|
||||
return false;
|
||||
}
|
||||
|
@ -104,7 +98,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
}
|
||||
|
||||
function onMouseInterval() {
|
||||
|
||||
if (!isMouseIdle && mouseIdleTime() >= 5000) {
|
||||
isMouseIdle = true;
|
||||
addIdleClasses();
|
||||
|
@ -114,14 +107,12 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
|
||||
var mouseInterval;
|
||||
function startMouseInterval() {
|
||||
|
||||
if (!mouseInterval) {
|
||||
mouseInterval = setInterval(onMouseInterval, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function stopMouseInterval() {
|
||||
|
||||
var interval = mouseInterval;
|
||||
|
||||
if (interval) {
|
||||
|
@ -133,7 +124,6 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
}
|
||||
|
||||
function initMouse() {
|
||||
|
||||
stopMouseInterval();
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
|
|
|
@ -1,66 +1,65 @@
|
|||
define(['browser'], function (browser) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
|
||||
function fallback(urls) {
|
||||
var i = 0;
|
||||
function fallback(urls) {
|
||||
var i = 0;
|
||||
|
||||
(function createIframe() {
|
||||
var frame = document.createElement('iframe');
|
||||
frame.style.display = 'none';
|
||||
frame.src = urls[i++];
|
||||
document.documentElement.appendChild(frame);
|
||||
(function createIframe() {
|
||||
var frame = document.createElement('iframe');
|
||||
frame.style.display = 'none';
|
||||
frame.src = urls[i++];
|
||||
document.documentElement.appendChild(frame);
|
||||
|
||||
// the download init has to be sequential otherwise IE only use the first
|
||||
var interval = setInterval(function () {
|
||||
if (frame.contentWindow.document.readyState === 'complete' || frame.contentWindow.document.readyState === 'interactive') {
|
||||
clearInterval(interval);
|
||||
// the download init has to be sequential otherwise IE only use the first
|
||||
var interval = setInterval(function () {
|
||||
if (frame.contentWindow.document.readyState === 'complete' || frame.contentWindow.document.readyState === 'interactive') {
|
||||
clearInterval(interval);
|
||||
|
||||
// Safari needs a timeout
|
||||
setTimeout(function () {
|
||||
frame.parentNode.removeChild(frame);
|
||||
}, 1000);
|
||||
// Safari needs a timeout
|
||||
setTimeout(function () {
|
||||
frame.parentNode.removeChild(frame);
|
||||
}, 1000);
|
||||
|
||||
if (i < urls.length) {
|
||||
createIframe();
|
||||
}
|
||||
if (i < urls.length) {
|
||||
createIframe();
|
||||
}
|
||||
}, 100);
|
||||
})();
|
||||
}
|
||||
|
||||
function sameDomain(url) {
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
|
||||
return location.hostname === a.hostname && location.protocol === a.protocol;
|
||||
}
|
||||
|
||||
function download(url) {
|
||||
var a = document.createElement('a');
|
||||
a.download = '';
|
||||
a.href = url;
|
||||
// firefox doesn't support `a.click()`...
|
||||
a.dispatchEvent(new MouseEvent('click'));
|
||||
}
|
||||
|
||||
return function (urls) {
|
||||
if (!urls) {
|
||||
throw new Error('`urls` required');
|
||||
}
|
||||
|
||||
if (typeof document.createElement('a').download === 'undefined') {
|
||||
return fallback(urls);
|
||||
}
|
||||
|
||||
var delay = 0;
|
||||
|
||||
urls.forEach(function (url) {
|
||||
// the download init has to be sequential for firefox if the urls are not on the same domain
|
||||
if (browser.firefox && !sameDomain(url)) {
|
||||
return setTimeout(download.bind(null, url), 100 * ++delay);
|
||||
}
|
||||
}, 100);
|
||||
})();
|
||||
}
|
||||
|
||||
function sameDomain(url) {
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
|
||||
return location.hostname === a.hostname && location.protocol === a.protocol;
|
||||
}
|
||||
|
||||
function download(url) {
|
||||
var a = document.createElement('a');
|
||||
a.download = '';
|
||||
a.href = url;
|
||||
// firefox doesn't support `a.click()`...
|
||||
a.dispatchEvent(new MouseEvent('click'));
|
||||
}
|
||||
|
||||
export default function (urls) {
|
||||
if (!urls) {
|
||||
throw new Error('`urls` required');
|
||||
}
|
||||
|
||||
if (typeof document.createElement('a').download === 'undefined') {
|
||||
return fallback(urls);
|
||||
}
|
||||
|
||||
var delay = 0;
|
||||
|
||||
urls.forEach(function (url) {
|
||||
// the download init has to be sequential for firefox if the urls are not on the same domain
|
||||
if (browser.firefox && !sameDomain(url)) {
|
||||
return setTimeout(download.bind(null, url), 100 * ++delay);
|
||||
}
|
||||
|
||||
download(url);
|
||||
});
|
||||
}
|
||||
|
||||
download(url);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@ import listView from 'listView';
|
|||
import cardBuilder from 'cardBuilder';
|
||||
import libraryMenu from 'libraryMenu';
|
||||
import libraryBrowser from 'libraryBrowser';
|
||||
import appHost from 'apphost';
|
||||
import imageLoader from 'imageLoader';
|
||||
import userSettings from 'userSettings';
|
||||
import 'emby-itemscontainer';
|
||||
|
|
|
@ -13,7 +13,6 @@ define([
|
|||
'listViewStyle',
|
||||
'dashboardcss',
|
||||
'detailtablecss'], function () {
|
||||
|
||||
function defineRoute(newRoute) {
|
||||
var path = newRoute.alias ? newRoute.alias : newRoute.path;
|
||||
console.debug('defining route: ' + path);
|
||||
|
@ -24,77 +23,88 @@ define([
|
|||
console.debug('defining core routes');
|
||||
|
||||
defineRoute({
|
||||
path: '/addserver.html',
|
||||
alias: '/addserver.html',
|
||||
path: '/controllers/session/addServer/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'auth/addserver'
|
||||
controller: 'session/addServer/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/selectserver.html',
|
||||
alias: '/selectserver.html',
|
||||
path: '/controllers/session/selectServer/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'auth/selectserver',
|
||||
controller: 'session/selectServer/index',
|
||||
type: 'selectserver'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/login.html',
|
||||
alias: '/login.html',
|
||||
path: '/controllers/session/login/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'auth/login',
|
||||
controller: 'session/login/index',
|
||||
type: 'login'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/forgotpassword.html',
|
||||
alias: '/forgotpassword.html',
|
||||
path: '/controllers/session/forgotPassword/index.html',
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'auth/forgotpassword'
|
||||
controller: 'session/forgotPassword/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/forgotpasswordpin.html',
|
||||
alias: '/forgotpasswordpin.html',
|
||||
path: '/controllers/session/redeemPassword/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
startup: true,
|
||||
controller: 'auth/forgotpasswordpin'
|
||||
controller: 'session/redeemPassword/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: '/mypreferencesmenu.html',
|
||||
alias: '/mypreferencesmenu.html',
|
||||
path: '/controllers/user/menu/index.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/menu'
|
||||
controller: 'user/menu/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/myprofile.html',
|
||||
alias: '/myprofile.html',
|
||||
path: '/controllers/user/profile/index.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/profile'
|
||||
controller: 'user/profile/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/mypreferencesdisplay.html',
|
||||
alias: '/mypreferencesdisplay.html',
|
||||
path: '/controllers/user/display/index.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/display'
|
||||
controller: 'user/display/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/mypreferenceshome.html',
|
||||
alias: '/mypreferenceshome.html',
|
||||
path: '/controllers/user/home/index.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/home'
|
||||
controller: 'user/home/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/mypreferencesplayback.html',
|
||||
alias: '/mypreferencesplayback.html',
|
||||
path: '/controllers/user/playback/index.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/playback'
|
||||
controller: 'user/playback/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/mypreferencessubtitles.html',
|
||||
alias: '/mypreferencessubtitles.html',
|
||||
path: '/controllers/user/subtitles/index.html',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
controller: 'user/subtitles'
|
||||
controller: 'user/subtitles/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
|
@ -140,10 +150,11 @@ define([
|
|||
controller: 'dashboard/dlna/profiles'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/addplugin.html',
|
||||
alias: '/addplugin.html',
|
||||
path: '/controllers/dashboard/plugins/add/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/add'
|
||||
controller: 'dashboard/plugins/add/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/library.html',
|
||||
|
@ -192,14 +203,16 @@ define([
|
|||
controller: 'dashboard/metadatanfo'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/notificationsetting.html',
|
||||
alias: '/notificationsetting.html',
|
||||
path: '/controllers/dashboard/notifications/notification/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/notifications/notification'
|
||||
controller: 'dashboard/notifications/notification/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/notificationsettings.html',
|
||||
controller: 'dashboard/notifications/notifications',
|
||||
alias: '/notificationsettings.html',
|
||||
path: '/controllers/dashboard/notifications/notifications/index.html',
|
||||
controller: 'dashboard/notifications/notifications/index',
|
||||
autoFocus: false,
|
||||
roles: 'admin'
|
||||
});
|
||||
|
@ -210,16 +223,18 @@ define([
|
|||
controller: 'dashboard/playback'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/availableplugins.html',
|
||||
alias: '/availableplugins.html',
|
||||
path: '/controllers/dashboard/plugins/available/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/available'
|
||||
controller: 'dashboard/plugins/available/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/repositories.html',
|
||||
alias: '/repositories.html',
|
||||
path: '/controllers/dashboard/plugins/repositories/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/repositories'
|
||||
controller: 'dashboard/plugins/repositories/index'
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
|
@ -288,10 +303,11 @@ define([
|
|||
transition: 'fade'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/installedplugins.html',
|
||||
alias: '/installedplugins.html',
|
||||
path: '/controllers/dashboard/plugins/installed/index.html',
|
||||
autoFocus: false,
|
||||
roles: 'admin',
|
||||
controller: 'dashboard/plugins/installed'
|
||||
controller: 'dashboard/plugins/installed/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/scheduledtask.html',
|
||||
|
@ -367,16 +383,18 @@ define([
|
|||
});
|
||||
|
||||
defineRoute({
|
||||
path: '/wizardremoteaccess.html',
|
||||
alias: '/wizardremoteaccess.html',
|
||||
path: '/controllers/wizard/remote/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'wizard/remoteaccess'
|
||||
controller: 'wizard/remote/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/wizardfinish.html',
|
||||
alias: '/wizardfinish.html',
|
||||
path: '/controllers/wizard/finish/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'wizard/finish'
|
||||
controller: 'wizard/finish/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/wizardlibrary.html',
|
||||
|
@ -385,28 +403,32 @@ define([
|
|||
controller: 'dashboard/mediaLibrary'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/wizardsettings.html',
|
||||
alias: '/wizardsettings.html',
|
||||
path: '/controllers/wizard/settings/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'wizard/settings'
|
||||
controller: 'wizard/settings/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/wizardstart.html',
|
||||
alias: '/wizardstart.html',
|
||||
path: '/controllers/wizard/start/index.html',
|
||||
autoFocus: false,
|
||||
anonymous: true,
|
||||
controller: 'wizard/start'
|
||||
controller: 'wizard/start/index'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/wizarduser.html',
|
||||
controller: 'wizard/user',
|
||||
alias: '/wizarduser.html',
|
||||
path: '/controllers/wizard/user/index.html',
|
||||
controller: 'wizard/user/index',
|
||||
autoFocus: false,
|
||||
anonymous: true
|
||||
});
|
||||
|
||||
defineRoute({
|
||||
path: '/videoosd.html',
|
||||
alias: '/video',
|
||||
path: '/controllers/playback/video/index.html',
|
||||
transition: 'fade',
|
||||
controller: 'playback/videoosd',
|
||||
controller: 'playback/video/index',
|
||||
autoFocus: false,
|
||||
type: 'video-osd',
|
||||
supportsThemeMedia: true,
|
||||
|
@ -414,8 +436,9 @@ define([
|
|||
enableMediaControl: false
|
||||
});
|
||||
defineRoute({
|
||||
path: '/nowplaying.html',
|
||||
controller: 'playback/nowplaying',
|
||||
alias: '/queue',
|
||||
path: '/controllers/playback/queue/index.html',
|
||||
controller: 'playback/queue/index',
|
||||
autoFocus: false,
|
||||
transition: 'fade',
|
||||
fullscreen: true,
|
||||
|
|
|
@ -2,7 +2,6 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
|
|||
'use strict';
|
||||
|
||||
function getBoundingClientRect(elem) {
|
||||
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
// If we don't have gBCR, just use 0,0 rather than error
|
||||
if (elem.getBoundingClientRect) {
|
||||
|
@ -13,7 +12,6 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
|
|||
}
|
||||
|
||||
function getPosition(scrollContainer, item, horizontal) {
|
||||
|
||||
var slideeOffset = getBoundingClientRect(scrollContainer);
|
||||
var itemOffset = getBoundingClientRect(item);
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ define([], function () {
|
|||
} else {
|
||||
window.open(url, target || '_blank');
|
||||
}
|
||||
|
||||
},
|
||||
enableFullscreen: function () {
|
||||
if (window.NativeShell) {
|
||||
|
|
|
@ -14,7 +14,7 @@ function getWindowLocationSearch(win) {
|
|||
return search || '';
|
||||
}
|
||||
|
||||
function getParameterByName(name, url) {
|
||||
window.getParameterByName = function (name, url) {
|
||||
'use strict';
|
||||
|
||||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
|
@ -27,7 +27,7 @@ function getParameterByName(name, url) {
|
|||
}
|
||||
|
||||
return decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||
}
|
||||
};
|
||||
|
||||
function pageClassOn(eventName, className, fn) {
|
||||
'use strict';
|
||||
|
@ -41,7 +41,7 @@ function pageClassOn(eventName, className, fn) {
|
|||
});
|
||||
}
|
||||
|
||||
function pageIdOn(eventName, id, fn) {
|
||||
window.pageIdOn = function(eventName, id, fn) {
|
||||
'use strict';
|
||||
|
||||
document.addEventListener(eventName, function (event) {
|
||||
|
@ -51,7 +51,7 @@ function pageIdOn(eventName, id, fn) {
|
|||
fn.call(target, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var Dashboard = {
|
||||
getCurrentUser: function () {
|
||||
|
@ -236,9 +236,7 @@ var Dashboard = {
|
|||
|
||||
var AppInfo = {};
|
||||
|
||||
!function () {
|
||||
'use strict';
|
||||
|
||||
function initClient() {
|
||||
function defineConnectionManager(connectionManager) {
|
||||
window.ConnectionManager = connectionManager;
|
||||
define('connectionManager', [], function () {
|
||||
|
@ -494,7 +492,7 @@ var AppInfo = {};
|
|||
if (appHost.supports('remotecontrol')) {
|
||||
list.push('plugins/sessionPlayer/plugin');
|
||||
|
||||
if (browser.chrome || browser.opera) {
|
||||
if (browser.chrome || browser.edgeChromium || browser.opera) {
|
||||
list.push('plugins/chromecastPlayer/plugin');
|
||||
}
|
||||
}
|
||||
|
@ -679,7 +677,6 @@ var AppInfo = {};
|
|||
'howler',
|
||||
'native-promise-only',
|
||||
'resize-observer-polyfill',
|
||||
'shaka',
|
||||
'swiper',
|
||||
'queryString',
|
||||
'sortable',
|
||||
|
@ -785,7 +782,6 @@ var AppInfo = {};
|
|||
define('multiSelect', [componentsPath + '/multiSelect/multiSelect'], returnFirstDependency);
|
||||
define('alphaPicker', [componentsPath + '/alphaPicker/alphaPicker'], returnFirstDependency);
|
||||
define('tabbedView', [componentsPath + '/tabbedview/tabbedview'], returnFirstDependency);
|
||||
define('itemsTab', [componentsPath + '/tabbedview/itemstab'], returnFirstDependency);
|
||||
define('collectionEditor', [componentsPath + '/collectionEditor/collectionEditor'], returnFirstDependency);
|
||||
define('playlistEditor', [componentsPath + '/playlisteditor/playlisteditor'], returnFirstDependency);
|
||||
define('recordingCreator', [componentsPath + '/recordingcreator/recordingcreator'], returnFirstDependency);
|
||||
|
@ -890,7 +886,7 @@ var AppInfo = {};
|
|||
};
|
||||
|
||||
appRouter.showVideoOsd = function () {
|
||||
return Dashboard.navigate('videoosd.html');
|
||||
return Dashboard.navigate('video');
|
||||
};
|
||||
|
||||
appRouter.showSelectServer = function () {
|
||||
|
@ -1127,7 +1123,9 @@ var AppInfo = {};
|
|||
})();
|
||||
|
||||
return onWebComponentsReady();
|
||||
}();
|
||||
}
|
||||
|
||||
initClient();
|
||||
|
||||
pageClassOn('viewshow', 'standalonePage', function () {
|
||||
document.querySelector('.skinHeader').classList.add('noHeaderRight');
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
import events from 'events';
|
||||
import * as userSettings from 'userSettings';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import connectionManager from 'connectionManager';
|
||||
import globalize from 'globalize';
|
||||
|
|
|
@ -7,7 +7,6 @@ function getTouches(e) {
|
|||
|
||||
class TouchHelper {
|
||||
constructor(elem, options) {
|
||||
|
||||
options = options || {};
|
||||
let touchTarget;
|
||||
let touchStartX;
|
||||
|
@ -24,7 +23,6 @@ class TouchHelper {
|
|||
const excludeTagNames = options.ignoreTagNames || [];
|
||||
|
||||
const touchStart = function (e) {
|
||||
|
||||
const touch = getTouches(e)[0];
|
||||
touchTarget = null;
|
||||
touchStartX = 0;
|
||||
|
@ -34,7 +32,6 @@ class TouchHelper {
|
|||
thresholdYMet = false;
|
||||
|
||||
if (touch) {
|
||||
|
||||
const currentTouchTarget = touch.target;
|
||||
|
||||
if (dom.parentWithTag(currentTouchTarget, excludeTagNames)) {
|
||||
|
@ -48,7 +45,6 @@ class TouchHelper {
|
|||
};
|
||||
|
||||
const touchEnd = function (e) {
|
||||
|
||||
const isTouchMove = e.type === 'touchmove';
|
||||
|
||||
if (touchTarget) {
|
||||
|
@ -81,7 +77,6 @@ class TouchHelper {
|
|||
} else if (deltaX < (0 - swipeXThreshold) && Math.abs(deltaY) < swipeXMaxY) {
|
||||
events.trigger(self, 'swipeleft', [touchTarget]);
|
||||
} else if ((deltaY < (0 - swipeYThreshold) || thresholdYMet) && Math.abs(deltaX) < swipeXMaxY) {
|
||||
|
||||
thresholdYMet = true;
|
||||
|
||||
events.trigger(self, 'swipeup', [touchTarget, {
|
||||
|
@ -139,7 +134,6 @@ class TouchHelper {
|
|||
});
|
||||
}
|
||||
destroy() {
|
||||
|
||||
const elem = this.elem;
|
||||
|
||||
if (elem) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue