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

Fix indentation issues

This commit is contained in:
Bill Thornton 2023-04-19 01:56:05 -04:00
parent 52c8cffc82
commit f2726653ae
120 changed files with 30271 additions and 30631 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,289 +1,286 @@
import globalize from './globalize';
/* eslint-disable indent */
export function parseISO8601Date(s, toLocal) {
// parenthese matches:
// year month day hours minutes seconds
// dotmilliseconds
// tzstring plusminus hours minutes
const re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/;
export function parseISO8601Date(s, toLocal) {
// parenthese matches:
// year month day hours minutes seconds
// dotmilliseconds
// tzstring plusminus hours minutes
const re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/;
const d = s.match(re);
const d = s.match(re);
// "2010-12-07T11:00:00.000-09:00" parses to:
// ["2010-12-07T11:00:00.000-09:00", "2010", "12", "07", "11",
// "00", "00", ".000", "-09:00", "-", "09", "00"]
// "2010-12-07T11:00:00.000Z" parses to:
// ["2010-12-07T11:00:00.000Z", "2010", "12", "07", "11",
// "00", "00", ".000", "Z", undefined, undefined, undefined]
// "2010-12-07T11:00:00.000-09:00" parses to:
// ["2010-12-07T11:00:00.000-09:00", "2010", "12", "07", "11",
// "00", "00", ".000", "-09:00", "-", "09", "00"]
// "2010-12-07T11:00:00.000Z" parses to:
// ["2010-12-07T11:00:00.000Z", "2010", "12", "07", "11",
// "00", "00", ".000", "Z", undefined, undefined, undefined]
if (!d) {
throw new Error("Couldn't parse ISO 8601 date string '" + s + "'");
}
// parse strings, leading zeros into proper ints
const a = [1, 2, 3, 4, 5, 6, 10, 11];
for (const i in a) {
d[a[i]] = parseInt(d[a[i]], 10);
}
d[7] = parseFloat(d[7]);
// Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]])
// note that month is 0-11, not 1-12
// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC
let ms = Date.UTC(d[1], d[2] - 1, d[3], d[4], d[5], d[6]);
// if there are milliseconds, add them
if (d[7] > 0) {
ms += Math.round(d[7] * 1000);
}
// if there's a timezone, calculate it
if (d[8] !== 'Z' && d[10]) {
let offset = d[10] * 60 * 60 * 1000;
if (d[11]) {
offset += d[11] * 60 * 1000;
}
if (d[9] === '-') {
ms -= offset;
} else {
ms += offset;
}
} else if (toLocal === false) {
ms += new Date().getTimezoneOffset() * 60000;
}
return new Date(ms);
if (!d) {
throw new Error("Couldn't parse ISO 8601 date string '" + s + "'");
}
/**
// parse strings, leading zeros into proper ints
const a = [1, 2, 3, 4, 5, 6, 10, 11];
for (const i in a) {
d[a[i]] = parseInt(d[a[i]], 10);
}
d[7] = parseFloat(d[7]);
// Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]])
// note that month is 0-11, not 1-12
// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC
let ms = Date.UTC(d[1], d[2] - 1, d[3], d[4], d[5], d[6]);
// if there are milliseconds, add them
if (d[7] > 0) {
ms += Math.round(d[7] * 1000);
}
// if there's a timezone, calculate it
if (d[8] !== 'Z' && d[10]) {
let offset = d[10] * 60 * 60 * 1000;
if (d[11]) {
offset += d[11] * 60 * 1000;
}
if (d[9] === '-') {
ms -= offset;
} else {
ms += offset;
}
} else if (toLocal === false) {
ms += new Date().getTimezoneOffset() * 60000;
}
return new Date(ms);
}
/**
* Return a string in '{}h {}m' format for duration.
* @param {number} ticks - Duration in ticks.
*/
export function getDisplayDuration(ticks) {
const totalMinutes = Math.round(ticks / 600000000) || 1;
const totalHours = Math.floor(totalMinutes / 60);
const remainderMinutes = totalMinutes % 60;
const result = [];
if (totalHours > 0) {
result.push(`${totalHours}h`);
}
result.push(`${remainderMinutes}m`);
return result.join(' ');
export function getDisplayDuration(ticks) {
const totalMinutes = Math.round(ticks / 600000000) || 1;
const totalHours = Math.floor(totalMinutes / 60);
const remainderMinutes = totalMinutes % 60;
const result = [];
if (totalHours > 0) {
result.push(`${totalHours}h`);
}
result.push(`${remainderMinutes}m`);
return result.join(' ');
}
export function getDisplayRunningTime(ticks) {
const ticksPerHour = 36000000000;
const ticksPerMinute = 600000000;
const ticksPerSecond = 10000000;
const parts = [];
let hours = ticks / ticksPerHour;
hours = Math.floor(hours);
if (hours) {
parts.push(hours.toLocaleString(globalize.getCurrentDateTimeLocale()));
}
export function getDisplayRunningTime(ticks) {
const ticksPerHour = 36000000000;
const ticksPerMinute = 600000000;
const ticksPerSecond = 10000000;
ticks -= (hours * ticksPerHour);
const parts = [];
let minutes = ticks / ticksPerMinute;
minutes = Math.floor(minutes);
let hours = ticks / ticksPerHour;
hours = Math.floor(hours);
ticks -= (minutes * ticksPerMinute);
if (hours) {
parts.push(hours.toLocaleString(globalize.getCurrentDateTimeLocale()));
}
if (minutes < 10 && hours) {
minutes = (0).toLocaleString(globalize.getCurrentDateTimeLocale()) + minutes.toLocaleString(globalize.getCurrentDateTimeLocale());
} else {
minutes = minutes.toLocaleString(globalize.getCurrentDateTimeLocale());
}
parts.push(minutes);
ticks -= (hours * ticksPerHour);
let seconds = ticks / ticksPerSecond;
seconds = Math.floor(seconds);
let minutes = ticks / ticksPerMinute;
minutes = Math.floor(minutes);
if (seconds < 10) {
seconds = (0).toLocaleString(globalize.getCurrentDateTimeLocale()) + seconds.toLocaleString(globalize.getCurrentDateTimeLocale());
} else {
seconds = seconds.toLocaleString(globalize.getCurrentDateTimeLocale());
}
parts.push(seconds);
ticks -= (minutes * ticksPerMinute);
return parts.join(':');
}
if (minutes < 10 && hours) {
minutes = (0).toLocaleString(globalize.getCurrentDateTimeLocale()) + minutes.toLocaleString(globalize.getCurrentDateTimeLocale());
} else {
minutes = minutes.toLocaleString(globalize.getCurrentDateTimeLocale());
}
parts.push(minutes);
const toLocaleTimeStringSupportsLocales = function () {
try {
new Date().toLocaleTimeString('i');
} catch (e) {
return e.name === 'RangeError';
}
return false;
}();
let seconds = ticks / ticksPerSecond;
seconds = Math.floor(seconds);
function getOptionList(options) {
const list = [];
if (seconds < 10) {
seconds = (0).toLocaleString(globalize.getCurrentDateTimeLocale()) + seconds.toLocaleString(globalize.getCurrentDateTimeLocale());
} else {
seconds = seconds.toLocaleString(globalize.getCurrentDateTimeLocale());
}
parts.push(seconds);
return parts.join(':');
for (const i in options) {
list.push({
name: i,
value: options[i]
});
}
const toLocaleTimeStringSupportsLocales = function () {
return list;
}
export function toLocaleString(date, options) {
if (!date) {
throw new Error('date cannot be null');
}
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleString(currentLocale, options);
}
}
return date.toLocaleString();
}
export function toLocaleDateString(date, options) {
if (!date) {
throw new Error('date cannot be null');
}
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleDateString(currentLocale, options);
}
}
// This is essentially a hard-coded polyfill
const optionList = getOptionList(options);
if (optionList.length === 1 && optionList[0].name === 'weekday') {
const weekday = [];
weekday[0] = 'Sun';
weekday[1] = 'Mon';
weekday[2] = 'Tue';
weekday[3] = 'Wed';
weekday[4] = 'Thu';
weekday[5] = 'Fri';
weekday[6] = 'Sat';
return weekday[date.getDay()];
}
return date.toLocaleDateString();
}
export function toLocaleTimeString(date, options) {
if (!date) {
throw new Error('date cannot be null');
}
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleTimeString(currentLocale, options);
}
}
return date.toLocaleTimeString();
}
export function getDisplayTime(date) {
if (!date) {
throw new Error('date cannot be null');
}
if ((typeof date).toString().toLowerCase() === 'string') {
try {
new Date().toLocaleTimeString('i');
} catch (e) {
return e.name === 'RangeError';
date = parseISO8601Date(date, true);
} catch (err) {
return date;
}
return false;
}();
function getOptionList(options) {
const list = [];
for (const i in options) {
list.push({
name: i,
value: options[i]
});
}
return list;
}
export function toLocaleString(date, options) {
if (!date) {
throw new Error('date cannot be null');
}
if (toLocaleTimeStringSupportsLocales) {
return toLocaleTimeString(date, {
options = options || {};
hour: 'numeric',
minute: '2-digit'
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleString(currentLocale, options);
}
}
return date.toLocaleString();
});
}
export function toLocaleDateString(date, options) {
if (!date) {
throw new Error('date cannot be null');
let time = toLocaleTimeString(date);
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';
if (!hour) {
hour = 12;
}
let minutes = date.getMinutes();
if (minutes < 10) {
minutes = '0' + minutes;
}
options = options || {};
minutes = ':' + minutes;
time = hour + minutes + suffix;
} else {
const timeParts = time.split(':');
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleDateString(currentLocale, options);
}
// Trim off seconds
if (timeParts.length > 2) {
// setting to 2 also handles '21:00:28 GMT+9:30'
timeParts.length = 2;
time = timeParts.join(':');
}
// This is essentially a hard-coded polyfill
const optionList = getOptionList(options);
if (optionList.length === 1 && optionList[0].name === 'weekday') {
const weekday = [];
weekday[0] = 'Sun';
weekday[1] = 'Mon';
weekday[2] = 'Tue';
weekday[3] = 'Wed';
weekday[4] = 'Thu';
weekday[5] = 'Fri';
weekday[6] = 'Sat';
return weekday[date.getDay()];
}
return date.toLocaleDateString();
}
export function toLocaleTimeString(date, options) {
if (!date) {
throw new Error('date cannot be null');
}
return time;
}
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
const currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleTimeString(currentLocale, options);
}
}
return date.toLocaleTimeString();
export function isRelativeDay(date, offsetInDays) {
if (!date) {
throw new Error('date cannot be null');
}
export function getDisplayTime(date) {
if (!date) {
throw new Error('date cannot be null');
}
const yesterday = new Date();
const day = yesterday.getDate() + offsetInDays;
if ((typeof date).toString().toLowerCase() === 'string') {
try {
date = parseISO8601Date(date, true);
} catch (err) {
return date;
}
}
yesterday.setDate(day); // automatically adjusts month/year appropriately
if (toLocaleTimeStringSupportsLocales) {
return toLocaleTimeString(date, {
return date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day;
}
hour: 'numeric',
minute: '2-digit'
});
}
let time = toLocaleTimeString(date);
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';
if (!hour) {
hour = 12;
}
let minutes = date.getMinutes();
if (minutes < 10) {
minutes = '0' + minutes;
}
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(':');
}
}
return time;
export default {
parseISO8601Date: parseISO8601Date,
getDisplayRunningTime: getDisplayRunningTime,
getDisplayDuration,
toLocaleDateString: toLocaleDateString,
toLocaleString: toLocaleString,
getDisplayTime: getDisplayTime,
isRelativeDay: isRelativeDay,
toLocaleTimeString: toLocaleTimeString,
supportsLocalization: function () {
return toLocaleTimeStringSupportsLocales;
}
};
export function isRelativeDay(date, offsetInDays) {
if (!date) {
throw new Error('date cannot be null');
}
const yesterday = new Date();
const day = yesterday.getDate() + offsetInDays;
yesterday.setDate(day); // automatically adjusts month/year appropriately
return date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day;
}
export default {
parseISO8601Date: parseISO8601Date,
getDisplayRunningTime: getDisplayRunningTime,
getDisplayDuration,
toLocaleDateString: toLocaleDateString,
toLocaleString: toLocaleString,
getDisplayTime: getDisplayTime,
isRelativeDay: isRelativeDay,
toLocaleTimeString: toLocaleTimeString,
supportsLocalization: function () {
return toLocaleTimeStringSupportsLocales;
}
};
/* eslint-enable indent */

View file

@ -1,272 +1,269 @@
/* 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;
export function parentWithAttribute(elem, name, value) {
while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) {
elem = elem.parentNode;
if (!elem || !elem.getAttribute) {
return null;
}
if (!elem || !elem.getAttribute) {
return null;
}
return elem;
}
/**
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;
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;
}
function containsAnyClass(classList, classNames) {
for (let i = 0, length = classNames.length; i < length; i++) {
if (classList.contains(classNames[i])) {
return true;
}
return false;
}
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;
export function parentWithClass(elem, classNames) {
// accept both string and array passed in
if (!Array.isArray(classNames)) {
classNames = [classNames];
}
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');
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);
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);
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;
let windowSize;
/**
/**
* Flag of event listener bound.
*/
let windowSizeEventsBound;
let windowSizeEventsBound;
/**
/**
* Resets cached window size.
*/
function clearWindowSize() {
windowSize = null;
}
function clearWindowSize() {
windowSize = null;
}
/**
/**
* @typedef {Object} windowSize
* @property {number} innerHeight - window innerHeight.
* @property {number} innerWidth - window innerWidth.
*/
/**
/**
* Returns window size.
* @returns {windowSize} Window size.
*/
export function getWindowSize() {
if (!windowSize) {
windowSize = {
innerHeight: window.innerHeight,
innerWidth: window.innerWidth
};
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 });
}
if (!windowSizeEventsBound) {
windowSizeEventsBound = true;
addEventListener(window, 'orientationchange', clearWindowSize, { passive: true });
addEventListener(window, 'resize', clearWindowSize, { passive: true });
}
return windowSize;
}
/**
return windowSize;
}
/**
* Standard screen widths.
*/
const standardWidths = [480, 720, 1280, 1440, 1920, 2560, 3840, 5120, 7680];
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;
export function getScreenWidth() {
let width = window.innerWidth;
const height = window.innerHeight;
if (height > width) {
width = height * (16.0 / 9.0);
}
standardWidths.sort((a, b) => Math.abs(width - a) - Math.abs(width - b));
return standardWidths[0];
if (height > width) {
width = height * (16.0 / 9.0);
}
/**
standardWidths.sort((a, b) => Math.abs(width - a) - Math.abs(width - b));
return standardWidths[0];
}
/**
* Name of animation end event.
*/
let _animationEvent;
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 (const t in animations) {
if (el.style[t] !== undefined) {
_animationEvent = animations[t];
return animations[t];
}
}
_animationEvent = 'animationend';
export function whichAnimationEvent() {
if (_animationEvent) {
return _animationEvent;
}
/**
const el = document.createElement('div');
const animations = {
'animation': 'animationend',
'OAnimation': 'oAnimationEnd',
'MozAnimation': 'animationend',
'WebkitAnimation': 'webkitAnimationEnd'
};
for (const 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');
}
export function whichAnimationCancelEvent() {
return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel');
}
/**
/**
* Name of transition end event.
*/
let _transitionEvent;
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 (const t in transitions) {
if (el.style[t] !== undefined) {
_transitionEvent = transitions[t];
return transitions[t];
}
}
_transitionEvent = 'transitionend';
export function whichTransitionEvent() {
if (_transitionEvent) {
return _transitionEvent;
}
/* eslint-enable indent */
const el = document.createElement('div');
const transitions = {
'transition': 'transitionend',
'OTransition': 'oTransitionEnd',
'MozTransition': 'transitionend',
'WebkitTransition': 'webkitTransitionEnd'
};
for (const t in transitions) {
if (el.style[t] !== undefined) {
_transitionEvent = transitions[t];
return transitions[t];
}
}
_transitionEvent = 'transitionend';
return _transitionEvent;
}
/**
* Sets title and ARIA-label of element.

View file

@ -5,338 +5,335 @@ import 'material-design-icons-iconfont';
import Dashboard from '../utils/dashboard';
import { getParameterByName } from '../utils/url.ts';
/* eslint-disable indent */
function getNode(item, folderState, selected) {
const htmlName = getNodeInnerHtml(item);
const node = {
id: item.Id,
text: htmlName,
state: {
opened: item.IsFolder && folderState == 'open',
selected: selected
},
li_attr: {
serveritemtype: item.Type,
collectiontype: item.CollectionType
}
};
if (item.IsFolder) {
node.children = [{
text: 'Loading...',
icon: false
}];
node.icon = false;
} else {
node.icon = false;
}
if (node.state.opened) {
node.li_attr.loadedFromServer = true;
}
if (selected) {
selectedNodeId = item.Id;
}
return node;
}
function getNode(item, folderState, selected) {
const htmlName = getNodeInnerHtml(item);
const node = {
id: item.Id,
text: htmlName,
function getNodeInnerHtml(item) {
let name = item.Name;
if (item.Number) {
name = item.Number + ' - ' + name;
}
if (item.IndexNumber != null && item.Type != 'Season') {
name = item.IndexNumber + ' - ' + name;
}
let htmlName = "<div class='editorNode'>";
if (item.IsFolder) {
htmlName += '<span class="material-icons metadataSidebarIcon folder" aria-hidden="true"></span>';
} else if (item.MediaType === 'Video') {
htmlName += '<span class="material-icons metadataSidebarIcon movie" aria-hidden="true"></span>';
} else if (item.MediaType === 'Audio') {
htmlName += '<span class="material-icons metadataSidebarIcon audiotrack" aria-hidden="true"></span>';
} else if (item.Type === 'TvChannel') {
htmlName += '<span class="material-icons metadataSidebarIcon live_tv" aria-hidden="true"></span>';
} else if (item.MediaType === 'Photo') {
htmlName += '<span class="material-icons metadataSidebarIcon photo" aria-hidden="true"></span>';
} else if (item.MediaType === 'Book') {
htmlName += '<span class="material-icons metadataSidebarIcon book" aria-hidden="true"></span>';
}
if (item.LockData) {
htmlName += '<span class="material-icons metadataSidebarIcon lock" aria-hidden="true"></span>';
}
htmlName += escapeHtml(name);
htmlName += '</div>';
return htmlName;
}
function loadChildrenOfRootNode(page, scope, callback) {
ApiClient.getLiveTvChannels({
limit: 0
}).then(function (result) {
const nodes = [];
nodes.push({
id: 'MediaFolders',
text: globalize.translate('HeaderMediaFolders'),
state: {
opened: item.IsFolder && folderState == 'open',
selected: selected
opened: true
},
li_attr: {
serveritemtype: item.Type,
collectiontype: item.CollectionType
}
};
if (item.IsFolder) {
node.children = [{
text: 'Loading...',
icon: false
}];
node.icon = false;
} else {
node.icon = false;
}
if (node.state.opened) {
node.li_attr.loadedFromServer = true;
}
if (selected) {
selectedNodeId = item.Id;
}
return node;
}
function getNodeInnerHtml(item) {
let name = item.Name;
if (item.Number) {
name = item.Number + ' - ' + name;
}
if (item.IndexNumber != null && item.Type != 'Season') {
name = item.IndexNumber + ' - ' + name;
}
let htmlName = "<div class='editorNode'>";
if (item.IsFolder) {
htmlName += '<span class="material-icons metadataSidebarIcon folder" aria-hidden="true"></span>';
} else if (item.MediaType === 'Video') {
htmlName += '<span class="material-icons metadataSidebarIcon movie" aria-hidden="true"></span>';
} else if (item.MediaType === 'Audio') {
htmlName += '<span class="material-icons metadataSidebarIcon audiotrack" aria-hidden="true"></span>';
} else if (item.Type === 'TvChannel') {
htmlName += '<span class="material-icons metadataSidebarIcon live_tv" aria-hidden="true"></span>';
} else if (item.MediaType === 'Photo') {
htmlName += '<span class="material-icons metadataSidebarIcon photo" aria-hidden="true"></span>';
} else if (item.MediaType === 'Book') {
htmlName += '<span class="material-icons metadataSidebarIcon book" aria-hidden="true"></span>';
}
if (item.LockData) {
htmlName += '<span class="material-icons metadataSidebarIcon lock" aria-hidden="true"></span>';
}
htmlName += escapeHtml(name);
htmlName += '</div>';
return htmlName;
}
function loadChildrenOfRootNode(page, scope, callback) {
ApiClient.getLiveTvChannels({
limit: 0
}).then(function (result) {
const nodes = [];
itemtype: 'mediafolders',
loadedFromServer: true
},
icon: false
});
if (result.TotalRecordCount) {
nodes.push({
id: 'MediaFolders',
text: globalize.translate('HeaderMediaFolders'),
id: 'livetv',
text: globalize.translate('LiveTV'),
state: {
opened: true
opened: false
},
li_attr: {
itemtype: 'mediafolders',
loadedFromServer: true
itemtype: 'livetv'
},
children: [{
text: 'Loading...',
icon: false
}],
icon: false
});
if (result.TotalRecordCount) {
nodes.push({
id: 'livetv',
text: globalize.translate('LiveTV'),
state: {
opened: false
},
li_attr: {
itemtype: 'livetv'
},
children: [{
text: 'Loading...',
icon: false
}],
icon: false
});
}
callback.call(scope, nodes);
nodesToLoad.push('MediaFolders');
});
}
function loadLiveTvChannels(service, openItems, callback) {
ApiClient.getLiveTvChannels({
ServiceName: service,
AddCurrentProgram: false
}).then(function (result) {
const nodes = result.Items.map(function (i) {
const state = openItems.indexOf(i.Id) == -1 ? 'closed' : 'open';
return getNode(i, state, false);
});
callback(nodes);
});
}
function loadMediaFolders(page, scope, openItems, callback) {
ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders')).then(function (result) {
const nodes = result.Items.map(function (n) {
const state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open';
return getNode(n, state, false);
});
callback.call(scope, nodes);
for (let i = 0, length = nodes.length; i < length; i++) {
if (nodes[i].state.opened) {
nodesToLoad.push(nodes[i].id);
}
}
});
}
function loadNode(page, scope, node, openItems, selectedId, currentUser, callback) {
const id = node.id;
if (id == '#') {
loadChildrenOfRootNode(page, scope, callback);
return;
}
if (id == 'livetv') {
loadLiveTvChannels(id, openItems, callback);
return;
}
if (id == 'MediaFolders') {
loadMediaFolders(page, scope, openItems, callback);
return;
}
const query = {
ParentId: id,
Fields: 'Settings',
IsVirtualUnaired: false,
IsMissing: false,
EnableTotalRecordCount: false,
EnableImages: false,
EnableUserData: false
};
const itemtype = node.li_attr.itemtype;
if (itemtype != 'Season' && itemtype != 'Series') {
query.SortBy = 'SortName';
}
ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function (result) {
const nodes = result.Items.map(function (n) {
const state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open';
return getNode(n, state, n.Id == selectedId);
});
callback.call(scope, nodes);
for (let i = 0, length = nodes.length; i < length; i++) {
if (nodes[i].state.opened) {
nodesToLoad.push(nodes[i].id);
}
}
});
}
function scrollToNode(id) {
const elem = $('#' + id)[0];
if (elem) {
elem.scrollIntoView();
}
}
function initializeTree(page, currentUser, openItems, selectedId) {
Promise.all([
import('jstree'),
import('jstree/dist/themes/default/style.css')
]).then(() => {
initializeTreeInternal(page, currentUser, openItems, selectedId);
});
}
function onNodeSelect(event, data) {
const node = data.node;
const eventData = {
id: node.id,
itemType: node.li_attr.itemtype,
serverItemType: node.li_attr.serveritemtype,
collectionType: node.li_attr.collectiontype
};
if (eventData.itemType != 'livetv' && eventData.itemType != 'mediafolders') {
{
this.dispatchEvent(new CustomEvent('itemclicked', {
detail: eventData,
bubbles: true,
cancelable: false
}));
}
document.querySelector('.editPageSidebar').classList.add('editPageSidebar-withcontent');
} else {
document.querySelector('.editPageSidebar').classList.remove('editPageSidebar-withcontent');
}
}
function onNodeOpen(_, data) {
const page = $(this).parents('.page')[0];
const node = data.node;
if (node.children) {
loadNodesToLoad(page, node);
}
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
node.li_attr.loadedFromServer = true;
$.jstree.reference('.libraryTree', page).load_node(node.id, loadNodeCallback);
}
}
function initializeTreeInternal(page, currentUser, openItems, selectedId) {
nodesToLoad = [];
selectedNodeId = null;
$.jstree.destroy();
$('.libraryTree', page).jstree({
'plugins': ['wholerow'],
core: {
check_callback: true,
data: function (node, callback) {
loadNode(page, this, node, openItems, selectedId, currentUser, callback);
},
themes: {
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', onNodeOpen)
.on('load_node.jstree', onNodeOpen);
}
function loadNodesToLoad(page, node) {
const children = node.children;
for (let i = 0, length = children.length; i < length; i++) {
const child = children[i];
if (nodesToLoad.indexOf(child) != -1) {
nodesToLoad = nodesToLoad.filter(function (n) {
return n != child;
});
$.jstree.reference('.libraryTree', page).load_node(child, loadNodeCallback);
}
}
}
function loadNodeCallback(node) {
if (selectedNodeId && node.children && node.children.indexOf(selectedNodeId) != -1) {
setTimeout(function () {
scrollToNode(selectedNodeId);
}, 500);
}
}
function updateEditorNode(page, item) {
const elem = $('#' + item.Id + '>a', page)[0];
if (elem == null) {
return;
}
$('.editorNode', elem).remove();
$(elem).append(getNodeInnerHtml(item));
if (item.IsFolder) {
const tree = jQuery.jstree._reference('.libraryTree');
const currentNode = tree._get_node(null, false);
tree.refresh(currentNode);
}
}
function setCurrentItemId(id) {
itemId = id;
}
function getCurrentItemId() {
if (itemId) {
return itemId;
}
return getParameterByName('id');
}
let nodesToLoad = [];
let selectedNodeId;
$(document).on('itemsaved', '.metadataEditorPage', function (e, item) {
updateEditorNode(this, item);
}).on('pagebeforeshow', '.metadataEditorPage', function () {
/* eslint-disable-next-line @babel/no-unused-expressions */
import('../styles/metadataeditor.scss');
}).on('pagebeforeshow', '.metadataEditorPage', function () {
const page = this;
Dashboard.getCurrentUser().then(function (user) {
const id = getCurrentItemId();
if (id) {
ApiClient.getAncestorItems(id, user.Id).then(function (ancestors) {
const ids = ancestors.map(function (i) {
return i.Id;
});
initializeTree(page, user, ids, id);
});
} else {
initializeTree(page, user, []);
}
});
}).on('pagebeforehide', '.metadataEditorPage', function () {
const page = this;
$('.libraryTree', page)
.off('select_node.jstree', onNodeSelect)
.off('open_node.jstree', onNodeOpen)
.off('load_node.jstree', onNodeOpen);
callback.call(scope, nodes);
nodesToLoad.push('MediaFolders');
});
let itemId;
window.MetadataEditor = {
getItemPromise: function () {
const currentItemId = getCurrentItemId();
if (currentItemId) {
return ApiClient.getItem(Dashboard.getCurrentUserId(), currentItemId);
}
return ApiClient.getRootFolder(Dashboard.getCurrentUserId());
},
getCurrentItemId: getCurrentItemId,
setCurrentItemId: setCurrentItemId
};
}
function loadLiveTvChannels(service, openItems, callback) {
ApiClient.getLiveTvChannels({
ServiceName: service,
AddCurrentProgram: false
}).then(function (result) {
const nodes = result.Items.map(function (i) {
const state = openItems.indexOf(i.Id) == -1 ? 'closed' : 'open';
return getNode(i, state, false);
});
callback(nodes);
});
}
function loadMediaFolders(page, scope, openItems, callback) {
ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders')).then(function (result) {
const nodes = result.Items.map(function (n) {
const state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open';
return getNode(n, state, false);
});
callback.call(scope, nodes);
for (let i = 0, length = nodes.length; i < length; i++) {
if (nodes[i].state.opened) {
nodesToLoad.push(nodes[i].id);
}
}
});
}
function loadNode(page, scope, node, openItems, selectedId, currentUser, callback) {
const id = node.id;
if (id == '#') {
loadChildrenOfRootNode(page, scope, callback);
return;
}
if (id == 'livetv') {
loadLiveTvChannels(id, openItems, callback);
return;
}
if (id == 'MediaFolders') {
loadMediaFolders(page, scope, openItems, callback);
return;
}
const query = {
ParentId: id,
Fields: 'Settings',
IsVirtualUnaired: false,
IsMissing: false,
EnableTotalRecordCount: false,
EnableImages: false,
EnableUserData: false
};
const itemtype = node.li_attr.itemtype;
if (itemtype != 'Season' && itemtype != 'Series') {
query.SortBy = 'SortName';
}
ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function (result) {
const nodes = result.Items.map(function (n) {
const state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open';
return getNode(n, state, n.Id == selectedId);
});
callback.call(scope, nodes);
for (let i = 0, length = nodes.length; i < length; i++) {
if (nodes[i].state.opened) {
nodesToLoad.push(nodes[i].id);
}
}
});
}
function scrollToNode(id) {
const elem = $('#' + id)[0];
if (elem) {
elem.scrollIntoView();
}
}
function initializeTree(page, currentUser, openItems, selectedId) {
Promise.all([
import('jstree'),
import('jstree/dist/themes/default/style.css')
]).then(() => {
initializeTreeInternal(page, currentUser, openItems, selectedId);
});
}
function onNodeSelect(event, data) {
const node = data.node;
const eventData = {
id: node.id,
itemType: node.li_attr.itemtype,
serverItemType: node.li_attr.serveritemtype,
collectionType: node.li_attr.collectiontype
};
if (eventData.itemType != 'livetv' && eventData.itemType != 'mediafolders') {
{
this.dispatchEvent(new CustomEvent('itemclicked', {
detail: eventData,
bubbles: true,
cancelable: false
}));
}
document.querySelector('.editPageSidebar').classList.add('editPageSidebar-withcontent');
} else {
document.querySelector('.editPageSidebar').classList.remove('editPageSidebar-withcontent');
}
}
function onNodeOpen(_, data) {
const page = $(this).parents('.page')[0];
const node = data.node;
if (node.children) {
loadNodesToLoad(page, node);
}
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
node.li_attr.loadedFromServer = true;
$.jstree.reference('.libraryTree', page).load_node(node.id, loadNodeCallback);
}
}
function initializeTreeInternal(page, currentUser, openItems, selectedId) {
nodesToLoad = [];
selectedNodeId = null;
$.jstree.destroy();
$('.libraryTree', page).jstree({
'plugins': ['wholerow'],
core: {
check_callback: true,
data: function (node, callback) {
loadNode(page, this, node, openItems, selectedId, currentUser, callback);
},
themes: {
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', onNodeOpen)
.on('load_node.jstree', onNodeOpen);
}
function loadNodesToLoad(page, node) {
const children = node.children;
for (let i = 0, length = children.length; i < length; i++) {
const child = children[i];
if (nodesToLoad.indexOf(child) != -1) {
nodesToLoad = nodesToLoad.filter(function (n) {
return n != child;
});
$.jstree.reference('.libraryTree', page).load_node(child, loadNodeCallback);
}
}
}
function loadNodeCallback(node) {
if (selectedNodeId && node.children && node.children.indexOf(selectedNodeId) != -1) {
setTimeout(function () {
scrollToNode(selectedNodeId);
}, 500);
}
}
function updateEditorNode(page, item) {
const elem = $('#' + item.Id + '>a', page)[0];
if (elem == null) {
return;
}
$('.editorNode', elem).remove();
$(elem).append(getNodeInnerHtml(item));
if (item.IsFolder) {
const tree = jQuery.jstree._reference('.libraryTree');
const currentNode = tree._get_node(null, false);
tree.refresh(currentNode);
}
}
function setCurrentItemId(id) {
itemId = id;
}
function getCurrentItemId() {
if (itemId) {
return itemId;
}
return getParameterByName('id');
}
let nodesToLoad = [];
let selectedNodeId;
$(document).on('itemsaved', '.metadataEditorPage', function (e, item) {
updateEditorNode(this, item);
}).on('pagebeforeshow', '.metadataEditorPage', function () {
/* eslint-disable-next-line @babel/no-unused-expressions */
import('../styles/metadataeditor.scss');
}).on('pagebeforeshow', '.metadataEditorPage', function () {
const page = this;
Dashboard.getCurrentUser().then(function (user) {
const id = getCurrentItemId();
if (id) {
ApiClient.getAncestorItems(id, user.Id).then(function (ancestors) {
const ids = ancestors.map(function (i) {
return i.Id;
});
initializeTree(page, user, ids, id);
});
} else {
initializeTree(page, user, []);
}
});
}).on('pagebeforehide', '.metadataEditorPage', function () {
const page = this;
$('.libraryTree', page)
.off('select_node.jstree', onNodeSelect)
.off('open_node.jstree', onNodeOpen)
.off('load_node.jstree', onNodeOpen);
});
let itemId;
window.MetadataEditor = {
getItemPromise: function () {
const currentItemId = getCurrentItemId();
if (currentItemId) {
return ApiClient.getItem(Dashboard.getCurrentUserId(), currentItemId);
}
return ApiClient.getRootFolder(Dashboard.getCurrentUserId());
},
getCurrentItemId: getCurrentItemId,
setCurrentItemId: setCurrentItemId
};
/* eslint-enable indent */

View file

@ -9,285 +9,283 @@ const Direction = {
ltr: 'ltr'
};
/* eslint-disable indent */
const fallbackCulture = 'en-us';
const RTL_LANGS = ['ar', 'fa', 'ur', 'he'];
const fallbackCulture = 'en-us';
const RTL_LANGS = ['ar', 'fa', 'ur', 'he'];
const allTranslations = {};
let currentCulture;
let currentDateTimeCulture;
let isRTL = false;
const allTranslations = {};
let currentCulture;
let currentDateTimeCulture;
let isRTL = false;
export function getCurrentLocale() {
return currentCulture;
}
export function getCurrentLocale() {
return currentCulture;
export function getCurrentDateTimeLocale() {
return currentDateTimeCulture;
}
function getDefaultLanguage() {
const culture = document.documentElement.getAttribute('data-culture');
if (culture) {
return culture;
}
export function getCurrentDateTimeLocale() {
return currentDateTimeCulture;
if (navigator.language) {
return navigator.language;
}
if (navigator.userLanguage) {
return navigator.userLanguage;
}
if (navigator.languages && navigator.languages.length) {
return navigator.languages[0];
}
function getDefaultLanguage() {
const culture = document.documentElement.getAttribute('data-culture');
if (culture) {
return culture;
}
return fallbackCulture;
}
if (navigator.language) {
return navigator.language;
}
if (navigator.userLanguage) {
return navigator.userLanguage;
}
if (navigator.languages && navigator.languages.length) {
return navigator.languages[0];
}
export function getIsRTL() {
return isRTL;
}
return fallbackCulture;
function checkAndProcessDir(culture) {
isRTL = false;
console.log(culture);
for (const lang of RTL_LANGS) {
if (culture.includes(lang)) {
isRTL = true;
break;
}
}
export function getIsRTL() {
return isRTL;
setDocumentDirection(isRTL ? Direction.rtl : Direction.ltr);
}
function setDocumentDirection(direction) {
document.getElementsByTagName('body')[0].setAttribute('dir', direction);
document.getElementsByTagName('html')[0].setAttribute('dir', direction);
if (direction === Direction.rtl)
import('../styles/rtl.scss');
}
export function getIsElementRTL(element) {
if (window.getComputedStyle) { // all browsers
return window.getComputedStyle(element, null).getPropertyValue('direction') == 'rtl';
}
return element.currentStyle.direction == 'rtl';
}
export function updateCurrentCulture() {
let culture;
try {
culture = userSettings.language();
} catch (err) {
console.error('no language set in user settings');
}
culture = culture || getDefaultLanguage();
checkAndProcessDir(culture);
currentCulture = normalizeLocaleName(culture);
document.documentElement.setAttribute('lang', currentCulture);
let dateTimeCulture;
try {
dateTimeCulture = userSettings.dateTimeLocale();
} catch (err) {
console.error('no date format set in user settings');
}
function checkAndProcessDir(culture) {
isRTL = false;
console.log(culture);
for (const lang of RTL_LANGS) {
if (culture.includes(lang)) {
isRTL = true;
break;
}
}
setDocumentDirection(isRTL ? Direction.rtl : Direction.ltr);
if (dateTimeCulture) {
currentDateTimeCulture = normalizeLocaleName(dateTimeCulture);
} else {
currentDateTimeCulture = currentCulture;
}
updateLocale(currentDateTimeCulture);
function setDocumentDirection(direction) {
document.getElementsByTagName('body')[0].setAttribute('dir', direction);
document.getElementsByTagName('html')[0].setAttribute('dir', direction);
if (direction === Direction.rtl)
import('../styles/rtl.scss');
ensureTranslations(currentCulture);
}
function ensureTranslations(culture) {
for (const i in allTranslations) {
ensureTranslation(allTranslations[i], culture);
}
export function getIsElementRTL(element) {
if (window.getComputedStyle) { // all browsers
return window.getComputedStyle(element, null).getPropertyValue('direction') == 'rtl';
}
return element.currentStyle.direction == 'rtl';
}
export function updateCurrentCulture() {
let culture;
try {
culture = userSettings.language();
} catch (err) {
console.error('no language set in user settings');
}
culture = culture || getDefaultLanguage();
checkAndProcessDir(culture);
currentCulture = normalizeLocaleName(culture);
document.documentElement.setAttribute('lang', currentCulture);
let dateTimeCulture;
try {
dateTimeCulture = userSettings.dateTimeLocale();
} catch (err) {
console.error('no date format set in user settings');
}
if (dateTimeCulture) {
currentDateTimeCulture = normalizeLocaleName(dateTimeCulture);
} else {
currentDateTimeCulture = currentCulture;
}
updateLocale(currentDateTimeCulture);
ensureTranslations(currentCulture);
}
function ensureTranslations(culture) {
if (culture !== fallbackCulture) {
for (const i in allTranslations) {
ensureTranslation(allTranslations[i], culture);
}
if (culture !== fallbackCulture) {
for (const i in allTranslations) {
ensureTranslation(allTranslations[i], fallbackCulture);
}
ensureTranslation(allTranslations[i], fallbackCulture);
}
}
}
function ensureTranslation(translationInfo, culture) {
if (translationInfo.dictionaries[culture]) {
return Promise.resolve();
}
return loadTranslation(translationInfo.translations, culture).then(function (dictionary) {
translationInfo.dictionaries[culture] = dictionary;
});
function ensureTranslation(translationInfo, culture) {
if (translationInfo.dictionaries[culture]) {
return Promise.resolve();
}
function normalizeLocaleName(culture) {
return culture.replace('_', '-').toLowerCase();
return loadTranslation(translationInfo.translations, culture).then(function (dictionary) {
translationInfo.dictionaries[culture] = dictionary;
});
}
function normalizeLocaleName(culture) {
return culture.replace('_', '-').toLowerCase();
}
function getDictionary(module, locale) {
if (!module) {
module = defaultModule();
}
function getDictionary(module, locale) {
if (!module) {
module = defaultModule();
}
const translations = allTranslations[module];
if (!translations) {
return {};
}
return translations.dictionaries[locale];
const translations = allTranslations[module];
if (!translations) {
return {};
}
export function register(options) {
allTranslations[options.name] = {
translations: options.strings || options.translations,
dictionaries: {}
};
return translations.dictionaries[locale];
}
export function register(options) {
allTranslations[options.name] = {
translations: options.strings || options.translations,
dictionaries: {}
};
}
export function loadStrings(options) {
const locale = getCurrentLocale();
const promises = [];
let optionsName;
if (typeof options === 'string') {
optionsName = options;
} else {
optionsName = options.name;
register(options);
}
promises.push(ensureTranslation(allTranslations[optionsName], locale));
promises.push(ensureTranslation(allTranslations[optionsName], fallbackCulture));
return Promise.all(promises);
}
export function loadStrings(options) {
const locale = getCurrentLocale();
const promises = [];
let optionsName;
if (typeof options === 'string') {
optionsName = options;
} else {
optionsName = options.name;
register(options);
}
promises.push(ensureTranslation(allTranslations[optionsName], locale));
promises.push(ensureTranslation(allTranslations[optionsName], fallbackCulture));
return Promise.all(promises);
}
function loadTranslation(translations, lang) {
lang = normalizeLocaleName(lang);
function loadTranslation(translations, lang) {
lang = normalizeLocaleName(lang);
let filtered = translations.filter(function (t) {
return normalizeLocaleName(t.lang) === lang;
});
let filtered = translations.filter(function (t) {
if (!filtered.length) {
lang = lang.replace(/-.*/, '');
filtered = translations.filter(function (t) {
return normalizeLocaleName(t.lang) === lang;
});
if (!filtered.length) {
lang = lang.replace(/-.*/, '');
filtered = translations.filter(function (t) {
return normalizeLocaleName(t.lang) === lang;
return normalizeLocaleName(t.lang) === fallbackCulture;
});
}
}
if (!filtered.length) {
filtered = translations.filter(function (t) {
return normalizeLocaleName(t.lang) === fallbackCulture;
});
}
return new Promise(function (resolve) {
if (!filtered.length) {
resolve();
return;
}
return new Promise(function (resolve) {
if (!filtered.length) {
resolve();
return;
}
const url = filtered[0].path;
const url = filtered[0].path;
import(/* webpackChunkName: "[request]" */ `../strings/${url}`).then((fileContent) => {
resolve(fileContent);
}).catch(() => {
resolve({});
});
import(/* webpackChunkName: "[request]" */ `../strings/${url}`).then((fileContent) => {
resolve(fileContent);
}).catch(() => {
resolve({});
});
}
function translateKey(key) {
const parts = key.split('#');
let module;
if (parts.length > 1) {
module = parts[0];
key = parts[1];
}
return translateKeyFromModule(key, module);
}
function translateKeyFromModule(key, module) {
let dictionary = getDictionary(module, getCurrentLocale());
if (dictionary && dictionary[key]) {
return dictionary[key];
}
dictionary = getDictionary(module, fallbackCulture);
if (dictionary && dictionary[key]) {
return dictionary[key];
}
if (!dictionary || isEmpty(dictionary)) {
console.warn('Translation dictionary is empty.');
} else {
console.error(`Translation key is missing from dictionary: ${key}`);
}
return key;
}
export function translate(key) {
let val = translateKey(key);
for (let i = 1; i < arguments.length; i++) {
val = val.replaceAll('{' + (i - 1) + '}', arguments[i].toLocaleString(currentCulture));
}
return val;
}
export function translateHtml(html, module) {
html = html.default || html;
if (!module) {
module = defaultModule();
}
if (!module) {
throw new Error('module cannot be null or empty');
}
let startIndex = html.indexOf('${');
if (startIndex === -1) {
return html;
}
startIndex += 2;
const endIndex = html.indexOf('}', startIndex);
if (endIndex === -1) {
return html;
}
const key = html.substring(startIndex, endIndex);
const val = translateKeyFromModule(key, module);
html = html.replace('${' + key + '}', val);
return translateHtml(html, module);
}
let _defaultModule;
export function defaultModule(val) {
if (val) {
_defaultModule = val;
}
return _defaultModule;
}
updateCurrentCulture();
Events.on(userSettings, 'change', function (e, name) {
if (name === 'language' || name === 'datetimelocale') {
updateCurrentCulture();
}
});
}
function translateKey(key) {
const parts = key.split('#');
let module;
if (parts.length > 1) {
module = parts[0];
key = parts[1];
}
return translateKeyFromModule(key, module);
}
function translateKeyFromModule(key, module) {
let dictionary = getDictionary(module, getCurrentLocale());
if (dictionary && dictionary[key]) {
return dictionary[key];
}
dictionary = getDictionary(module, fallbackCulture);
if (dictionary && dictionary[key]) {
return dictionary[key];
}
if (!dictionary || isEmpty(dictionary)) {
console.warn('Translation dictionary is empty.');
} else {
console.error(`Translation key is missing from dictionary: ${key}`);
}
return key;
}
export function translate(key) {
let val = translateKey(key);
for (let i = 1; i < arguments.length; i++) {
val = val.replaceAll('{' + (i - 1) + '}', arguments[i].toLocaleString(currentCulture));
}
return val;
}
export function translateHtml(html, module) {
html = html.default || html;
if (!module) {
module = defaultModule();
}
if (!module) {
throw new Error('module cannot be null or empty');
}
let startIndex = html.indexOf('${');
if (startIndex === -1) {
return html;
}
startIndex += 2;
const endIndex = html.indexOf('}', startIndex);
if (endIndex === -1) {
return html;
}
const key = html.substring(startIndex, endIndex);
const val = translateKeyFromModule(key, module);
html = html.replace('${' + key + '}', val);
return translateHtml(html, module);
}
let _defaultModule;
export function defaultModule(val) {
if (val) {
_defaultModule = val;
}
return _defaultModule;
}
updateCurrentCulture();
Events.on(userSettings, 'change', function (e, name) {
if (name === 'language' || name === 'datetimelocale') {
updateCurrentCulture();
}
});
export default {
translate,
@ -302,4 +300,3 @@ export default {
getIsElementRTL
};
/* eslint-enable indent */

View file

@ -30,71 +30,67 @@ function getWebDeviceIcon(browser) {
}
}
/* eslint-disable indent */
export function getDeviceIcon(device) {
switch (device.AppName || device.Client) {
case 'Samsung Smart TV':
return BASE_DEVICE_IMAGE_URL + 'samsung.svg';
case 'Xbox One':
return BASE_DEVICE_IMAGE_URL + 'xbox.svg';
case 'Sony PS4':
return BASE_DEVICE_IMAGE_URL + 'playstation.svg';
case 'Kodi':
case 'Kodi JellyCon':
return BASE_DEVICE_IMAGE_URL + 'kodi.svg';
case 'Jellyfin Android':
case 'AndroidTV':
case 'Android TV':
return BASE_DEVICE_IMAGE_URL + 'android.svg';
case 'Jellyfin Mobile (iOS)':
case 'Jellyfin Mobile (iPadOS)':
case 'Jellyfin iOS':
case 'Infuse':
return BASE_DEVICE_IMAGE_URL + 'apple.svg';
case 'Home Assistant':
return BASE_DEVICE_IMAGE_URL + 'home-assistant.svg';
case 'Jellyfin Roku':
return BASE_DEVICE_IMAGE_URL + 'roku.svg';
case 'Finamp':
return BASE_DEVICE_IMAGE_URL + 'finamp.svg';
case 'Jellyfin Web':
return getWebDeviceIcon(device.Name || device.DeviceName);
default:
return BASE_DEVICE_IMAGE_URL + 'other.svg';
}
export function getDeviceIcon(device) {
switch (device.AppName || device.Client) {
case 'Samsung Smart TV':
return BASE_DEVICE_IMAGE_URL + 'samsung.svg';
case 'Xbox One':
return BASE_DEVICE_IMAGE_URL + 'xbox.svg';
case 'Sony PS4':
return BASE_DEVICE_IMAGE_URL + 'playstation.svg';
case 'Kodi':
case 'Kodi JellyCon':
return BASE_DEVICE_IMAGE_URL + 'kodi.svg';
case 'Jellyfin Android':
case 'AndroidTV':
case 'Android TV':
return BASE_DEVICE_IMAGE_URL + 'android.svg';
case 'Jellyfin Mobile (iOS)':
case 'Jellyfin Mobile (iPadOS)':
case 'Jellyfin iOS':
case 'Infuse':
return BASE_DEVICE_IMAGE_URL + 'apple.svg';
case 'Home Assistant':
return BASE_DEVICE_IMAGE_URL + 'home-assistant.svg';
case 'Jellyfin Roku':
return BASE_DEVICE_IMAGE_URL + 'roku.svg';
case 'Finamp':
return BASE_DEVICE_IMAGE_URL + 'finamp.svg';
case 'Jellyfin Web':
return getWebDeviceIcon(device.Name || device.DeviceName);
default:
return BASE_DEVICE_IMAGE_URL + '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';
default:
return 'folder';
}
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';
default:
return 'folder';
}
/* eslint-enable indent */
}
export default {
getDeviceIcon: getDeviceIcon,

View file

@ -4,256 +4,252 @@ import { appRouter } from '../components/appRouter';
import dom from './dom';
import { appHost } from '../components/apphost';
/* eslint-disable indent */
let lastInputTime = new Date().getTime();
let lastInputTime = new Date().getTime();
export function notify() {
lastInputTime = new Date().getTime();
handleCommand('unknown');
}
export function notify() {
lastInputTime = new Date().getTime();
handleCommand('unknown');
export function notifyMouseMove() {
lastInputTime = new Date().getTime();
}
export function idleTime() {
return new Date().getTime() - lastInputTime;
}
export function select(sourceElement) {
sourceElement.click();
}
let eventListenerCount = 0;
export function on(scope, fn) {
eventListenerCount++;
dom.addEventListener(scope, 'command', fn, {});
}
export function off(scope, fn) {
if (eventListenerCount) {
eventListenerCount--;
}
export function notifyMouseMove() {
lastInputTime = new Date().getTime();
dom.removeEventListener(scope, 'command', fn, {});
}
const commandTimes = {};
function checkCommandTime(command) {
const last = commandTimes[command] || 0;
const now = new Date().getTime();
if ((now - last) < 1000) {
return false;
}
export function idleTime() {
return new Date().getTime() - lastInputTime;
commandTimes[command] = now;
return true;
}
export function handleCommand(commandName, options) {
lastInputTime = new Date().getTime();
let sourceElement = (options ? options.sourceElement : null);
if (sourceElement) {
sourceElement = focusManager.focusableParent(sourceElement);
}
export function select(sourceElement) {
sourceElement.click();
}
if (!sourceElement) {
sourceElement = document.activeElement || window;
let eventListenerCount = 0;
export function on(scope, fn) {
eventListenerCount++;
dom.addEventListener(scope, 'command', fn, {});
}
const dialogs = document.querySelectorAll('.dialogContainer .dialog.opened');
export function off(scope, fn) {
if (eventListenerCount) {
eventListenerCount--;
// Suppose the top open dialog is active
const dlg = dialogs.length ? dialogs[dialogs.length - 1] : null;
if (dlg && !dlg.contains(sourceElement)) {
sourceElement = dlg;
}
dom.removeEventListener(scope, 'command', fn, {});
}
const commandTimes = {};
if (eventListenerCount) {
const customEvent = new CustomEvent('command', {
detail: {
command: commandName
},
bubbles: true,
cancelable: true
});
function checkCommandTime(command) {
const last = commandTimes[command] || 0;
const now = new Date().getTime();
if ((now - last) < 1000) {
return false;
const eventResult = sourceElement.dispatchEvent(customEvent);
if (!eventResult) {
// event cancelled
return;
}
commandTimes[command] = now;
return true;
}
export function handleCommand(commandName, options) {
lastInputTime = new Date().getTime();
let sourceElement = (options ? options.sourceElement : null);
if (sourceElement) {
sourceElement = focusManager.focusableParent(sourceElement);
}
if (!sourceElement) {
sourceElement = document.activeElement || window;
const dialogs = document.querySelectorAll('.dialogContainer .dialog.opened');
// Suppose the top open dialog is active
const dlg = dialogs.length ? dialogs[dialogs.length - 1] : null;
if (dlg && !dlg.contains(sourceElement)) {
sourceElement = dlg;
const keyActions = (command) => ({
'up': () => {
focusManager.moveUp(sourceElement);
},
'down': () => {
focusManager.moveDown(sourceElement);
},
'left': () => {
focusManager.moveLeft(sourceElement);
},
'right': () => {
focusManager.moveRight(sourceElement);
},
'home': () => {
appRouter.goHome();
},
'settings': () => {
appRouter.showSettings();
},
'back': () => {
if (appRouter.canGoBack()) {
appRouter.back();
} else if (appHost.supports('exit')) {
appHost.exit();
}
}
if (eventListenerCount) {
const customEvent = new CustomEvent('command', {
detail: {
command: commandName
},
bubbles: true,
cancelable: true
});
const eventResult = sourceElement.dispatchEvent(customEvent);
if (!eventResult) {
// event cancelled
return;
},
'select': () => {
select(sourceElement);
},
'nextchapter': () => {
playbackManager.nextChapter();
},
'next': () => {
playbackManager.nextTrack();
},
'nexttrack': () => {
playbackManager.nextTrack();
},
'previous': () => {
playbackManager.previousTrack();
},
'previoustrack': () => {
playbackManager.previousTrack();
},
'previouschapter': () => {
playbackManager.previousChapter();
},
'guide': () => {
appRouter.showGuide();
},
'recordedtv': () => {
appRouter.showRecordedTV();
},
'livetv': () => {
appRouter.showLiveTV();
},
'mute': () => {
playbackManager.setMute(true);
},
'unmute': () => {
playbackManager.setMute(false);
},
'togglemute': () => {
playbackManager.toggleMute();
},
'channelup': () => {
playbackManager.channelUp();
},
'channeldown': () => {
playbackManager.channelDown();
},
'volumedown': () => {
playbackManager.volumeDown();
},
'volumeup': () => {
playbackManager.volumeUp();
},
'play': () => {
playbackManager.unpause();
},
'pause': () => {
playbackManager.pause();
},
'playpause': () => {
playbackManager.playPause();
},
'stop': () => {
if (checkCommandTime('stop')) {
playbackManager.stop();
}
},
'changezoom': () => {
playbackManager.toggleAspectRatio();
},
'increaseplaybackrate': () => {
playbackManager.increasePlaybackRate();
},
'decreaseplaybackrate': () => {
playbackManager.decreasePlaybackRate();
},
'changeaudiotrack': () => {
playbackManager.changeAudioStream();
},
'changesubtitletrack': () => {
playbackManager.changeSubtitleStream();
},
'search': () => {
appRouter.showSearch();
},
'favorites': () => {
appRouter.showFavorites();
},
'fastforward': () => {
playbackManager.fastForward();
},
'rewind': () => {
playbackManager.rewind();
},
'seek': () => {
playbackManager.seekMs(options);
},
'togglefullscreen': () => {
playbackManager.toggleFullscreen();
},
'disabledisplaymirror': () => {
playbackManager.enableDisplayMirroring(false);
},
'enabledisplaymirror': () => {
playbackManager.enableDisplayMirroring(true);
},
'toggledisplaymirror': () => {
playbackManager.toggleDisplayMirroring();
},
'nowplaying': () => {
appRouter.showNowPlaying();
},
'repeatnone': () => {
playbackManager.setRepeatMode('RepeatNone');
},
'repeatall': () => {
playbackManager.setRepeatMode('RepeatAll');
},
'repeatone': () => {
playbackManager.setRepeatMode('RepeatOne');
},
'unknown': () => {
// This is the command given by 'notify', it's a no-op
}
})[command];
const keyActions = (command) => ({
'up': () => {
focusManager.moveUp(sourceElement);
},
'down': () => {
focusManager.moveDown(sourceElement);
},
'left': () => {
focusManager.moveLeft(sourceElement);
},
'right': () => {
focusManager.moveRight(sourceElement);
},
'home': () => {
appRouter.goHome();
},
'settings': () => {
appRouter.showSettings();
},
'back': () => {
if (appRouter.canGoBack()) {
appRouter.back();
} else if (appHost.supports('exit')) {
appHost.exit();
}
},
'select': () => {
select(sourceElement);
},
'nextchapter': () => {
playbackManager.nextChapter();
},
'next': () => {
playbackManager.nextTrack();
},
'nexttrack': () => {
playbackManager.nextTrack();
},
'previous': () => {
playbackManager.previousTrack();
},
'previoustrack': () => {
playbackManager.previousTrack();
},
'previouschapter': () => {
playbackManager.previousChapter();
},
'guide': () => {
appRouter.showGuide();
},
'recordedtv': () => {
appRouter.showRecordedTV();
},
'livetv': () => {
appRouter.showLiveTV();
},
'mute': () => {
playbackManager.setMute(true);
},
'unmute': () => {
playbackManager.setMute(false);
},
'togglemute': () => {
playbackManager.toggleMute();
},
'channelup': () => {
playbackManager.channelUp();
},
'channeldown': () => {
playbackManager.channelDown();
},
'volumedown': () => {
playbackManager.volumeDown();
},
'volumeup': () => {
playbackManager.volumeUp();
},
'play': () => {
playbackManager.unpause();
},
'pause': () => {
playbackManager.pause();
},
'playpause': () => {
playbackManager.playPause();
},
'stop': () => {
if (checkCommandTime('stop')) {
playbackManager.stop();
}
},
'changezoom': () => {
playbackManager.toggleAspectRatio();
},
'increaseplaybackrate': () => {
playbackManager.increasePlaybackRate();
},
'decreaseplaybackrate': () => {
playbackManager.decreasePlaybackRate();
},
'changeaudiotrack': () => {
playbackManager.changeAudioStream();
},
'changesubtitletrack': () => {
playbackManager.changeSubtitleStream();
},
'search': () => {
appRouter.showSearch();
},
'favorites': () => {
appRouter.showFavorites();
},
'fastforward': () => {
playbackManager.fastForward();
},
'rewind': () => {
playbackManager.rewind();
},
'seek': () => {
playbackManager.seekMs(options);
},
'togglefullscreen': () => {
playbackManager.toggleFullscreen();
},
'disabledisplaymirror': () => {
playbackManager.enableDisplayMirroring(false);
},
'enabledisplaymirror': () => {
playbackManager.enableDisplayMirroring(true);
},
'toggledisplaymirror': () => {
playbackManager.toggleDisplayMirroring();
},
'nowplaying': () => {
appRouter.showNowPlaying();
},
'repeatnone': () => {
playbackManager.setRepeatMode('RepeatNone');
},
'repeatall': () => {
playbackManager.setRepeatMode('RepeatAll');
},
'repeatone': () => {
playbackManager.setRepeatMode('RepeatOne');
},
'unknown': () => {
// This is the command given by 'notify', it's a no-op
}
})[command];
const action = keyActions(commandName);
if (action !== undefined) {
action.call();
} else {
console.debug(`inputManager: tried to process command with no action assigned: ${commandName}`);
}
const action = keyActions(commandName);
if (action !== undefined) {
action.call();
} else {
console.debug(`inputManager: tried to process command with no action assigned: ${commandName}`);
}
}
dom.addEventListener(document, 'click', notify, {
passive: true
});
/* eslint-enable indent */
dom.addEventListener(document, 'click', notify, {
passive: true
});
export default {
handleCommand: handleCommand,

File diff suppressed because it is too large Load diff

View file

@ -4,169 +4,166 @@ import browser from './browser';
import layoutManager from '../components/layoutManager';
import dom from './dom';
import Events from '../utils/events.ts';
/* eslint-disable indent */
const self = {};
const self = {};
let lastMouseInputTime = new Date().getTime();
let isMouseIdle;
let lastMouseInputTime = new Date().getTime();
let isMouseIdle;
function mouseIdleTime() {
return new Date().getTime() - lastMouseInputTime;
function mouseIdleTime() {
return new Date().getTime() - lastMouseInputTime;
}
function notifyApp() {
inputManager.notifyMouseMove();
}
function removeIdleClasses() {
const classList = document.body.classList;
classList.remove('mouseIdle');
classList.remove('mouseIdle-tv');
}
function addIdleClasses() {
const classList = document.body.classList;
classList.add('mouseIdle');
if (layoutManager.tv) {
classList.add('mouseIdle-tv');
}
}
function notifyApp() {
inputManager.notifyMouseMove();
}
function removeIdleClasses() {
const classList = document.body.classList;
classList.remove('mouseIdle');
classList.remove('mouseIdle-tv');
}
function addIdleClasses() {
const classList = document.body.classList;
classList.add('mouseIdle');
if (layoutManager.tv) {
classList.add('mouseIdle-tv');
}
}
export function showCursor() {
if (isMouseIdle) {
isMouseIdle = false;
removeIdleClasses();
Events.trigger(self, 'mouseactive');
}
}
export function hideCursor() {
if (!isMouseIdle) {
isMouseIdle = true;
addIdleClasses();
Events.trigger(self, 'mouseidle');
}
}
let lastPointerMoveData;
function onPointerMove(e) {
const eventX = e.screenX || e.clientX;
const eventY = e.screenY || e.clientY;
// if coord don't exist how could it move
if (typeof eventX === 'undefined' && typeof eventY === 'undefined') {
return;
}
const 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();
showCursor();
}
function onPointerEnter(e) {
const pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
if (pointerType === 'mouse' && !isMouseIdle) {
const parent = focusManager.focusableParent(e.target);
if (parent) {
focusManager.focus(parent);
}
}
}
function enableFocusWithMouse() {
if (!layoutManager.tv) {
return false;
}
if (browser.web0s) {
return false;
}
return !!browser.tv;
}
function onMouseInterval() {
if (!isMouseIdle && mouseIdleTime() >= 5000) {
hideCursor();
}
}
let mouseInterval;
function startMouseInterval() {
if (!mouseInterval) {
mouseInterval = setInterval(onMouseInterval, 5000);
}
}
function stopMouseInterval() {
const interval = mouseInterval;
if (interval) {
clearInterval(interval);
mouseInterval = null;
}
export function showCursor() {
if (isMouseIdle) {
isMouseIdle = false;
removeIdleClasses();
Events.trigger(self, 'mouseactive');
}
}
export function hideCursor() {
if (!isMouseIdle) {
isMouseIdle = true;
addIdleClasses();
Events.trigger(self, 'mouseidle');
}
}
let lastPointerMoveData;
function onPointerMove(e) {
const eventX = e.screenX || e.clientX;
const eventY = e.screenY || e.clientY;
// if coord don't exist how could it move
if (typeof eventX === 'undefined' && typeof eventY === 'undefined') {
return;
}
function initMouse() {
stopMouseInterval();
const obj = lastPointerMoveData;
if (!obj) {
lastPointerMoveData = {
x: eventX,
y: eventY
};
return;
}
/* eslint-disable-next-line compat/compat */
dom.removeEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
// 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();
showCursor();
}
function onPointerEnter(e) {
const pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
if (pointerType === 'mouse' && !isMouseIdle) {
const parent = focusManager.focusableParent(e.target);
if (parent) {
focusManager.focus(parent);
}
}
}
function enableFocusWithMouse() {
if (!layoutManager.tv) {
return false;
}
if (browser.web0s) {
return false;
}
return !!browser.tv;
}
function onMouseInterval() {
if (!isMouseIdle && mouseIdleTime() >= 5000) {
hideCursor();
}
}
let mouseInterval;
function startMouseInterval() {
if (!mouseInterval) {
mouseInterval = setInterval(onMouseInterval, 5000);
}
}
function stopMouseInterval() {
const interval = mouseInterval;
if (interval) {
clearInterval(interval);
mouseInterval = null;
}
removeIdleClasses();
}
function initMouse() {
stopMouseInterval();
/* eslint-disable-next-line compat/compat */
dom.removeEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
passive: true
});
if (!layoutManager.mobile) {
startMouseInterval();
dom.addEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
passive: true
});
}
if (!layoutManager.mobile) {
startMouseInterval();
/* eslint-disable-next-line compat/compat */
dom.removeEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, {
capture: true,
passive: true
});
dom.addEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
passive: true
});
}
/* eslint-disable-next-line compat/compat */
dom.removeEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, {
if (enableFocusWithMouse()) {
dom.addEventListener(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();
initMouse();
Events.on(layoutManager, 'modechange', initMouse);
/* eslint-enable indent */
Events.on(layoutManager, 'modechange', initMouse);
export default {
hideCursor,