@@ -12,10 +12,10 @@
- ${LabelPrevious}
+ ${Previous}
- ${LabelNext}
+ ${Next}
diff --git a/src/controllers/wizard/remote/index.html b/src/controllers/wizard/remote/index.html
index 0718c2dc3..0334f584c 100644
--- a/src/controllers/wizard/remote/index.html
+++ b/src/controllers/wizard/remote/index.html
@@ -22,10 +22,10 @@
- ${LabelPrevious}
+ ${Previous}
- ${LabelNext}
+ ${Next}
diff --git a/src/controllers/wizard/remote/index.js b/src/controllers/wizard/remote/index.js
index 3c482607d..74c795658 100644
--- a/src/controllers/wizard/remote/index.js
+++ b/src/controllers/wizard/remote/index.js
@@ -11,7 +11,7 @@ function save(page) {
config.EnableAutomaticPortMapping = page.querySelector('#chkEnableUpnp').checked;
apiClient.ajax({
type: 'POST',
- data: config,
+ data: JSON.stringify(config),
url: apiClient.getUrl('Startup/RemoteAccess')
}).then(function () {
loading.hide();
diff --git a/src/controllers/wizard/settings/index.html b/src/controllers/wizard/settings/index.html
index d4f537cf9..d1f557d8f 100644
--- a/src/controllers/wizard/settings/index.html
+++ b/src/controllers/wizard/settings/index.html
@@ -17,10 +17,10 @@
- ${LabelPrevious}
+ ${Previous}
- ${LabelNext}
+ ${Next}
diff --git a/src/controllers/wizard/settings/index.js b/src/controllers/wizard/settings/index.js
index a1c3c1126..2eaef4fab 100644
--- a/src/controllers/wizard/settings/index.js
+++ b/src/controllers/wizard/settings/index.js
@@ -11,7 +11,7 @@ function save(page) {
config.MetadataCountryCode = page.querySelector('#selectCountry').value;
apiClient.ajax({
type: 'POST',
- data: config,
+ data: JSON.stringify(config),
url: apiClient.getUrl('Startup/Configuration')
}).then(function () {
loading.hide();
diff --git a/src/controllers/wizard/start/index.html b/src/controllers/wizard/start/index.html
index 05e282bee..5306d2ca7 100644
--- a/src/controllers/wizard/start/index.html
+++ b/src/controllers/wizard/start/index.html
@@ -19,7 +19,7 @@
- ${LabelNext}
+ ${Next}
diff --git a/src/controllers/wizard/start/index.js b/src/controllers/wizard/start/index.js
index cec93446d..8c147fc75 100644
--- a/src/controllers/wizard/start/index.js
+++ b/src/controllers/wizard/start/index.js
@@ -17,7 +17,7 @@ function save(page) {
config.UICulture = $('#selectLocalizationLanguage', page).val();
apiClient.ajax({
type: 'POST',
- data: config,
+ data: JSON.stringify(config),
url: apiClient.getUrl('Startup/Configuration')
}).then(function () {
Dashboard.navigate('wizarduser.html');
diff --git a/src/controllers/wizard/user/index.html b/src/controllers/wizard/user/index.html
index 3ce0b3ba7..24429d043 100644
--- a/src/controllers/wizard/user/index.html
+++ b/src/controllers/wizard/user/index.html
@@ -23,10 +23,10 @@
- ${LabelPrevious}
+ ${Previous}
- ${LabelNext}
+ ${Next}
diff --git a/src/controllers/wizard/user/index.js b/src/controllers/wizard/user/index.js
index 855086a3a..fc9a27855 100644
--- a/src/controllers/wizard/user/index.js
+++ b/src/controllers/wizard/user/index.js
@@ -23,10 +23,10 @@ function submit(form) {
const apiClient = getApiClient();
apiClient.ajax({
type: 'POST',
- data: {
+ data: JSON.stringify({
Name: form.querySelector('#txtUsername').value,
Password: form.querySelector('#txtManualPassword').value
- },
+ }),
url: apiClient.getUrl('Startup/User')
}).then(onUpdateUserComplete);
}
diff --git a/src/elements/emby-checkbox/emby-checkbox.js b/src/elements/emby-checkbox/emby-checkbox.js
index d3f24d6f8..d44c58ed4 100644
--- a/src/elements/emby-checkbox/emby-checkbox.js
+++ b/src/elements/emby-checkbox/emby-checkbox.js
@@ -5,12 +5,12 @@ import 'webcomponents';
/* eslint-disable indent */
- let EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype);
+ const EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype);
function onKeyDown(e) {
// Don't submit form on enter
// Real (non-emulator) Tizen does nothing on Space
- if (e.keyCode === 13 || e.keyCode === 32) {
+ if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
e.preventDefault();
this.checked = !this.checked;
@@ -26,7 +26,7 @@ import 'webcomponents';
const enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s ? true : false;
function forceRefresh(loading) {
- let elem = this.parentNode;
+ const elem = this.parentNode;
elem.style.webkitAnimationName = 'repaintChrome';
elem.style.webkitAnimationDelay = (loading === true ? '500ms' : '');
diff --git a/src/elements/emby-itemrefreshindicator/emby-itemrefreshindicator.js b/src/elements/emby-itemrefreshindicator/emby-itemrefreshindicator.js
index 67eacf3db..51f3fc5be 100644
--- a/src/elements/emby-itemrefreshindicator/emby-itemrefreshindicator.js
+++ b/src/elements/emby-itemrefreshindicator/emby-itemrefreshindicator.js
@@ -40,7 +40,7 @@ import 'webcomponents';
}
}
- let EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
+ const EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
EmbyItemRefreshIndicatorPrototype.createdCallback = function () {
// base method
diff --git a/src/elements/emby-itemscontainer/emby-itemscontainer.js b/src/elements/emby-itemscontainer/emby-itemscontainer.js
index 691552c07..ef30d1e66 100644
--- a/src/elements/emby-itemscontainer/emby-itemscontainer.js
+++ b/src/elements/emby-itemscontainer/emby-itemscontainer.js
@@ -18,7 +18,7 @@ import 'webcomponents';
function onClick(e) {
const itemsContainer = this;
- let multiSelect = itemsContainer.multiSelect;
+ const multiSelect = itemsContainer.multiSelect;
if (multiSelect) {
if (multiSelect.onContainerClick.call(itemsContainer, e) === false) {
@@ -164,7 +164,7 @@ import 'webcomponents';
}
function getEventsToMonitor(itemsContainer) {
- let monitor = itemsContainer.getAttribute('data-monitor');
+ const monitor = itemsContainer.getAttribute('data-monitor');
if (monitor) {
return monitor.split(',');
}
@@ -356,7 +356,7 @@ import 'webcomponents';
ItemsContainerPrototype.resume = function (options) {
this.paused = false;
- let refreshIntervalEndTime = this.refreshIntervalEndTime;
+ const refreshIntervalEndTime = this.refreshIntervalEndTime;
if (refreshIntervalEndTime) {
const remainingMs = refreshIntervalEndTime - new Date().getTime();
if (remainingMs > 0 && !this.needsRefresh) {
@@ -395,7 +395,7 @@ import 'webcomponents';
return;
}
- let timeout = this.refreshTimeout;
+ const timeout = this.refreshTimeout;
if (timeout) {
clearTimeout(timeout);
}
@@ -434,7 +434,7 @@ import 'webcomponents';
function onDataFetched(result) {
const items = result.Items || result;
- let parentContainer = this.parentContainer;
+ const parentContainer = this.parentContainer;
if (parentContainer) {
if (items.length) {
parentContainer.classList.remove('hide');
diff --git a/src/elements/emby-playstatebutton/emby-playstatebutton.js b/src/elements/emby-playstatebutton/emby-playstatebutton.js
index 7b5c34409..322b7b372 100644
--- a/src/elements/emby-playstatebutton/emby-playstatebutton.js
+++ b/src/elements/emby-playstatebutton/emby-playstatebutton.js
@@ -75,7 +75,7 @@ import EmbyButtonPrototype from 'emby-button';
button.title = globalize.translate('Played');
}
- let text = button.querySelector('.button-text');
+ const text = button.querySelector('.button-text');
if (text) {
text.innerHTML = button.title;
}
diff --git a/src/elements/emby-progressbar/emby-progressbar.js b/src/elements/emby-progressbar/emby-progressbar.js
index 54fcb1999..e232bbcde 100644
--- a/src/elements/emby-progressbar/emby-progressbar.js
+++ b/src/elements/emby-progressbar/emby-progressbar.js
@@ -1,6 +1,6 @@
/* eslint-disable indent */
- let ProgressBarPrototype = Object.create(HTMLDivElement.prototype);
+ const ProgressBarPrototype = Object.create(HTMLDivElement.prototype);
function onAutoTimeProgress() {
const start = parseInt(this.getAttribute('data-starttime'));
diff --git a/src/elements/emby-progressring/emby-progressring.js b/src/elements/emby-progressring/emby-progressring.js
index 10db8b9a2..929b80a57 100644
--- a/src/elements/emby-progressring/emby-progressring.js
+++ b/src/elements/emby-progressring/emby-progressring.js
@@ -3,7 +3,7 @@ import 'webcomponents';
/* eslint-disable indent */
- let EmbyProgressRing = Object.create(HTMLDivElement.prototype);
+ const EmbyProgressRing = Object.create(HTMLDivElement.prototype);
EmbyProgressRing.createdCallback = function () {
this.classList.add('progressring');
@@ -79,7 +79,7 @@ import 'webcomponents';
};
EmbyProgressRing.detachedCallback = function () {
- let observer = this.observer;
+ const observer = this.observer;
if (observer) {
// later, you can stop observing
diff --git a/src/elements/emby-radio/emby-radio.js b/src/elements/emby-radio/emby-radio.js
index b31d43644..7c468a84a 100644
--- a/src/elements/emby-radio/emby-radio.js
+++ b/src/elements/emby-radio/emby-radio.js
@@ -1,15 +1,16 @@
import layoutManager from 'layoutManager';
import 'css!./emby-radio';
import 'webcomponents';
+import browser from 'browser';
/* eslint-disable indent */
- let EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
+ const EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
function onKeyDown(e) {
// Don't submit form on enter
// Real (non-emulator) Tizen does nothing on Space
- if (e.keyCode === 13 || e.keyCode === 32) {
+ if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
e.preventDefault();
if (!this.checked) {
@@ -35,7 +36,7 @@ import 'webcomponents';
this.classList.add('mdl-radio__button');
- let labelElement = this.parentNode;
+ const labelElement = this.parentNode;
labelElement.classList.add('mdl-radio');
labelElement.classList.add('mdl-js-radio');
labelElement.classList.add('mdl-js-ripple-effect');
@@ -43,7 +44,7 @@ import 'webcomponents';
labelElement.classList.add('show-focus');
}
- let labelTextElement = labelElement.querySelector('span');
+ const labelTextElement = labelElement.querySelector('span');
labelTextElement.classList.add('radioButtonLabel');
labelTextElement.classList.add('mdl-radio__label');
diff --git a/src/elements/emby-scrollbuttons/emby-scrollbuttons.js b/src/elements/emby-scrollbuttons/emby-scrollbuttons.js
index fcff58739..f7665c061 100644
--- a/src/elements/emby-scrollbuttons/emby-scrollbuttons.js
+++ b/src/elements/emby-scrollbuttons/emby-scrollbuttons.js
@@ -118,7 +118,7 @@ const EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
}
function onScrollButtonClick(e) {
- let scroller = this.parentNode.nextSibling;
+ const scroller = this.parentNode.nextSibling;
const direction = this.getAttribute('data-direction');
const scrollSize = getScrollSize(scroller);
@@ -161,7 +161,7 @@ const EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
const parent = this.scroller;
this.scroller = null;
- let scrollHandler = this.scrollHandler;
+ const scrollHandler = this.scrollHandler;
if (parent && scrollHandler) {
parent.removeScrollEventListener(scrollHandler, {
capture: false,
diff --git a/src/elements/emby-scroller/emby-scroller.js b/src/elements/emby-scroller/emby-scroller.js
index 9812ce3cc..b2bb51e20 100644
--- a/src/elements/emby-scroller/emby-scroller.js
+++ b/src/elements/emby-scroller/emby-scroller.js
@@ -9,7 +9,7 @@ import 'css!./emby-scroller';
/* eslint-disable indent */
- let ScrollerPrototype = Object.create(HTMLDivElement.prototype);
+ const ScrollerPrototype = Object.create(HTMLDivElement.prototype);
ScrollerPrototype.createdCallback = function () {
this.classList.add('emby-scroller');
diff --git a/src/elements/emby-slider/emby-slider.js b/src/elements/emby-slider/emby-slider.js
index b39e24f5e..40d2e69bb 100644
--- a/src/elements/emby-slider/emby-slider.js
+++ b/src/elements/emby-slider/emby-slider.js
@@ -8,7 +8,7 @@ import 'emby-input';
/* eslint-disable indent */
- let EmbySliderPrototype = Object.create(HTMLInputElement.prototype);
+ const EmbySliderPrototype = Object.create(HTMLInputElement.prototype);
let supportsValueSetOverride = false;
@@ -94,7 +94,7 @@ import 'emby-input';
// Keep only one per slider frame request
cancelAnimationFrame(range.updateValuesFrame);
range.updateValuesFrame = requestAnimationFrame(function () {
- let backgroundLower = range.backgroundLower;
+ const backgroundLower = range.backgroundLower;
if (backgroundLower) {
let fraction = (value - range.min) / (range.max - range.min);
diff --git a/src/elements/emby-tabs/emby-tabs.js b/src/elements/emby-tabs/emby-tabs.js
index 320a14e2c..db7ad56f5 100644
--- a/src/elements/emby-tabs/emby-tabs.js
+++ b/src/elements/emby-tabs/emby-tabs.js
@@ -8,7 +8,7 @@ import 'scrollStyles';
/* eslint-disable indent */
- let EmbyTabs = Object.create(HTMLDivElement.prototype);
+ const EmbyTabs = Object.create(HTMLDivElement.prototype);
const buttonClass = 'emby-tab-button';
const activeButtonClass = buttonClass + '-active';
@@ -21,7 +21,7 @@ import 'scrollStyles';
}
function removeActivePanelClass(tabs, index) {
- let tabPanel = getTabPanel(tabs, index);
+ const tabPanel = getTabPanel(tabs, index);
if (tabPanel) {
tabPanel.classList.remove('is-active');
}
@@ -52,7 +52,7 @@ import 'scrollStyles';
removeActivePanelClass(tabs, previousIndex);
}
- let newPanel = getTabPanel(tabs, index);
+ const newPanel = getTabPanel(tabs, index);
if (newPanel) {
// animate new panel ?
@@ -225,7 +225,7 @@ import 'scrollStyles';
}
}));
- let currentTabButton = tabButtons[current];
+ const currentTabButton = tabButtons[current];
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, false);
if (current !== selected && currentTabButton) {
diff --git a/src/index.html b/src/index.html
index 797fce8a9..c689a42f3 100644
--- a/src/index.html
+++ b/src/index.html
@@ -137,8 +137,7 @@
}
@media screen
- and (min-device-width: 992px)
- and (-webkit-min-device-pixel-ratio: 1) {
+ and (min-device-width: 992px) {
.splashLogo {
background-image: url(assets/img/banner-light.png);
}
diff --git a/src/libraries/navdrawer/navdrawer.js b/src/libraries/navdrawer/navdrawer.js
index 4733c617f..965b68aee 100644
--- a/src/libraries/navdrawer/navdrawer.js
+++ b/src/libraries/navdrawer/navdrawer.js
@@ -1,354 +1,357 @@
-define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser, dom) {
- "use strict";
+/* Cleaning this file properly is not neecessary, since it's an outdated library
+ * and will be replaced soon by a Vue component.
+ */
- browser = browser.default || browser;
+import browser from 'browser';
+import dom from 'dom';
+import 'css!./navdrawer';
+import 'scrollStyles';
- return function (options) {
- function getTouches(e) {
- return e.changedTouches || e.targetTouches || e.touches;
+export default function (options) {
+ function getTouches(e) {
+ return e.changedTouches || e.targetTouches || e.touches;
+ }
+
+ function onMenuTouchStart(e) {
+ options.target.classList.remove('transition');
+ var touches = getTouches(e);
+ var touch = touches[0] || {};
+ menuTouchStartX = touch.clientX;
+ menuTouchStartY = touch.clientY;
+ menuTouchStartTime = new Date().getTime();
+ }
+
+ function setVelocity(deltaX) {
+ var time = new Date().getTime() - (menuTouchStartTime || 0);
+ velocity = Math.abs(deltaX) / time;
+ }
+
+ function onMenuTouchMove(e) {
+ var isOpen = self.visible;
+ var touches = getTouches(e);
+ var touch = touches[0] || {};
+ var endX = touch.clientX || 0;
+ var endY = touch.clientY || 0;
+ var deltaX = endX - (menuTouchStartX || 0);
+ var deltaY = endY - (menuTouchStartY || 0);
+ setVelocity(deltaX);
+
+ if (isOpen && dragMode !== 1 && deltaX > 0) {
+ dragMode = 2;
}
- function onMenuTouchStart(e) {
- options.target.classList.remove("transition");
- var touches = getTouches(e);
- var touch = touches[0] || {};
- menuTouchStartX = touch.clientX;
- menuTouchStartY = touch.clientY;
- menuTouchStartTime = new Date().getTime();
+ if (dragMode === 0 && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5) {
+ dragMode = 1;
+ scrollContainer.addEventListener('scroll', disableEvent);
+ self.showMask();
+ } else if (dragMode === 0 && Math.abs(deltaY) >= 5) {
+ dragMode = 2;
}
- function setVelocity(deltaX) {
- var time = new Date().getTime() - (menuTouchStartTime || 0);
- velocity = Math.abs(deltaX) / time;
+ if (dragMode === 1) {
+ newPos = currentPos + deltaX;
+ self.changeMenuPos();
}
+ }
- function onMenuTouchMove(e) {
- var isOpen = self.visible;
- var touches = getTouches(e);
- var touch = touches[0] || {};
- var endX = touch.clientX || 0;
- var endY = touch.clientY || 0;
- var deltaX = endX - (menuTouchStartX || 0);
- var deltaY = endY - (menuTouchStartY || 0);
- setVelocity(deltaX);
+ function onMenuTouchEnd(e) {
+ options.target.classList.add('transition');
+ scrollContainer.removeEventListener('scroll', disableEvent);
+ dragMode = 0;
+ var touches = getTouches(e);
+ var touch = touches[0] || {};
+ var endX = touch.clientX || 0;
+ var endY = touch.clientY || 0;
+ var deltaX = endX - (menuTouchStartX || 0);
+ var deltaY = endY - (menuTouchStartY || 0);
+ currentPos = deltaX;
+ self.checkMenuState(deltaX, deltaY);
+ }
- if (isOpen && 1 !== dragMode && deltaX > 0) {
- dragMode = 2;
- }
+ function onEdgeTouchStart(e) {
+ if (isPeeking) {
+ onMenuTouchMove(e);
+ } else {
+ if (((getTouches(e)[0] || {}).clientX || 0) <= options.handleSize) {
+ isPeeking = true;
- if (0 === dragMode && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5) {
- dragMode = 1;
- scrollContainer.addEventListener("scroll", disableEvent);
- self.showMask();
- } else if (0 === dragMode && Math.abs(deltaY) >= 5) {
- dragMode = 2;
- }
-
- if (1 === dragMode) {
- newPos = currentPos + deltaX;
- self.changeMenuPos();
- }
- }
-
- function onMenuTouchEnd(e) {
- options.target.classList.add("transition");
- scrollContainer.removeEventListener("scroll", disableEvent);
- dragMode = 0;
- var touches = getTouches(e);
- var touch = touches[0] || {};
- var endX = touch.clientX || 0;
- var endY = touch.clientY || 0;
- var deltaX = endX - (menuTouchStartX || 0);
- var deltaY = endY - (menuTouchStartY || 0);
- currentPos = deltaX;
- self.checkMenuState(deltaX, deltaY);
- }
-
- function onEdgeTouchStart(e) {
- if (isPeeking) {
- onMenuTouchMove(e);
- } else {
- if (((getTouches(e)[0] || {}).clientX || 0) <= options.handleSize) {
- isPeeking = true;
-
- if (e.type === "touchstart") {
- dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {});
- dom.addEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {});
- }
-
- onMenuTouchStart(e);
+ if (e.type === 'touchstart') {
+ dom.removeEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
+ dom.addEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
}
+
+ onMenuTouchStart(e);
}
}
+ }
- function onEdgeTouchMove(e) {
- e.preventDefault();
- e.stopPropagation();
- onEdgeTouchStart(e);
+ function onEdgeTouchMove(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ onEdgeTouchStart(e);
+ }
+
+ function onEdgeTouchEnd(e) {
+ if (isPeeking) {
+ isPeeking = false;
+ dom.removeEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
+ onMenuTouchEnd(e);
}
+ }
- function onEdgeTouchEnd(e) {
- if (isPeeking) {
- isPeeking = false;
- dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {});
- onMenuTouchEnd(e);
- }
- }
+ function disableEvent(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
- function disableEvent(e) {
- e.preventDefault();
- e.stopPropagation();
- }
+ function onBackgroundTouchStart(e) {
+ var touches = getTouches(e);
+ var touch = touches[0] || {};
+ backgroundTouchStartX = touch.clientX;
+ backgroundTouchStartTime = new Date().getTime();
+ }
- function onBackgroundTouchStart(e) {
- var touches = getTouches(e);
- var touch = touches[0] || {};
- backgroundTouchStartX = touch.clientX;
- backgroundTouchStartTime = new Date().getTime();
- }
+ function onBackgroundTouchMove(e) {
+ var touches = getTouches(e);
+ var touch = touches[0] || {};
+ var endX = touch.clientX || 0;
- function onBackgroundTouchMove(e) {
- var touches = getTouches(e);
- var touch = touches[0] || {};
- var endX = touch.clientX || 0;
-
- if (endX <= options.width && self.isVisible) {
- countStart++;
- var deltaX = endX - (backgroundTouchStartX || 0);
-
- if (countStart == 1) {
- startPoint = deltaX;
- }
- if (deltaX < 0 && dragMode !== 2) {
- dragMode = 1;
- newPos = deltaX - startPoint + options.width;
- self.changeMenuPos();
- var time = new Date().getTime() - (backgroundTouchStartTime || 0);
- velocity = Math.abs(deltaX) / time;
- }
- }
-
- e.preventDefault();
- e.stopPropagation();
- }
-
- function onBackgroundTouchEnd(e) {
- var touches = getTouches(e);
- var touch = touches[0] || {};
- var endX = touch.clientX || 0;
+ if (endX <= options.width && self.isVisible) {
+ countStart++;
var deltaX = endX - (backgroundTouchStartX || 0);
- self.checkMenuState(deltaX);
- countStart = 0;
- }
- function onMaskTransitionEnd() {
- var classList = mask.classList;
-
- if (!classList.contains("backdrop")) {
- classList.add("hide");
+ if (countStart == 1) {
+ startPoint = deltaX;
+ }
+ if (deltaX < 0 && dragMode !== 2) {
+ dragMode = 1;
+ newPos = deltaX - startPoint + options.width;
+ self.changeMenuPos();
+ var time = new Date().getTime() - (backgroundTouchStartTime || 0);
+ velocity = Math.abs(deltaX) / time;
}
}
- var self;
- var defaults;
- var mask;
- var newPos = 0;
- var currentPos = 0;
- var startPoint = 0;
- var countStart = 0;
- var velocity = 0;
- options.target.classList.add("transition");
- var dragMode = 0;
- var scrollContainer = options.target.querySelector(".mainDrawer-scrollContainer");
- scrollContainer.classList.add("scrollY");
+ e.preventDefault();
+ e.stopPropagation();
+ }
- var TouchMenuLA = function () {
- self = this;
- defaults = {
- width: 260,
- handleSize: 10,
- disableMask: false,
- maxMaskOpacity: 0.5
- };
- this.isVisible = false;
- this.initialize();
+ function onBackgroundTouchEnd(e) {
+ var touches = getTouches(e);
+ var touch = touches[0] || {};
+ var endX = touch.clientX || 0;
+ var deltaX = endX - (backgroundTouchStartX || 0);
+ self.checkMenuState(deltaX);
+ countStart = 0;
+ }
+
+ function onMaskTransitionEnd() {
+ var classList = mask.classList;
+
+ if (!classList.contains('backdrop')) {
+ classList.add('hide');
+ }
+ }
+
+ var self;
+ var defaults;
+ var mask;
+ var newPos = 0;
+ var currentPos = 0;
+ var startPoint = 0;
+ var countStart = 0;
+ var velocity = 0;
+ options.target.classList.add('transition');
+ var dragMode = 0;
+ var scrollContainer = options.target.querySelector('.mainDrawer-scrollContainer');
+ scrollContainer.classList.add('scrollY');
+
+ var TouchMenuLA = function () {
+ self = this;
+ defaults = {
+ width: 260,
+ handleSize: 10,
+ disableMask: false,
+ maxMaskOpacity: 0.5
};
+ this.isVisible = false;
+ this.initialize();
+ };
- TouchMenuLA.prototype.initElements = function () {
- options.target.classList.add("touch-menu-la");
- options.target.style.width = options.width + "px";
- options.target.style.left = -options.width + "px";
+ TouchMenuLA.prototype.initElements = function () {
+ options.target.classList.add('touch-menu-la');
+ options.target.style.width = options.width + 'px';
+ options.target.style.left = -options.width + 'px';
- if (!options.disableMask) {
- mask = document.createElement("div");
- mask.className = "tmla-mask hide";
- document.body.appendChild(mask);
- dom.addEventListener(mask, dom.whichTransitionEvent(), onMaskTransitionEnd, {
- passive: true
- });
- }
- };
-
- var menuTouchStartX;
- var menuTouchStartY;
- var menuTouchStartTime;
- var edgeContainer = document.querySelector(".mainDrawerHandle");
- var isPeeking = false;
-
- TouchMenuLA.prototype.animateToPosition = function (pos) {
- requestAnimationFrame(function () {
- options.target.style.transform = pos ? "translateX(" + pos + "px)" : "none";
+ if (!options.disableMask) {
+ mask = document.createElement('div');
+ mask.className = 'tmla-mask hide';
+ document.body.appendChild(mask);
+ dom.addEventListener(mask, dom.whichTransitionEvent(), onMaskTransitionEnd, {
+ passive: true
});
- };
+ }
+ };
- TouchMenuLA.prototype.changeMenuPos = function () {
- if (newPos <= options.width) {
- this.animateToPosition(newPos);
- }
- };
+ var menuTouchStartX;
+ var menuTouchStartY;
+ var menuTouchStartTime;
+ var edgeContainer = document.querySelector('.mainDrawerHandle');
+ var isPeeking = false;
- TouchMenuLA.prototype.clickMaskClose = function () {
- mask.addEventListener("click", function () {
+ TouchMenuLA.prototype.animateToPosition = function (pos) {
+ requestAnimationFrame(function () {
+ options.target.style.transform = pos ? 'translateX(' + pos + 'px)' : 'none';
+ });
+ };
+
+ TouchMenuLA.prototype.changeMenuPos = function () {
+ if (newPos <= options.width) {
+ this.animateToPosition(newPos);
+ }
+ };
+
+ TouchMenuLA.prototype.clickMaskClose = function () {
+ mask.addEventListener('click', function () {
+ self.close();
+ });
+ };
+
+ TouchMenuLA.prototype.checkMenuState = function (deltaX, deltaY) {
+ if (velocity >= 0.4) {
+ if (deltaX >= 0 || Math.abs(deltaY || 0) >= 70) {
+ self.open();
+ } else {
self.close();
- });
- };
-
- TouchMenuLA.prototype.checkMenuState = function (deltaX, deltaY) {
- if (velocity >= 0.4) {
- if (deltaX >= 0 || Math.abs(deltaY || 0) >= 70) {
- self.open();
- } else {
+ }
+ } else {
+ if (newPos >= 100) {
+ self.open();
+ } else {
+ if (newPos) {
self.close();
}
- } else {
- if (newPos >= 100) {
- self.open();
- } else {
- if (newPos) {
- self.close();
- }
- }
}
- };
-
- TouchMenuLA.prototype.open = function () {
- this.animateToPosition(options.width);
- currentPos = options.width;
- this.isVisible = true;
- options.target.classList.add("drawer-open");
- self.showMask();
- self.invoke(options.onChange);
- };
-
- TouchMenuLA.prototype.close = function () {
- this.animateToPosition(0);
- currentPos = 0;
- self.isVisible = false;
- options.target.classList.remove("drawer-open");
- self.hideMask();
- self.invoke(options.onChange);
- };
-
- TouchMenuLA.prototype.toggle = function () {
- if (self.isVisible) {
- self.close();
- } else {
- self.open();
- }
- };
-
- var backgroundTouchStartX;
- var backgroundTouchStartTime;
-
- TouchMenuLA.prototype.showMask = function () {
- mask.classList.remove("hide");
- mask.classList.add("backdrop");
- };
-
- TouchMenuLA.prototype.hideMask = function () {
- mask.classList.add("hide");
- mask.classList.remove("backdrop");
- };
-
- TouchMenuLA.prototype.invoke = function (fn) {
- if (fn) {
- fn.apply(self);
- }
- };
-
- var _edgeSwipeEnabled;
-
- TouchMenuLA.prototype.setEdgeSwipeEnabled = function (enabled) {
- if (!options.disableEdgeSwipe) {
- if (browser.touch) {
- if (enabled) {
- if (!_edgeSwipeEnabled) {
- _edgeSwipeEnabled = true;
- dom.addEventListener(edgeContainer, "touchstart", onEdgeTouchStart, {
- passive: true
- });
- dom.addEventListener(edgeContainer, "touchend", onEdgeTouchEnd, {
- passive: true
- });
- dom.addEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, {
- passive: true
- });
- }
- } else {
- if (_edgeSwipeEnabled) {
- _edgeSwipeEnabled = false;
- dom.removeEventListener(edgeContainer, "touchstart", onEdgeTouchStart, {
- passive: true
- });
- dom.removeEventListener(edgeContainer, "touchend", onEdgeTouchEnd, {
- passive: true
- });
- dom.removeEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, {
- passive: true
- });
- }
- }
- }
- }
- };
-
- TouchMenuLA.prototype.initialize = function () {
- options = Object.assign(defaults, options || {});
-
- if (browser.edge) {
- options.disableEdgeSwipe = true;
- }
-
- self.initElements();
-
- if (browser.touch) {
- dom.addEventListener(options.target, "touchstart", onMenuTouchStart, {
- passive: true
- });
- dom.addEventListener(options.target, "touchmove", onMenuTouchMove, {
- passive: true
- });
- dom.addEventListener(options.target, "touchend", onMenuTouchEnd, {
- passive: true
- });
- dom.addEventListener(options.target, "touchcancel", onMenuTouchEnd, {
- passive: true
- });
- dom.addEventListener(mask, "touchstart", onBackgroundTouchStart, {
- passive: true
- });
- dom.addEventListener(mask, "touchmove", onBackgroundTouchMove, {});
- dom.addEventListener(mask, "touchend", onBackgroundTouchEnd, {
- passive: true
- });
- dom.addEventListener(mask, "touchcancel", onBackgroundTouchEnd, {
- passive: true
- });
- }
-
- self.clickMaskClose();
- };
-
- return new TouchMenuLA();
+ }
};
-});
+
+ TouchMenuLA.prototype.open = function () {
+ this.animateToPosition(options.width);
+ currentPos = options.width;
+ this.isVisible = true;
+ options.target.classList.add('drawer-open');
+ self.showMask();
+ self.invoke(options.onChange);
+ };
+
+ TouchMenuLA.prototype.close = function () {
+ this.animateToPosition(0);
+ currentPos = 0;
+ self.isVisible = false;
+ options.target.classList.remove('drawer-open');
+ self.hideMask();
+ self.invoke(options.onChange);
+ };
+
+ TouchMenuLA.prototype.toggle = function () {
+ if (self.isVisible) {
+ self.close();
+ } else {
+ self.open();
+ }
+ };
+
+ var backgroundTouchStartX;
+ var backgroundTouchStartTime;
+
+ TouchMenuLA.prototype.showMask = function () {
+ mask.classList.remove('hide');
+ mask.classList.add('backdrop');
+ };
+
+ TouchMenuLA.prototype.hideMask = function () {
+ mask.classList.add('hide');
+ mask.classList.remove('backdrop');
+ };
+
+ TouchMenuLA.prototype.invoke = function (fn) {
+ if (fn) {
+ fn.apply(self);
+ }
+ };
+
+ var _edgeSwipeEnabled;
+
+ TouchMenuLA.prototype.setEdgeSwipeEnabled = function (enabled) {
+ if (!options.disableEdgeSwipe) {
+ if (browser.touch) {
+ if (enabled) {
+ if (!_edgeSwipeEnabled) {
+ _edgeSwipeEnabled = true;
+ dom.addEventListener(edgeContainer, 'touchstart', onEdgeTouchStart, {
+ passive: true
+ });
+ dom.addEventListener(edgeContainer, 'touchend', onEdgeTouchEnd, {
+ passive: true
+ });
+ dom.addEventListener(edgeContainer, 'touchcancel', onEdgeTouchEnd, {
+ passive: true
+ });
+ }
+ } else {
+ if (_edgeSwipeEnabled) {
+ _edgeSwipeEnabled = false;
+ dom.removeEventListener(edgeContainer, 'touchstart', onEdgeTouchStart, {
+ passive: true
+ });
+ dom.removeEventListener(edgeContainer, 'touchend', onEdgeTouchEnd, {
+ passive: true
+ });
+ dom.removeEventListener(edgeContainer, 'touchcancel', onEdgeTouchEnd, {
+ passive: true
+ });
+ }
+ }
+ }
+ }
+ };
+
+ TouchMenuLA.prototype.initialize = function () {
+ options = Object.assign(defaults, options || {});
+
+ if (browser.edge) {
+ options.disableEdgeSwipe = true;
+ }
+
+ self.initElements();
+
+ if (browser.touch) {
+ dom.addEventListener(options.target, 'touchstart', onMenuTouchStart, {
+ passive: true
+ });
+ dom.addEventListener(options.target, 'touchmove', onMenuTouchMove, {
+ passive: true
+ });
+ dom.addEventListener(options.target, 'touchend', onMenuTouchEnd, {
+ passive: true
+ });
+ dom.addEventListener(options.target, 'touchcancel', onMenuTouchEnd, {
+ passive: true
+ });
+ dom.addEventListener(mask, 'touchstart', onBackgroundTouchStart, {
+ passive: true
+ });
+ dom.addEventListener(mask, 'touchmove', onBackgroundTouchMove, {});
+ dom.addEventListener(mask, 'touchend', onBackgroundTouchEnd, {
+ passive: true
+ });
+ dom.addEventListener(mask, 'touchcancel', onBackgroundTouchEnd, {
+ passive: true
+ });
+ }
+
+ self.clickMaskClose();
+ };
+
+ return new TouchMenuLA();
+}
diff --git a/src/libraries/screensavermanager.js b/src/libraries/screensavermanager.js
index 557b31e0f..5c24ec63d 100644
--- a/src/libraries/screensavermanager.js
+++ b/src/libraries/screensavermanager.js
@@ -1,134 +1,128 @@
-define(["events", "playbackManager", "pluginManager", "inputManager", "connectionManager", "userSettings"], function (events, playbackManager, pluginManager, inputManager, connectionManager, userSettings) {
- "use strict";
+import events from 'events';
+import playbackManager from 'playbackManager';
+import pluginManager from 'pluginManager';
+import inputManager from 'inputManager';
+import connectionManager from 'connectionManager';
+import * as userSettings from 'userSettings';
- playbackManager = playbackManager.default || playbackManager;
+function getMinIdleTime() {
+ // Returns the minimum amount of idle time required before the screen saver can be displayed
+ //time units used Millisecond
+ return 180000;
+}
- function getMinIdleTime() {
- // Returns the minimum amount of idle time required before the screen saver can be displayed
- //time units used Millisecond
- return 180000;
+let lastFunctionalEvent = 0;
+
+function getFunctionalEventIdleTime() {
+ return new Date().getTime() - lastFunctionalEvent;
+}
+
+events.on(playbackManager, 'playbackstop', function (e, stopInfo) {
+ const state = stopInfo.state;
+ if (state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') {
+ lastFunctionalEvent = new Date().getTime();
}
-
- var lastFunctionalEvent = 0;
-
- function getFunctionalEventIdleTime() {
- return new Date().getTime() - lastFunctionalEvent;
- }
-
- events.on(playbackManager, "playbackstop", function (e, stopInfo) {
- var state = stopInfo.state;
- if (state.NowPlayingItem && state.NowPlayingItem.MediaType == "Video") {
- lastFunctionalEvent = new Date().getTime();
- }
- });
-
- function getScreensaverPlugin(isLoggedIn) {
-
- var option;
- try {
- option = userSettings.get("screensaver", false);
- } catch (err) {
- option = isLoggedIn ? "backdropscreensaver" : "logoscreensaver";
- }
-
- var plugins = pluginManager.ofType("screensaver");
-
- for (var i = 0, length = plugins.length; i < length; i++) {
- var plugin = plugins[i];
-
- if (plugin.id === option) {
- return plugin;
- }
- }
-
- return null;
- }
-
- function ScreenSaverManager() {
-
- var self = this;
- var activeScreenSaver;
-
- function showScreenSaver(screensaver) {
-
- if (activeScreenSaver) {
- throw new Error("An existing screensaver is already active.");
- }
-
- console.debug("Showing screensaver " + screensaver.name);
-
- screensaver.show();
- activeScreenSaver = screensaver;
-
- if (screensaver.hideOnClick !== false) {
- window.addEventListener("click", hide, true);
- }
- if (screensaver.hideOnMouse !== false) {
- window.addEventListener("mousemove", hide, true);
- }
- if (screensaver.hideOnKey !== false) {
- window.addEventListener("keydown", hide, true);
- }
- }
-
- function hide() {
- if (activeScreenSaver) {
- console.debug("Hiding screensaver");
- activeScreenSaver.hide();
- activeScreenSaver = null;
- }
-
- window.removeEventListener("click", hide, true);
- window.removeEventListener("mousemove", hide, true);
- window.removeEventListener("keydown", hide, true);
- }
-
- self.isShowing = function () {
- return activeScreenSaver != null;
- };
-
- self.show = function () {
- var isLoggedIn;
- var apiClient = connectionManager.currentApiClient();
-
- if (apiClient && apiClient.isLoggedIn()) {
- isLoggedIn = true;
- }
-
- var screensaver = getScreensaverPlugin(isLoggedIn);
-
- if (screensaver) {
- showScreenSaver(screensaver);
- }
- };
-
- self.hide = function () {
- hide();
- };
-
- function onInterval() {
-
- if (self.isShowing()) {
- return;
- }
-
- if (inputManager.idleTime() < getMinIdleTime()) {
- return;
- }
-
- if (getFunctionalEventIdleTime < getMinIdleTime()) {
- return;
- }
-
- if (playbackManager.isPlayingVideo()) {
- return;
- }
-
- self.show();
- }
-
- setInterval(onInterval, 10000);
- }
-
- return new ScreenSaverManager();
});
+
+function getScreensaverPlugin(isLoggedIn) {
+ let option;
+ try {
+ option = userSettings.get('screensaver', false);
+ } catch (err) {
+ option = isLoggedIn ? 'backdropscreensaver' : 'logoscreensaver';
+ }
+
+ const plugins = pluginManager.ofType('screensaver');
+
+ for (const plugin of plugins) {
+ if (plugin.id === option) {
+ return plugin;
+ }
+ }
+
+ return null;
+}
+
+function ScreenSaverManager() {
+ let activeScreenSaver;
+
+ function showScreenSaver(screensaver) {
+ if (activeScreenSaver) {
+ throw new Error('An existing screensaver is already active.');
+ }
+
+ console.debug('Showing screensaver ' + screensaver.name);
+
+ screensaver.show();
+ activeScreenSaver = screensaver;
+
+ if (screensaver.hideOnClick !== false) {
+ window.addEventListener('click', hide, true);
+ }
+ if (screensaver.hideOnMouse !== false) {
+ window.addEventListener('mousemove', hide, true);
+ }
+ if (screensaver.hideOnKey !== false) {
+ window.addEventListener('keydown', hide, true);
+ }
+ }
+
+ function hide() {
+ if (activeScreenSaver) {
+ console.debug('Hiding screensaver');
+ activeScreenSaver.hide();
+ activeScreenSaver = null;
+ }
+
+ window.removeEventListener('click', hide, true);
+ window.removeEventListener('mousemove', hide, true);
+ window.removeEventListener('keydown', hide, true);
+ }
+
+ this.isShowing = () => {
+ return activeScreenSaver != null;
+ };
+
+ this.show = function () {
+ let isLoggedIn;
+ const apiClient = connectionManager.currentApiClient();
+
+ if (apiClient && apiClient.isLoggedIn()) {
+ isLoggedIn = true;
+ }
+
+ const screensaver = getScreensaverPlugin(isLoggedIn);
+
+ if (screensaver) {
+ showScreenSaver(screensaver);
+ }
+ };
+
+ this.hide = function () {
+ hide();
+ };
+
+ const onInterval = () => {
+ if (this.isShowing()) {
+ return;
+ }
+
+ if (inputManager.idleTime() < getMinIdleTime()) {
+ return;
+ }
+
+ if (getFunctionalEventIdleTime < getMinIdleTime()) {
+ return;
+ }
+
+ if (playbackManager.isPlayingVideo()) {
+ return;
+ }
+
+ this.show();
+ };
+
+ setInterval(onInterval, 10000);
+}
+
+export default new ScreenSaverManager;
diff --git a/src/libraries/scroller.js b/src/libraries/scroller.js
index cc75dcdee..c460ec5b2 100644
--- a/src/libraries/scroller.js
+++ b/src/libraries/scroller.js
@@ -1,928 +1,886 @@
-define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'scrollStyles'], function (browser, layoutManager, dom, focusManager, ResizeObserver) {
- 'use strict';
+/* Cleaning this file properly is not neecessary, since it's an outdated library
+ * and will be replaced soon by a Vue component.
+ */
- browser = browser.default || browser;
- focusManager = focusManager.default || focusManager;
+import browser from 'browser';
+import layoutManager from 'layoutManager';
+import dom from 'dom';
+import focusManager from 'focusManager';
+import ResizeObserver from 'ResizeObserver';
+import 'scrollStyles';
- /**
+/**
* Return type of the value.
*
* @param {Mixed} value
*
* @return {String}
*/
- function type(value) {
- if (value == null) {
- return String(value);
- }
-
- if (typeof value === 'object' || typeof value === 'function') {
- return Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || 'object';
- }
-
- return typeof value;
+function type(value) {
+ if (value == null) {
+ return String(value);
}
- /**
- * Disables an event it was triggered on and unbinds itself.
- *
- * @param {Event} event
- *
- * @return {Void}
- */
- function disableOneEvent(event) {
- /*jshint validthis:true */
- event.preventDefault();
- event.stopPropagation();
- this.removeEventListener(event.type, disableOneEvent);
+ if (typeof value === 'object' || typeof value === 'function') {
+ return Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || 'object';
}
- /**
- * Make sure that number is within the limits.
- *
- * @param {Number} number
- * @param {Number} min
- * @param {Number} max
- *
- * @return {Number}
- */
- function within(number, min, max) {
- return number < min ? min : number > max ? max : number;
+ return typeof value;
+}
+
+/**
+ * Disables an event it was triggered on and unbinds itself.
+ *
+ * @param {Event} event
+ *
+ * @return {Void}
+ */
+function disableOneEvent(event) {
+ /*jshint validthis:true */
+ event.preventDefault();
+ event.stopPropagation();
+ this.removeEventListener(event.type, disableOneEvent);
+}
+
+/**
+ * Make sure that number is within the limits.
+ *
+ * @param {Number} number
+ * @param {Number} min
+ * @param {Number} max
+ *
+ * @return {Number}
+ */
+function within(number, min, max) {
+ return number < min ? min : number > max ? max : number;
+}
+
+// Other global values
+var dragMouseEvents = ['mousemove', 'mouseup'];
+var dragTouchEvents = ['touchmove', 'touchend'];
+var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
+var interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA'];
+
+var scrollerFactory = function (frame, options) {
+ // Extend options
+ var o = Object.assign({}, {
+ slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
+ horizontal: false, // Switch to horizontal mode.
+
+ // Scrolling
+ mouseWheel: true,
+ scrollBy: 0, // Pixels or items to move per one mouse scroll. 0 to disable scrolling
+
+ // Dragging
+ dragSource: null, // Selector or DOM element for catching dragging events. Default is FRAME.
+ mouseDragging: 1, // Enable navigation by dragging the SLIDEE with mouse cursor.
+ touchDragging: 1, // Enable navigation by dragging the SLIDEE with touch events.
+ dragThreshold: 3, // Distance in pixels before Sly recognizes dragging.
+ intervactive: null, // Selector for special interactive elements.
+
+ // Mixed options
+ speed: 0 // Animations speed in milliseconds. 0 to disable animations.
+
+ }, options);
+
+ var isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style;
+
+ // native scroll is a must with touch input
+ // also use native scroll when scrolling vertically in desktop mode - excluding horizontal because the mouse wheel support is choppy at the moment
+ // in cases with firefox, if the smooth scroll api is supported then use that because their implementation is very good
+ if (options.allowNativeScroll === false) {
+ options.enableNativeScroll = false;
+ } else if (isSmoothScrollSupported && ((browser.firefox && !layoutManager.tv) || options.allowNativeSmoothScroll)) {
+ // native smooth scroll
+ options.enableNativeScroll = true;
+ } else if (options.requireAnimation && (browser.animate || browser.supportsCssAnimation())) {
+ // transform is the only way to guarantee animation
+ options.enableNativeScroll = false;
+ } else if (!layoutManager.tv || !browser.animate) {
+ options.enableNativeScroll = true;
}
- // Other global values
- var dragMouseEvents = ['mousemove', 'mouseup'];
- var dragTouchEvents = ['touchmove', 'touchend'];
- var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
- var interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA'];
- var tmpArray = [];
- var time;
-
- // Math shorthands
- var abs = Math.abs;
- var sqrt = Math.sqrt;
- var pow = Math.pow;
- var round = Math.round;
- var max = Math.max;
- var min = Math.min;
-
- var scrollerFactory = function (frame, options) {
-
- // Extend options
- var o = Object.assign({}, {
- slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
- horizontal: false, // Switch to horizontal mode.
-
- // Scrolling
- mouseWheel: true,
- scrollBy: 0, // Pixels or items to move per one mouse scroll. 0 to disable scrolling
-
- // Dragging
- dragSource: null, // Selector or DOM element for catching dragging events. Default is FRAME.
- mouseDragging: 1, // Enable navigation by dragging the SLIDEE with mouse cursor.
- touchDragging: 1, // Enable navigation by dragging the SLIDEE with touch events.
- dragThreshold: 3, // Distance in pixels before Sly recognizes dragging.
- intervactive: null, // Selector for special interactive elements.
-
- // Mixed options
- speed: 0 // Animations speed in milliseconds. 0 to disable animations.
-
- }, options);
-
- var isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style;
-
- // native scroll is a must with touch input
- // also use native scroll when scrolling vertically in desktop mode - excluding horizontal because the mouse wheel support is choppy at the moment
- // in cases with firefox, if the smooth scroll api is supported then use that because their implementation is very good
- if (options.allowNativeScroll === false) {
- options.enableNativeScroll = false;
- } else if (isSmoothScrollSupported && ((browser.firefox && !layoutManager.tv) || options.allowNativeSmoothScroll)) {
- // native smooth scroll
- options.enableNativeScroll = true;
- } else if (options.requireAnimation && (browser.animate || browser.supportsCssAnimation())) {
-
- // transform is the only way to guarantee animation
- options.enableNativeScroll = false;
- } else if (!layoutManager.tv || !browser.animate) {
-
- options.enableNativeScroll = true;
- }
-
- // Need this for the magic wheel. With the animated scroll the magic wheel will run off of the screen
- if (browser.web0s) {
- options.enableNativeScroll = true;
- }
-
- // Private variables
- var self = this;
- self.options = o;
-
- // Frame
- var slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0];
- self._pos = {
- start: 0,
- center: 0,
- end: 0,
- cur: 0,
- dest: 0
- };
-
- var transform = !options.enableNativeScroll;
-
- // Miscellaneous
- var scrollSource = frame;
- var dragSourceElement = o.dragSource ? o.dragSource : frame;
- var dragging = {
- released: 1
- };
- var scrolling = {
- last: 0,
- delta: 0,
- resetTime: 200
- };
-
- // Expose properties
- self.initialized = 0;
- self.slidee = slideeElement;
- self.options = o;
- self.dragging = dragging;
-
- var nativeScrollElement = frame;
-
- function sibling(n, elem) {
- var matched = [];
-
- for (; n; n = n.nextSibling) {
- if (n.nodeType === 1 && n !== elem) {
- matched.push(n);
- }
- }
- return matched;
- }
-
- var requiresReflow = true;
-
- var frameSize = 0;
- var slideeSize = 0;
- function ensureSizeInfo() {
-
- if (requiresReflow) {
-
- requiresReflow = false;
-
- // Reset global variables
- frameSize = o.horizontal ? (frame).offsetWidth : (frame).offsetHeight;
-
- slideeSize = o.scrollWidth || Math.max(slideeElement[o.horizontal ? 'offsetWidth' : 'offsetHeight'], slideeElement[o.horizontal ? 'scrollWidth' : 'scrollHeight']);
-
- // Set position limits & relativess
- self._pos.end = max(slideeSize - frameSize, 0);
- }
- }
-
- /**
- * Loading function.
- *
- * Populate arrays, set sizes, bind events, ...
- *
- * @param {Boolean} [isInit] Whether load is called from within self.init().
- * @return {Void}
- */
- function load(isInit) {
-
- requiresReflow = true;
-
- if (!isInit) {
-
- ensureSizeInfo();
-
- // Fix possible overflowing
- var pos = self._pos;
- self.slideTo(within(pos.dest, pos.start, pos.end));
- }
- }
-
- function initFrameResizeObserver() {
-
- var observerOptions = {};
-
- self.frameResizeObserver = new ResizeObserver(onResize, observerOptions);
-
- self.frameResizeObserver.observe(frame);
- }
-
- self.reload = function () {
- load();
- };
-
- self.getScrollEventName = function () {
- return transform ? 'scrollanimate' : 'scroll';
- };
-
- self.getScrollSlider = function () {
- return slideeElement;
- };
-
- self.getScrollFrame = function () {
- return frame;
- };
-
- function nativeScrollTo(container, pos, immediate) {
-
- if (container.scroll) {
- if (o.horizontal) {
-
- container.scroll({
- left: pos,
- behavior: immediate ? 'instant' : 'smooth'
- });
- } else {
-
- container.scroll({
- top: pos,
- behavior: immediate ? 'instant' : 'smooth'
- });
- }
- } else if (!immediate && container.scrollTo) {
- if (o.horizontal) {
- container.scrollTo(Math.round(pos), 0);
- } else {
- container.scrollTo(0, Math.round(pos));
- }
- } else {
- if (o.horizontal) {
- container.scrollLeft = Math.round(pos);
- } else {
- container.scrollTop = Math.round(pos);
- }
- }
- }
-
- var lastAnimate;
-
- /**
- * Animate to a position.
- *
- * @param {Int} newPos New position.
- * @param {Bool} immediate Reposition immediately without an animation.
- *
- * @return {Void}
- */
- self.slideTo = function (newPos, immediate, fullItemPos) {
-
- ensureSizeInfo();
- var pos = self._pos;
-
- newPos = within(newPos, pos.start, pos.end);
-
- if (!transform) {
-
- nativeScrollTo(nativeScrollElement, newPos, immediate);
- return;
- }
-
- // Update the animation object
- var from = pos.cur;
- immediate = immediate || dragging.init || !o.speed;
-
- var now = new Date().getTime();
-
- if (o.autoImmediate) {
- if (!immediate && (now - (lastAnimate || 0)) <= 50) {
- immediate = true;
- }
- }
-
- if (!immediate && o.skipSlideToWhenVisible && fullItemPos && fullItemPos.isVisible) {
-
- return;
- }
-
- // Start animation rendering
- // NOTE the dependency was modified here to fix a scrollbutton issue
- pos.dest = newPos;
- renderAnimateWithTransform(from, newPos, immediate);
- lastAnimate = now;
- };
-
- function setStyleProperty(elem, name, value, speed, resetTransition) {
-
- var style = elem.style;
-
- if (resetTransition || browser.edge) {
- style.transition = 'none';
- void elem.offsetWidth;
- }
-
- style.transition = 'transform ' + speed + 'ms ease-out';
- style[name] = value;
- }
-
- function dispatchScrollEventIfNeeded() {
- if (o.dispatchScrollEvent) {
- frame.dispatchEvent(new CustomEvent(self.getScrollEventName(), {
- bubbles: true,
- cancelable: false
- }));
- }
- }
-
- function renderAnimateWithTransform(fromPosition, toPosition, immediate) {
-
- var speed = o.speed;
-
- if (immediate) {
- speed = o.immediateSpeed || 50;
- }
-
- if (o.horizontal) {
- setStyleProperty(slideeElement, 'transform', 'translateX(' + (-round(toPosition)) + 'px)', speed);
- } else {
- setStyleProperty(slideeElement, 'transform', 'translateY(' + (-round(toPosition)) + 'px)', speed);
- }
- self._pos.cur = toPosition;
-
- dispatchScrollEventIfNeeded();
- }
-
- 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) {
- return elem.getBoundingClientRect();
- } else {
- return { top: 0, left: 0 };
- }
- }
-
- /**
- * Returns the position object.
- *
- * @param {Mixed} item
- *
- * @return {Object}
- */
- self.getPos = function (item) {
-
- var scrollElement = transform ? slideeElement : nativeScrollElement;
- var slideeOffset = getBoundingClientRect(scrollElement);
- var itemOffset = getBoundingClientRect(item);
-
- var slideeStartPos = o.horizontal ? slideeOffset.left : slideeOffset.top;
- var slideeEndPos = o.horizontal ? slideeOffset.right : slideeOffset.bottom;
-
- var offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
-
- var size = o.horizontal ? itemOffset.width : itemOffset.height;
- if (!size && size !== 0) {
- size = item[o.horizontal ? 'offsetWidth' : 'offsetHeight'];
- }
-
- var centerOffset = o.centerOffset || 0;
-
- if (!transform) {
- centerOffset = 0;
- if (o.horizontal) {
- offset += nativeScrollElement.scrollLeft;
- } else {
- offset += nativeScrollElement.scrollTop;
- }
- }
-
- ensureSizeInfo();
-
- var currentStart = self._pos.cur;
- var currentEnd = currentStart + frameSize;
-
- console.debug('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd);
- var isVisible = offset >= currentStart && (offset + size) <= currentEnd;
-
- return {
- start: offset,
- center: offset + centerOffset - (frameSize / 2) + (size / 2),
- end: offset - frameSize + size,
- size: size,
- isVisible: isVisible
- };
- };
-
- self.getCenterPosition = function (item) {
-
- ensureSizeInfo();
-
- var pos = self.getPos(item);
- return within(pos.center, pos.start, pos.end);
- };
-
- function dragInitSlidee(event) {
- var isTouch = event.type === 'touchstart';
-
- // Ignore when already in progress, or interactive element in non-touch navivagion
- if (dragging.init || !isTouch && isInteractive(event.target)) {
- return;
- }
-
- // SLIDEE dragging conditions
- if (!(isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) {
- return;
- }
-
- if (!isTouch) {
- // prevents native image dragging in Firefox
- event.preventDefault();
- }
-
- // Reset dragging object
- dragging.released = 0;
-
- // Properties used in dragHandler
- dragging.init = 0;
- dragging.source = event.target;
- dragging.touch = isTouch;
- var pointer = isTouch ? event.touches[0] : event;
- dragging.initX = pointer.pageX;
- dragging.initY = pointer.pageY;
- dragging.initPos = self._pos.cur;
- dragging.start = +new Date();
- dragging.time = 0;
- dragging.path = 0;
- dragging.delta = 0;
- dragging.locked = 0;
- dragging.pathToLock = isTouch ? 30 : 10;
-
- // Bind dragging events
- if (transform) {
-
- if (isTouch) {
- dragTouchEvents.forEach(function (eventName) {
- dom.addEventListener(document, eventName, dragHandler, {
- passive: true
- });
- });
- } else {
- dragMouseEvents.forEach(function (eventName) {
- dom.addEventListener(document, eventName, dragHandler, {
- passive: true
- });
- });
- }
- }
- }
-
- /**
- * Handler for dragging scrollbar handle or SLIDEE.
- *
- * @param {Event} event
- *
- * @return {Void}
- */
- function dragHandler(event) {
- dragging.released = event.type === 'mouseup' || event.type === 'touchend';
- var pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event;
- dragging.pathX = pointer.pageX - dragging.initX;
- dragging.pathY = pointer.pageY - dragging.initY;
- dragging.path = sqrt(pow(dragging.pathX, 2) + pow(dragging.pathY, 2));
- dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY;
-
- if (!dragging.released && dragging.path < 1) {
- return;
- }
-
- // We haven't decided whether this is a drag or not...
- if (!dragging.init) {
- // If the drag path was very short, maybe it's not a drag?
- if (dragging.path < o.dragThreshold) {
- // If the pointer was released, the path will not become longer and it's
- // definitely not a drag. If not released yet, decide on next iteration
- return dragging.released ? dragEnd() : undefined;
- } else {
- // If dragging path is sufficiently long we can confidently start a drag
- // if drag is in different direction than scroll, ignore it
- if (o.horizontal ? abs(dragging.pathX) > abs(dragging.pathY) : abs(dragging.pathX) < abs(dragging.pathY)) {
- dragging.init = 1;
- } else {
- return dragEnd();
- }
- }
- }
-
- //event.preventDefault();
-
- // Disable click on a source element, as it is unwelcome when dragging
- if (!dragging.locked && dragging.path > dragging.pathToLock) {
- dragging.locked = 1;
- dragging.source.addEventListener('click', disableOneEvent);
- }
-
- // Cancel dragging on release
- if (dragging.released) {
- dragEnd();
- }
-
- self.slideTo(round(dragging.initPos - dragging.delta));
- }
-
- /**
- * Stops dragging and cleans up after it.
- *
- * @return {Void}
- */
- function dragEnd() {
- dragging.released = true;
-
- dragTouchEvents.forEach(function (eventName) {
- dom.removeEventListener(document, eventName, dragHandler, {
- passive: true
- });
- });
-
- dragMouseEvents.forEach(function (eventName) {
- dom.removeEventListener(document, eventName, dragHandler, {
- passive: true
- });
- });
-
- // Make sure that disableOneEvent is not active in next tick.
- setTimeout(function () {
- dragging.source.removeEventListener('click', disableOneEvent);
- });
-
- dragging.init = 0;
- }
-
- /**
- * Check whether element is interactive.
- *
- * @return {Boolean}
- */
- function isInteractive(element) {
-
- while (element) {
-
- if (interactiveElements.indexOf(element.tagName) !== -1) {
- return true;
- }
-
- element = element.parentNode;
- }
- return false;
- }
-
- /**
- * Mouse wheel delta normalization.
- *
- * @param {Event} event
- *
- * @return {Int}
- */
- function normalizeWheelDelta(event) {
- // JELLYFIN MOD: Only use deltaX for horizontal scroll and remove IE8 support
- scrolling.curDelta = o.horizontal ? event.deltaX : event.deltaY;
- // END JELLYFIN MOD
-
- if (transform) {
- scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100;
- }
- return scrolling.curDelta;
- }
-
- /**
- * Mouse scrolling handler.
- *
- * @param {Event} event
- *
- * @return {Void}
- */
- function scrollHandler(event) {
-
- ensureSizeInfo();
- var pos = self._pos;
- // Ignore if there is no scrolling to be done
- if (!o.scrollBy || pos.start === pos.end) {
- return;
- }
- var delta = normalizeWheelDelta(event);
-
- if (transform) {
- // Trap scrolling only when necessary and/or requested
- if (delta > 0 && pos.dest < pos.end || delta < 0 && pos.dest > pos.start) {
- //stopDefault(event, 1);
- }
-
- self.slideBy(o.scrollBy * delta);
- } else {
-
- if (isSmoothScrollSupported) {
- delta *= 12;
- }
-
- if (o.horizontal) {
- nativeScrollElement.scrollLeft += delta;
- } else {
- nativeScrollElement.scrollTop += delta;
- }
- }
- }
-
- /**
- * Destroys instance and everything it created.
- *
- * @return {Void}
- */
- self.destroy = function () {
-
- if (self.frameResizeObserver) {
- self.frameResizeObserver.disconnect();
- self.frameResizeObserver = null;
- }
-
- // Reset native FRAME element scroll
- dom.removeEventListener(frame, 'scroll', resetScroll, {
- passive: true
- });
-
- dom.removeEventListener(scrollSource, wheelEvent, scrollHandler, {
- passive: true
- });
-
- dom.removeEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
- passive: true
- });
-
- dom.removeEventListener(frame, 'click', onFrameClick, {
- passive: true,
- capture: true
- });
-
- dom.removeEventListener(dragSourceElement, 'mousedown', dragInitSlidee, {
- //passive: true
- });
-
- // Reset initialized status and return the instance
- self.initialized = 0;
- return self;
- };
-
- var contentRect = {};
-
- function onResize(entries) {
-
- var entry = entries[0];
-
- if (entry) {
-
- var newRect = entry.contentRect;
-
- // handle element being hidden
- if (newRect.width === 0 || newRect.height === 0) {
- return;
- }
-
- if (newRect.width !== contentRect.width || newRect.height !== contentRect.height) {
-
- contentRect = newRect;
-
- load(false);
- }
- }
- }
-
- function resetScroll() {
- if (o.horizontal) {
- this.scrollLeft = 0;
- } else {
- this.scrollTop = 0;
- }
- }
-
- function onFrameClick(e) {
- if (e.which === 1) {
- var focusableParent = focusManager.focusableParent(e.target);
- if (focusableParent && focusableParent !== document.activeElement) {
- focusableParent.focus();
- }
- }
- }
-
- self.getScrollPosition = function () {
-
- if (transform) {
- return self._pos.cur;
- }
-
- if (o.horizontal) {
- return nativeScrollElement.scrollLeft;
- } else {
- return nativeScrollElement.scrollTop;
- }
- };
-
- self.getScrollSize = function () {
-
- if (transform) {
- return slideeSize;
- }
-
- if (o.horizontal) {
- return nativeScrollElement.scrollWidth;
- } else {
- return nativeScrollElement.scrollHeight;
- }
- };
-
- /**
- * Initialize.
- *
- * @return {Object}
- */
- self.init = function () {
- if (self.initialized) {
- return;
- }
-
- if (!transform) {
- if (o.horizontal) {
- if (layoutManager.desktop && !o.hideScrollbar) {
- nativeScrollElement.classList.add('scrollX');
- } else {
- nativeScrollElement.classList.add('scrollX');
- nativeScrollElement.classList.add('hiddenScrollX');
-
- if (layoutManager.tv && o.allowNativeSmoothScroll !== false) {
- nativeScrollElement.classList.add('smoothScrollX');
- }
- }
-
- if (o.forceHideScrollbars) {
- nativeScrollElement.classList.add('hiddenScrollX-forced');
- }
- } else {
- if (layoutManager.desktop && !o.hideScrollbar) {
- nativeScrollElement.classList.add('scrollY');
- } else {
- nativeScrollElement.classList.add('scrollY');
- nativeScrollElement.classList.add('hiddenScrollY');
-
- if (layoutManager.tv && o.allowNativeSmoothScroll !== false) {
- nativeScrollElement.classList.add('smoothScrollY');
- }
- }
-
- if (o.forceHideScrollbars) {
- nativeScrollElement.classList.add('hiddenScrollY-forced');
- }
- }
- } else {
- frame.style.overflow = 'hidden';
- slideeElement.style['will-change'] = 'transform';
- slideeElement.style.transition = 'transform ' + o.speed + 'ms ease-out';
-
- if (o.horizontal) {
- slideeElement.classList.add('animatedScrollX');
- } else {
- slideeElement.classList.add('animatedScrollY');
- }
- }
-
- if (transform || layoutManager.tv) {
- // This can prevent others from being able to listen to mouse events
- dom.addEventListener(dragSourceElement, 'mousedown', dragInitSlidee, {
- //passive: true
- });
- }
-
- initFrameResizeObserver();
-
- if (transform) {
-
- dom.addEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
- passive: true
- });
-
- if (!o.horizontal) {
- dom.addEventListener(frame, 'scroll', resetScroll, {
- passive: true
- });
- }
-
- if (o.mouseWheel) {
- // Scrolling navigation
- dom.addEventListener(scrollSource, wheelEvent, scrollHandler, {
- passive: true
- });
- }
-
- } else if (o.horizontal) {
-
- // Don't bind to mouse events with vertical scroll since the mouse wheel can handle this natively
-
- if (o.mouseWheel) {
- // Scrolling navigation
- dom.addEventListener(scrollSource, wheelEvent, scrollHandler, {
- passive: true
- });
- }
- }
-
- dom.addEventListener(frame, 'click', onFrameClick, {
- passive: true,
- capture: true
- });
-
- // Mark instance as initialized
- self.initialized = 1;
-
- // Load
- load(true);
-
- // Return instance
- return self;
- };
+ // Need this for the magic wheel. With the animated scroll the magic wheel will run off of the screen
+ if (browser.web0s) {
+ options.enableNativeScroll = true;
+ }
+
+ // Private variables
+ var self = this;
+ self.options = o;
+
+ // Frame
+ var slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0];
+ self._pos = {
+ start: 0,
+ center: 0,
+ end: 0,
+ cur: 0,
+ dest: 0
};
+ var transform = !options.enableNativeScroll;
+
+ // Miscellaneous
+ var scrollSource = frame;
+ var dragSourceElement = o.dragSource ? o.dragSource : frame;
+ var dragging = {
+ released: 1
+ };
+ var scrolling = {
+ last: 0,
+ delta: 0,
+ resetTime: 200
+ };
+
+ // Expose properties
+ self.initialized = 0;
+ self.slidee = slideeElement;
+ self.options = o;
+ self.dragging = dragging;
+
+ var nativeScrollElement = frame;
+
+ function sibling(n, elem) {
+ var matched = [];
+
+ for (; n; n = n.nextSibling) {
+ if (n.nodeType === 1 && n !== elem) {
+ matched.push(n);
+ }
+ }
+ return matched;
+ }
+
+ var requiresReflow = true;
+
+ var frameSize = 0;
+ var slideeSize = 0;
+ function ensureSizeInfo() {
+ if (requiresReflow) {
+ requiresReflow = false;
+
+ // Reset global variables
+ frameSize = o.horizontal ? (frame).offsetWidth : (frame).offsetHeight;
+
+ slideeSize = o.scrollWidth || Math.max(slideeElement[o.horizontal ? 'offsetWidth' : 'offsetHeight'], slideeElement[o.horizontal ? 'scrollWidth' : 'scrollHeight']);
+
+ // Set position limits & relativess
+ self._pos.end = Math.max(slideeSize - frameSize, 0);
+ }
+ }
+
/**
- * Slide SLIDEE by amount of pixels.
+ * Loading function.
*
- * @param {Int} delta Pixels/Items. Positive means forward, negative means backward.
- * @param {Bool} immediate Reposition immediately without an animation.
+ * Populate arrays, set sizes, bind events, ...
*
+ * @param {Boolean} [isInit] Whether load is called from within self.init().
* @return {Void}
*/
- scrollerFactory.prototype.slideBy = function (delta, immediate) {
- if (!delta) {
+ function load(isInit) {
+ requiresReflow = true;
+
+ if (!isInit) {
+ ensureSizeInfo();
+
+ // Fix possible overflowing
+ var pos = self._pos;
+ self.slideTo(within(pos.dest, pos.start, pos.end));
+ }
+ }
+
+ function initFrameResizeObserver() {
+ var observerOptions = {};
+
+ self.frameResizeObserver = new ResizeObserver(onResize, observerOptions);
+
+ self.frameResizeObserver.observe(frame);
+ }
+
+ self.reload = function () {
+ load();
+ };
+
+ self.getScrollEventName = function () {
+ return transform ? 'scrollanimate' : 'scroll';
+ };
+
+ self.getScrollSlider = function () {
+ return slideeElement;
+ };
+
+ self.getScrollFrame = function () {
+ return frame;
+ };
+
+ function nativeScrollTo(container, pos, immediate) {
+ if (container.scroll) {
+ if (o.horizontal) {
+ container.scroll({
+ left: pos,
+ behavior: immediate ? 'instant' : 'smooth'
+ });
+ } else {
+ container.scroll({
+ top: pos,
+ behavior: immediate ? 'instant' : 'smooth'
+ });
+ }
+ } else if (!immediate && container.scrollTo) {
+ if (o.horizontal) {
+ container.scrollTo(Math.round(pos), 0);
+ } else {
+ container.scrollTo(0, Math.round(pos));
+ }
+ } else {
+ if (o.horizontal) {
+ container.scrollLeft = Math.round(pos);
+ } else {
+ container.scrollTop = Math.round(pos);
+ }
+ }
+ }
+
+ var lastAnimate;
+
+ /**
+ * Animate to a position.
+ *
+ * @param {Int} newPos New position.
+ * @param {Bool} immediate Reposition immediately without an animation.
+ *
+ * @return {Void}
+ */
+ self.slideTo = function (newPos, immediate, fullItemPos) {
+ ensureSizeInfo();
+ var pos = self._pos;
+
+ newPos = within(newPos, pos.start, pos.end);
+
+ if (!transform) {
+ nativeScrollTo(nativeScrollElement, newPos, immediate);
return;
}
- this.slideTo(this._pos.dest + delta, immediate);
- };
- /**
- * Core method for handling `toLocation` methods.
- *
- * @param {String} location
- * @param {Mixed} item
- * @param {Bool} immediate
- *
- * @return {Void}
- */
- scrollerFactory.prototype.to = function (location, item, immediate) {
- // Optional arguments logic
- if (type(item) === 'boolean') {
- immediate = item;
- item = undefined;
- }
+ // Update the animation object
+ var from = pos.cur;
+ immediate = immediate || dragging.init || !o.speed;
- if (item === undefined) {
- this.slideTo(this._pos[location], immediate);
- } else {
- var itemPos = this.getPos(item);
+ var now = new Date().getTime();
- if (itemPos) {
- this.slideTo(itemPos[location], immediate, itemPos);
+ if (o.autoImmediate) {
+ if (!immediate && (now - (lastAnimate || 0)) <= 50) {
+ immediate = true;
}
}
+
+ if (!immediate && o.skipSlideToWhenVisible && fullItemPos && fullItemPos.isVisible) {
+ return;
+ }
+
+ // Start animation rendering
+ // NOTE the dependency was modified here to fix a scrollbutton issue
+ pos.dest = newPos;
+ renderAnimateWithTransform(from, newPos, immediate);
+ lastAnimate = now;
};
+ function setStyleProperty(elem, name, value, speed, resetTransition) {
+ var style = elem.style;
+
+ if (resetTransition || browser.edge) {
+ style.transition = 'none';
+ void elem.offsetWidth;
+ }
+
+ style.transition = 'transform ' + speed + 'ms ease-out';
+ style[name] = value;
+ }
+
+ function dispatchScrollEventIfNeeded() {
+ if (o.dispatchScrollEvent) {
+ frame.dispatchEvent(new CustomEvent(self.getScrollEventName(), {
+ bubbles: true,
+ cancelable: false
+ }));
+ }
+ }
+
+ function renderAnimateWithTransform(fromPosition, toPosition, immediate) {
+ var speed = o.speed;
+
+ if (immediate) {
+ speed = o.immediateSpeed || 50;
+ }
+
+ if (o.horizontal) {
+ setStyleProperty(slideeElement, 'transform', 'translateX(' + (-Math.round(toPosition)) + 'px)', speed);
+ } else {
+ setStyleProperty(slideeElement, 'transform', 'translateY(' + (-Math.round(toPosition)) + 'px)', speed);
+ }
+ self._pos.cur = toPosition;
+
+ dispatchScrollEventIfNeeded();
+ }
+
+ 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) {
+ return elem.getBoundingClientRect();
+ } else {
+ return { top: 0, left: 0 };
+ }
+ }
+
/**
- * Animate element or the whole SLIDEE to the start of the frame.
+ * Returns the position object.
*
- * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
- * @param {Bool} immediate Reposition immediately without an animation.
+ * @param {Mixed} item
+ *
+ * @return {Object}
+ */
+ self.getPos = function (item) {
+ var scrollElement = transform ? slideeElement : nativeScrollElement;
+ var slideeOffset = getBoundingClientRect(scrollElement);
+ var itemOffset = getBoundingClientRect(item);
+
+ var offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
+
+ var size = o.horizontal ? itemOffset.width : itemOffset.height;
+ if (!size && size !== 0) {
+ size = item[o.horizontal ? 'offsetWidth' : 'offsetHeight'];
+ }
+
+ var centerOffset = o.centerOffset || 0;
+
+ if (!transform) {
+ centerOffset = 0;
+ if (o.horizontal) {
+ offset += nativeScrollElement.scrollLeft;
+ } else {
+ offset += nativeScrollElement.scrollTop;
+ }
+ }
+
+ ensureSizeInfo();
+
+ var currentStart = self._pos.cur;
+ var currentEnd = currentStart + frameSize;
+
+ console.debug('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd);
+ var isVisible = offset >= currentStart && (offset + size) <= currentEnd;
+
+ return {
+ start: offset,
+ center: offset + centerOffset - (frameSize / 2) + (size / 2),
+ end: offset - frameSize + size,
+ size: size,
+ isVisible: isVisible
+ };
+ };
+
+ self.getCenterPosition = function (item) {
+ ensureSizeInfo();
+
+ var pos = self.getPos(item);
+ return within(pos.center, pos.start, pos.end);
+ };
+
+ function dragInitSlidee(event) {
+ var isTouch = event.type === 'touchstart';
+
+ // Ignore when already in progress, or interactive element in non-touch navivagion
+ if (dragging.init || !isTouch && isInteractive(event.target)) {
+ return;
+ }
+
+ // SLIDEE dragging conditions
+ if (!(isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) {
+ return;
+ }
+
+ if (!isTouch) {
+ // prevents native image dragging in Firefox
+ event.preventDefault();
+ }
+
+ // Reset dragging object
+ dragging.released = 0;
+
+ // Properties used in dragHandler
+ dragging.init = 0;
+ dragging.source = event.target;
+ dragging.touch = isTouch;
+ var pointer = isTouch ? event.touches[0] : event;
+ dragging.initX = pointer.pageX;
+ dragging.initY = pointer.pageY;
+ dragging.initPos = self._pos.cur;
+ dragging.start = +new Date();
+ dragging.time = 0;
+ dragging.path = 0;
+ dragging.delta = 0;
+ dragging.locked = 0;
+ dragging.pathToLock = isTouch ? 30 : 10;
+
+ // Bind dragging events
+ if (transform) {
+ if (isTouch) {
+ dragTouchEvents.forEach(function (eventName) {
+ dom.addEventListener(document, eventName, dragHandler, {
+ passive: true
+ });
+ });
+ } else {
+ dragMouseEvents.forEach(function (eventName) {
+ dom.addEventListener(document, eventName, dragHandler, {
+ passive: true
+ });
+ });
+ }
+ }
+ }
+
+ /**
+ * Handler for dragging scrollbar handle or SLIDEE.
+ *
+ * @param {Event} event
*
* @return {Void}
*/
- scrollerFactory.prototype.toStart = function (item, immediate) {
- this.to('start', item, immediate);
- };
+ function dragHandler(event) {
+ dragging.released = event.type === 'mouseup' || event.type === 'touchend';
+ var pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event;
+ dragging.pathX = pointer.pageX - dragging.initX;
+ dragging.pathY = pointer.pageY - dragging.initY;
+ dragging.path = Math.sqrt(Math.pow(dragging.pathX, 2) + Math.pow(dragging.pathY, 2));
+ dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY;
+
+ if (!dragging.released && dragging.path < 1) {
+ return;
+ }
+
+ // We haven't decided whether this is a drag or not...
+ if (!dragging.init) {
+ // If the drag path was very short, maybe it's not a drag?
+ if (dragging.path < o.dragThreshold) {
+ // If the pointer was released, the path will not become longer and it's
+ // definitely not a drag. If not released yet, decide on next iteration
+ return dragging.released ? dragEnd() : undefined;
+ } else {
+ // If dragging path is sufficiently long we can confidently start a drag
+ // if drag is in different direction than scroll, ignore it
+ if (o.horizontal ? Math.abs(dragging.pathX) > Math.abs(dragging.pathY) : Math.abs(dragging.pathX) < Math.abs(dragging.pathY)) {
+ dragging.init = 1;
+ } else {
+ return dragEnd();
+ }
+ }
+ }
+
+ //event.preventDefault();
+
+ // Disable click on a source element, as it is unwelcome when dragging
+ if (!dragging.locked && dragging.path > dragging.pathToLock) {
+ dragging.locked = 1;
+ dragging.source.addEventListener('click', disableOneEvent);
+ }
+
+ // Cancel dragging on release
+ if (dragging.released) {
+ dragEnd();
+ }
+
+ self.slideTo(Math.round(dragging.initPos - dragging.delta));
+ }
/**
- * Animate element or the whole SLIDEE to the end of the frame.
- *
- * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
- * @param {Bool} immediate Reposition immediately without an animation.
+ * Stops dragging and cleans up after it.
*
* @return {Void}
*/
- scrollerFactory.prototype.toEnd = function (item, immediate) {
- this.to('end', item, immediate);
- };
+ function dragEnd() {
+ dragging.released = true;
+
+ dragTouchEvents.forEach(function (eventName) {
+ dom.removeEventListener(document, eventName, dragHandler, {
+ passive: true
+ });
+ });
+
+ dragMouseEvents.forEach(function (eventName) {
+ dom.removeEventListener(document, eventName, dragHandler, {
+ passive: true
+ });
+ });
+
+ // Make sure that disableOneEvent is not active in next tick.
+ setTimeout(function () {
+ dragging.source.removeEventListener('click', disableOneEvent);
+ });
+
+ dragging.init = 0;
+ }
/**
- * Animate element or the whole SLIDEE to the center of the frame.
+ * Check whether element is interactive.
*
- * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
- * @param {Bool} immediate Reposition immediately without an animation.
+ * @return {Boolean}
+ */
+ function isInteractive(element) {
+ while (element) {
+ if (interactiveElements.indexOf(element.tagName) !== -1) {
+ return true;
+ }
+
+ element = element.parentNode;
+ }
+ return false;
+ }
+
+ /**
+ * Mouse wheel delta normalization.
+ *
+ * @param {Event} event
+ *
+ * @return {Int}
+ */
+ function normalizeWheelDelta(event) {
+ // JELLYFIN MOD: Only use deltaX for horizontal scroll and remove IE8 support
+ scrolling.curDelta = o.horizontal ? event.deltaX : event.deltaY;
+ // END JELLYFIN MOD
+
+ if (transform) {
+ scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100;
+ }
+ return scrolling.curDelta;
+ }
+
+ /**
+ * Mouse scrolling handler.
+ *
+ * @param {Event} event
*
* @return {Void}
*/
- scrollerFactory.prototype.toCenter = function (item, immediate) {
- this.to('center', item, immediate);
+ function scrollHandler(event) {
+ ensureSizeInfo();
+ var pos = self._pos;
+ // Ignore if there is no scrolling to be done
+ if (!o.scrollBy || pos.start === pos.end) {
+ return;
+ }
+ var delta = normalizeWheelDelta(event);
+
+ if (transform) {
+ // Trap scrolling only when necessary and/or requested
+ if (delta > 0 && pos.dest < pos.end || delta < 0 && pos.dest > pos.start) {
+ //stopDefault(event, 1);
+ }
+
+ self.slideBy(o.scrollBy * delta);
+ } else {
+ if (isSmoothScrollSupported) {
+ delta *= 12;
+ }
+
+ if (o.horizontal) {
+ nativeScrollElement.scrollLeft += delta;
+ } else {
+ nativeScrollElement.scrollTop += delta;
+ }
+ }
+ }
+
+ /**
+ * Destroys instance and everything it created.
+ *
+ * @return {Void}
+ */
+ self.destroy = function () {
+ if (self.frameResizeObserver) {
+ self.frameResizeObserver.disconnect();
+ self.frameResizeObserver = null;
+ }
+
+ // Reset native FRAME element scroll
+ dom.removeEventListener(frame, 'scroll', resetScroll, {
+ passive: true
+ });
+
+ dom.removeEventListener(scrollSource, wheelEvent, scrollHandler, {
+ passive: true
+ });
+
+ dom.removeEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
+ passive: true
+ });
+
+ dom.removeEventListener(frame, 'click', onFrameClick, {
+ passive: true,
+ capture: true
+ });
+
+ dom.removeEventListener(dragSourceElement, 'mousedown', dragInitSlidee, {
+ //passive: true
+ });
+
+ // Reset initialized status and return the instance
+ self.initialized = 0;
+ return self;
};
- scrollerFactory.create = function (frame, options) {
- var instance = new scrollerFactory(frame, options);
- return Promise.resolve(instance);
+ var contentRect = {};
+
+ function onResize(entries) {
+ var entry = entries[0];
+
+ if (entry) {
+ var newRect = entry.contentRect;
+
+ // handle element being hidden
+ if (newRect.width === 0 || newRect.height === 0) {
+ return;
+ }
+
+ if (newRect.width !== contentRect.width || newRect.height !== contentRect.height) {
+ contentRect = newRect;
+
+ load(false);
+ }
+ }
+ }
+
+ function resetScroll() {
+ if (o.horizontal) {
+ this.scrollLeft = 0;
+ } else {
+ this.scrollTop = 0;
+ }
+ }
+
+ function onFrameClick(e) {
+ if (e.which === 1) {
+ var focusableParent = focusManager.focusableParent(e.target);
+ if (focusableParent && focusableParent !== document.activeElement) {
+ focusableParent.focus();
+ }
+ }
+ }
+
+ self.getScrollPosition = function () {
+ if (transform) {
+ return self._pos.cur;
+ }
+
+ if (o.horizontal) {
+ return nativeScrollElement.scrollLeft;
+ } else {
+ return nativeScrollElement.scrollTop;
+ }
};
- return scrollerFactory;
-});
+ self.getScrollSize = function () {
+ if (transform) {
+ return slideeSize;
+ }
+
+ if (o.horizontal) {
+ return nativeScrollElement.scrollWidth;
+ } else {
+ return nativeScrollElement.scrollHeight;
+ }
+ };
+
+ /**
+ * Initialize.
+ *
+ * @return {Object}
+ */
+ self.init = function () {
+ if (self.initialized) {
+ return;
+ }
+
+ if (!transform) {
+ if (o.horizontal) {
+ if (layoutManager.desktop && !o.hideScrollbar) {
+ nativeScrollElement.classList.add('scrollX');
+ } else {
+ nativeScrollElement.classList.add('scrollX');
+ nativeScrollElement.classList.add('hiddenScrollX');
+
+ if (layoutManager.tv && o.allowNativeSmoothScroll !== false) {
+ nativeScrollElement.classList.add('smoothScrollX');
+ }
+ }
+
+ if (o.forceHideScrollbars) {
+ nativeScrollElement.classList.add('hiddenScrollX-forced');
+ }
+ } else {
+ if (layoutManager.desktop && !o.hideScrollbar) {
+ nativeScrollElement.classList.add('scrollY');
+ } else {
+ nativeScrollElement.classList.add('scrollY');
+ nativeScrollElement.classList.add('hiddenScrollY');
+
+ if (layoutManager.tv && o.allowNativeSmoothScroll !== false) {
+ nativeScrollElement.classList.add('smoothScrollY');
+ }
+ }
+
+ if (o.forceHideScrollbars) {
+ nativeScrollElement.classList.add('hiddenScrollY-forced');
+ }
+ }
+ } else {
+ frame.style.overflow = 'hidden';
+ slideeElement.style['will-change'] = 'transform';
+ slideeElement.style.transition = 'transform ' + o.speed + 'ms ease-out';
+
+ if (o.horizontal) {
+ slideeElement.classList.add('animatedScrollX');
+ } else {
+ slideeElement.classList.add('animatedScrollY');
+ }
+ }
+
+ if (transform || layoutManager.tv) {
+ // This can prevent others from being able to listen to mouse events
+ dom.addEventListener(dragSourceElement, 'mousedown', dragInitSlidee, {
+ //passive: true
+ });
+ }
+
+ initFrameResizeObserver();
+
+ if (transform) {
+ dom.addEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
+ passive: true
+ });
+
+ if (!o.horizontal) {
+ dom.addEventListener(frame, 'scroll', resetScroll, {
+ passive: true
+ });
+ }
+
+ if (o.mouseWheel) {
+ // Scrolling navigation
+ dom.addEventListener(scrollSource, wheelEvent, scrollHandler, {
+ passive: true
+ });
+ }
+ } else if (o.horizontal) {
+ // Don't bind to mouse events with vertical scroll since the mouse wheel can handle this natively
+
+ if (o.mouseWheel) {
+ // Scrolling navigation
+ dom.addEventListener(scrollSource, wheelEvent, scrollHandler, {
+ passive: true
+ });
+ }
+ }
+
+ dom.addEventListener(frame, 'click', onFrameClick, {
+ passive: true,
+ capture: true
+ });
+
+ // Mark instance as initialized
+ self.initialized = 1;
+
+ // Load
+ load(true);
+
+ // Return instance
+ return self;
+ };
+};
+
+/**
+ * Slide SLIDEE by amount of pixels.
+ *
+ * @param {Int} delta Pixels/Items. Positive means forward, negative means backward.
+ * @param {Bool} immediate Reposition immediately without an animation.
+ *
+ * @return {Void}
+ */
+scrollerFactory.prototype.slideBy = function (delta, immediate) {
+ if (!delta) {
+ return;
+ }
+ this.slideTo(this._pos.dest + delta, immediate);
+};
+
+/**
+ * Core method for handling `toLocation` methods.
+ *
+ * @param {String} location
+ * @param {Mixed} item
+ * @param {Bool} immediate
+ *
+ * @return {Void}
+ */
+scrollerFactory.prototype.to = function (location, item, immediate) {
+ // Optional arguments logic
+ if (type(item) === 'boolean') {
+ immediate = item;
+ item = undefined;
+ }
+
+ if (item === undefined) {
+ this.slideTo(this._pos[location], immediate);
+ } else {
+ var itemPos = this.getPos(item);
+
+ if (itemPos) {
+ this.slideTo(itemPos[location], immediate, itemPos);
+ }
+ }
+};
+
+/**
+ * Animate element or the whole SLIDEE to the start of the frame.
+ *
+ * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
+ * @param {Bool} immediate Reposition immediately without an animation.
+ *
+ * @return {Void}
+ */
+scrollerFactory.prototype.toStart = function (item, immediate) {
+ this.to('start', item, immediate);
+};
+
+/**
+ * Animate element or the whole SLIDEE to the end of the frame.
+ *
+ * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
+ * @param {Bool} immediate Reposition immediately without an animation.
+ *
+ * @return {Void}
+ */
+scrollerFactory.prototype.toEnd = function (item, immediate) {
+ this.to('end', item, immediate);
+};
+
+/**
+ * Animate element or the whole SLIDEE to the center of the frame.
+ *
+ * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
+ * @param {Bool} immediate Reposition immediately without an animation.
+ *
+ * @return {Void}
+ */
+scrollerFactory.prototype.toCenter = function (item, immediate) {
+ this.to('center', item, immediate);
+};
+
+scrollerFactory.create = function (frame, options) {
+ var instance = new scrollerFactory(frame, options);
+ return Promise.resolve(instance);
+};
+
+export default scrollerFactory;
diff --git a/src/plugins/bookPlayer/plugin.js b/src/plugins/bookPlayer/plugin.js
index c167046cb..415bd7b95 100644
--- a/src/plugins/bookPlayer/plugin.js
+++ b/src/plugins/bookPlayer/plugin.js
@@ -27,16 +27,16 @@ export class BookPlayer {
this._loaded = false;
loading.show();
- let elem = this.createMediaElement();
+ const elem = this.createMediaElement();
return this.setCurrentSrc(elem, options);
}
stop() {
this.unbindEvents();
- let elem = this._mediaElement;
- let tocElement = this._tocElement;
- let rendition = this._rendition;
+ const elem = this._mediaElement;
+ const tocElement = this._tocElement;
+ const rendition = this._rendition;
if (elem) {
dialogHelper.close(elem);
@@ -93,11 +93,11 @@ export class BookPlayer {
}
onWindowKeyUp(e) {
- let key = keyboardnavigation.getKeyName(e);
+ const key = keyboardnavigation.getKeyName(e);
// TODO: depending on the event this can be the document or the rendition itself
- let rendition = this._rendition || this;
- let book = rendition.book;
+ const rendition = this._rendition || this;
+ const book = rendition.book;
if (this._loaded === false) return;
switch (key) {
@@ -125,8 +125,8 @@ export class BookPlayer {
onTouchStart(e) {
// TODO: depending on the event this can be the document or the rendition itself
- let rendition = this._rendition || this;
- let book = rendition.book;
+ const rendition = this._rendition || this;
+ const book = rendition.book;
// check that the event is from the book or the document
if (!book || this._loaded === false) return;
@@ -134,7 +134,8 @@ export class BookPlayer {
// epubjs stores pages off the screen or something for preloading
// get the modulus of the touch event to account for the increased width
if (!e.touches || e.touches.length === 0) return;
- let touch = e.touches[0].clientX % dom.getWindowSize().innerWidth;
+
+ const touch = e.touches[0].clientX % dom.getWindowSize().innerWidth;
if (touch < dom.getWindowSize().innerWidth / 2) {
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
} else {
@@ -147,7 +148,7 @@ export class BookPlayer {
}
bindMediaElementEvents() {
- let elem = this._mediaElement;
+ const elem = this._mediaElement;
elem.addEventListener('close', this.onDialogClosed, {once: true});
elem.querySelector('.btnBookplayerExit').addEventListener('click', this.onDialogClosed, {once: true});
@@ -166,7 +167,7 @@ export class BookPlayer {
}
unbindMediaElementEvents() {
- let elem = this._mediaElement;
+ const elem = this._mediaElement;
elem.removeEventListener('close', this.onDialogClosed);
elem.querySelector('.btnBookplayerExit').removeEventListener('click', this.onDialogClosed);
@@ -231,7 +232,7 @@ export class BookPlayer {
}
setCurrentSrc(elem, options) {
- let item = options.items[0];
+ const item = options.items[0];
this._currentItem = item;
this.streamInfo = {
started: true,
@@ -241,25 +242,25 @@ export class BookPlayer {
}
};
- let serverId = item.ServerId;
- let apiClient = connectionManager.getApiClient(serverId);
+ const serverId = item.ServerId;
+ const apiClient = connectionManager.getApiClient(serverId);
return new Promise((resolve, reject) => {
import('epubjs').then(({default: epubjs}) => {
- let downloadHref = apiClient.getItemDownloadUrl(item.Id);
- let book = epubjs(downloadHref, {openAs: 'epub'});
- let rendition = book.renderTo(elem, {width: '100%', height: '97%'});
+ const downloadHref = apiClient.getItemDownloadUrl(item.Id);
+ const book = epubjs(downloadHref, {openAs: 'epub'});
+ const rendition = book.renderTo(elem, {width: '100%', height: '97%'});
this._currentSrc = downloadHref;
this._rendition = rendition;
- let cancellationToken = {
+ const cancellationToken = {
shouldCancel: false
};
this._cancellationToken = cancellationToken;
return rendition.display().then(() => {
- let epubElem = document.querySelector('.epub-container');
+ const epubElem = document.querySelector('.epub-container');
epubElem.style.display = 'none';
this.bindEvents();
diff --git a/src/plugins/bookPlayer/tableOfContents.js b/src/plugins/bookPlayer/tableOfContents.js
index 23e288aff..a1c5d8f22 100644
--- a/src/plugins/bookPlayer/tableOfContents.js
+++ b/src/plugins/bookPlayer/tableOfContents.js
@@ -11,7 +11,7 @@ export default class TableOfContents {
}
destroy() {
- let elem = this._elem;
+ const elem = this._elem;
if (elem) {
this.unbindEvents();
dialogHelper.close(elem);
@@ -21,14 +21,14 @@ export default class TableOfContents {
}
bindEvents() {
- let elem = this._elem;
+ const elem = this._elem;
elem.addEventListener('close', this.onDialogClosed, {once: true});
elem.querySelector('.btnBookplayerTocClose').addEventListener('click', this.onDialogClosed, {once: true});
}
unbindEvents() {
- let elem = this._elem;
+ const elem = this._elem;
elem.removeEventListener('close', this.onDialogClosed);
elem.querySelector('.btnBookplayerTocClose').removeEventListener('click', this.onDialogClosed);
@@ -39,10 +39,10 @@ export default class TableOfContents {
}
replaceLinks(contents, f) {
- let links = contents.querySelectorAll('a[href]');
+ const links = contents.querySelectorAll('a[href]');
links.forEach((link) => {
- let href = link.getAttribute('href');
+ const href = link.getAttribute('href');
link.onclick = () => {
f(href);
@@ -52,9 +52,9 @@ export default class TableOfContents {
}
createMediaElement() {
- let rendition = this._rendition;
+ const rendition = this._rendition;
- let elem = dialogHelper.createDialog({
+ const elem = dialogHelper.createDialog({
size: 'small',
autoFocus: false,
removeOnClose: true
@@ -69,7 +69,7 @@ export default class TableOfContents {
rendition.book.navigation.forEach((chapter) => {
tocHtml += '
';
// Remove '../' from href
- let link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href;
+ const link = chapter.href.startsWith('../') ? chapter.href.substr(3) : chapter.href;
tocHtml += `${chapter.label} `;
tocHtml += ' ';
});
@@ -78,7 +78,7 @@ export default class TableOfContents {
elem.innerHTML = tocHtml;
this.replaceLinks(elem, (href) => {
- let relative = rendition.book.path.relative(href);
+ const relative = rendition.book.path.relative(href);
rendition.display(relative);
this.destroy();
});
diff --git a/src/plugins/chromecastPlayer/plugin.js b/src/plugins/chromecastPlayer/plugin.js
index 4a4ce2560..b7e6d0596 100644
--- a/src/plugins/chromecastPlayer/plugin.js
+++ b/src/plugins/chromecastPlayer/plugin.js
@@ -1,66 +1,71 @@
-define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', 'globalize', 'events', 'require', 'castSenderApiLoader'], function (appSettings, userSettings, playbackManager, connectionManager, globalize, events, require, castSenderApiLoader) {
- 'use strict';
+import appSettings from 'appSettings';
+import * as userSettings from 'userSettings';
+import playbackManager from 'playbackManager';
+import connectionManager from 'connectionManager';
+import globalize from 'globalize';
+import events from 'events';
+import castSenderApiLoader from 'castSenderApiLoader';
- playbackManager = playbackManager.default || playbackManager;
+// Based on https://github.com/googlecast/CastVideos-chrome/blob/master/CastVideos.js
- // Based on https://github.com/googlecast/CastVideos-chrome/blob/master/CastVideos.js
- var currentResolve;
- var currentReject;
+let currentResolve;
+let currentReject;
- var PlayerName = 'Google Cast';
+const PlayerName = 'Google Cast';
- function sendConnectionResult(isOk) {
- var resolve = currentResolve;
- var reject = currentReject;
+function sendConnectionResult(isOk) {
+ const resolve = currentResolve;
+ const reject = currentReject;
- currentResolve = null;
- currentReject = null;
+ currentResolve = null;
+ currentReject = null;
- if (isOk) {
- if (resolve) {
- resolve();
- }
+ if (isOk) {
+ if (resolve) {
+ resolve();
+ }
+ } else {
+ if (reject) {
+ reject();
} else {
- if (reject) {
- reject();
- } else {
- playbackManager.removeActivePlayer(PlayerName);
- }
+ playbackManager.removeActivePlayer(PlayerName);
}
}
+}
- /**
- * Constants of states for Chromecast device
- **/
- var DEVICE_STATE = {
- 'IDLE': 0,
- 'ACTIVE': 1,
- 'WARNING': 2,
- 'ERROR': 3
- };
+/**
+ * Constants of states for Chromecast device
+ **/
+const DEVICE_STATE = {
+ 'IDLE': 0,
+ 'ACTIVE': 1,
+ 'WARNING': 2,
+ 'ERROR': 3
+};
- /**
- * Constants of states for CastPlayer
- **/
- var PLAYER_STATE = {
- 'IDLE': 'IDLE',
- 'LOADING': 'LOADING',
- 'LOADED': 'LOADED',
- 'PLAYING': 'PLAYING',
- 'PAUSED': 'PAUSED',
- 'STOPPED': 'STOPPED',
- 'SEEKING': 'SEEKING',
- 'ERROR': 'ERROR'
- };
+/**
+ * Constants of states for CastPlayer
+ **/
+const PLAYER_STATE = {
+ 'IDLE': 'IDLE',
+ 'LOADING': 'LOADING',
+ 'LOADED': 'LOADED',
+ 'PLAYING': 'PLAYING',
+ 'PAUSED': 'PAUSED',
+ 'STOPPED': 'STOPPED',
+ 'SEEKING': 'SEEKING',
+ 'ERROR': 'ERROR'
+};
- // production version registered with google
- // replace this value if you want to test changes on another instance
- var applicationStable = 'F007D354';
- var applicationUnstable = '6F511C87';
+// production version registered with google
+// replace this value if you want to test changes on another instance
+const applicationStable = 'F007D354';
+const applicationUnstable = '6F511C87';
- var messageNamespace = 'urn:x-cast:com.connectsdk';
+const messageNamespace = 'urn:x-cast:com.connectsdk';
- var CastPlayer = function () {
+class CastPlayer {
+ constructor() {
/* device variables */
// @type {DEVICE_STATE} A state for device
this.deviceState = DEVICE_STATE.IDLE;
@@ -81,7 +86,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
this.mediaStatusUpdateHandler = this.onMediaStatusUpdate.bind(this);
this.initializeCastPlayer();
- };
+ }
/**
* Initialize Cast media player
@@ -89,8 +94,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
* invoked once the API has finished initialization. The sessionListener and
* receiverListener may be invoked at any time afterwards, and possibly more than once.
*/
- CastPlayer.prototype.initializeCastPlayer = function () {
- var chrome = window.chrome;
+ initializeCastPlayer() {
+ const chrome = window.chrome;
if (!chrome) {
return;
}
@@ -100,35 +105,35 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
return;
}
- var applicationID = applicationStable;
+ let applicationID = applicationStable;
if (userSettings.chromecastVersion() === 'unstable') {
applicationID = applicationUnstable;
}
// request session
- var sessionRequest = new chrome.cast.SessionRequest(applicationID);
- var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
+ const sessionRequest = new chrome.cast.SessionRequest(applicationID);
+ const apiConfig = new chrome.cast.ApiConfig(sessionRequest,
this.sessionListener.bind(this),
this.receiverListener.bind(this));
console.debug('chromecast.initialize');
chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.errorHandler);
- };
+ }
/**
* Callback function for init success
*/
- CastPlayer.prototype.onInitSuccess = function () {
+ onInitSuccess() {
this.isInitialized = true;
console.debug('chromecast init success');
- };
+ }
/**
* Generic error callback function
*/
- CastPlayer.prototype.onError = function () {
+ onError() {
console.debug('chromecast error');
- };
+ }
/**
* @param {!Object} e A new session
@@ -137,7 +142,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
* join existing session and occur in Cast mode and media
* status gets synced up with current media of the session
*/
- CastPlayer.prototype.sessionListener = function (e) {
+ sessionListener(e) {
this.session = e;
if (this.session) {
if (this.session.media[0]) {
@@ -146,24 +151,15 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
this.onSessionConnected(e);
}
- };
-
- function alertText(text, title) {
- require(['alert'], function (alert) {
- alert.default({
- text: text,
- title: title
- });
- });
}
- CastPlayer.prototype.messageListener = function (namespace, message) {
+ messageListener(namespace, message) {
if (typeof (message) === 'string') {
message = JSON.parse(message);
}
if (message.type === 'playbackerror') {
- var errorCode = message.data;
+ const errorCode = message.data;
setTimeout(function () {
alertText(globalize.translate('MessagePlaybackError' + errorCode), globalize.translate('HeaderPlaybackError'));
}, 300);
@@ -174,14 +170,14 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
} else if (message.type) {
events.trigger(this, message.type, [message.data]);
}
- };
+ }
/**
* @param {string} e Receiver availability
* This indicates availability of receivers but
* does not provide a list of device IDs
*/
- CastPlayer.prototype.receiverListener = function (e) {
+ receiverListener(e) {
if (e === 'available') {
console.debug('chromecast receiver found');
this.hasReceivers = true;
@@ -189,12 +185,12 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
console.debug('chromecast receiver list empty');
this.hasReceivers = false;
}
- };
+ }
/**
* session update listener
*/
- CastPlayer.prototype.sessionUpdateListener = function (isAlive) {
+ sessionUpdateListener(isAlive) {
if (isAlive) {
console.debug('sessionUpdateListener: already alive');
} else {
@@ -209,28 +205,28 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
sendConnectionResult(false);
}
- };
+ }
/**
* Requests that a receiver application session be created or joined. By default, the SessionRequest
* passed to the API at initialization time is used; this may be overridden by passing a different
* session request in opt_sessionRequest.
*/
- CastPlayer.prototype.launchApp = function () {
+ launchApp() {
console.debug('chromecast launching app...');
chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this));
- };
+ }
/**
* Callback function for request session success
* @param {Object} e A chrome.cast.Session object
*/
- CastPlayer.prototype.onRequestSessionSuccess = function (e) {
+ onRequestSessionSuccess(e) {
console.debug('chromecast session success: ' + e.sessionId);
this.onSessionConnected(e);
- };
+ }
- CastPlayer.prototype.onSessionConnected = function (session) {
+ onSessionConnected(session) {
this.session = session;
this.deviceState = DEVICE_STATE.ACTIVE;
@@ -246,46 +242,38 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
options: {},
command: 'Identify'
});
- };
-
- function onVolumeUpKeyDown() {
- playbackManager.volumeUp();
- }
-
- function onVolumeDownKeyDown() {
- playbackManager.volumeDown();
}
/**
* session update listener
*/
- CastPlayer.prototype.sessionMediaListener = function (e) {
+ sessionMediaListener(e) {
this.currentMediaSession = e;
this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler);
- };
+ }
/**
* Callback function for launch error
*/
- CastPlayer.prototype.onLaunchError = function () {
+ onLaunchError() {
console.debug('chromecast launch error');
this.deviceState = DEVICE_STATE.ERROR;
sendConnectionResult(false);
- };
+ }
/**
* Stops the running receiver application associated with the session.
*/
- CastPlayer.prototype.stopApp = function () {
+ stopApp() {
if (this.session) {
this.session.stop(this.onStopAppSuccess.bind(this, 'Session stopped'), this.errorHandler);
}
- };
+ }
/**
* Callback function for stop app success
*/
- CastPlayer.prototype.onStopAppSuccess = function (message) {
+ onStopAppSuccess(message) {
console.debug(message);
this.deviceState = DEVICE_STATE.IDLE;
@@ -294,13 +282,13 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
document.removeEventListener('volumedownbutton', onVolumeDownKeyDown, false);
this.currentMediaSession = null;
- };
+ }
/**
* Loads media into a running receiver application
* @param {Number} mediaIndex An index number to indicate current media content
*/
- CastPlayer.prototype.loadMedia = function (options, command) {
+ loadMedia(options, command) {
if (!this.session) {
console.debug('no session');
return Promise.reject();
@@ -322,20 +310,20 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
options: options,
command: command
});
- };
+ }
- CastPlayer.prototype.sendMessage = function (message) {
- var player = this;
+ sendMessage(message) {
+ const player = this;
- var receiverName = null;
+ let receiverName = null;
- var session = player.session;
+ const session = player.session;
if (session && session.receiver && session.receiver.friendlyName) {
receiverName = session.receiver.friendlyName;
}
- var apiClient;
+ let apiClient;
if (message.options && message.options.ServerId) {
apiClient = connectionManager.getApiClient(message.options.ServerId);
} else if (message.options && message.options.items && message.options.items.length) {
@@ -354,7 +342,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
receiverName: receiverName
});
- var bitrateSetting = appSettings.maxChromecastBitrate();
+ const bitrateSetting = appSettings.maxChromecastBitrate();
if (bitrateSetting) {
message.maxBitrate = bitrateSetting;
}
@@ -365,33 +353,31 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
}
return new Promise(function (resolve, reject) {
- require(['./chromecastHelper'], function (chromecastHelper) {
- chromecastHelper = chromecastHelper.default || chromecastHelper;
-
+ import('./chromecastHelper').then(({ default: chromecastHelper }) => {
chromecastHelper.getServerAddress(apiClient).then(function (serverAddress) {
message.serverAddress = serverAddress;
player.sendMessageInternal(message).then(resolve, reject);
}, reject);
});
});
- };
+ }
- CastPlayer.prototype.sendMessageInternal = function (message) {
+ sendMessageInternal(message) {
message = JSON.stringify(message);
this.session.sendMessage(messageNamespace, message, this.onPlayCommandSuccess.bind(this), this.errorHandler);
return Promise.resolve();
- };
+ }
- CastPlayer.prototype.onPlayCommandSuccess = function () {
+ onPlayCommandSuccess() {
console.debug('Message was sent to receiver ok.');
- };
+ }
/**
* Callback function for loadMedia success
* @param {Object} mediaSession A new media object.
*/
- CastPlayer.prototype.onMediaDiscovered = function (how, mediaSession) {
+ onMediaDiscovered(how, mediaSession) {
console.debug('chromecast new media session ID:' + mediaSession.mediaSessionId + ' (' + how + ')');
this.currentMediaSession = mediaSession;
@@ -404,24 +390,24 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
}
this.currentMediaSession.addUpdateListener(this.mediaStatusUpdateHandler);
- };
+ }
/**
* Callback function for media status update from receiver
* @param {!Boolean} e true/false
*/
- CastPlayer.prototype.onMediaStatusUpdate = function (e) {
+ onMediaStatusUpdate(e) {
console.debug('chromecast updating media: ' + e);
if (e === false) {
this.castPlayerState = PLAYER_STATE.IDLE;
}
- };
+ }
/**
* Set media volume in Cast mode
* @param {Boolean} mute A boolean
*/
- CastPlayer.prototype.setReceiverVolume = function (mute, vol) {
+ setReceiverVolume(mute, vol) {
if (!this.currentMediaSession) {
console.debug('this.currentMediaSession is null');
return;
@@ -436,142 +422,161 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
this.mediaCommandSuccessCallback.bind(this),
this.errorHandler);
}
- };
+ }
/**
* Mute CC
*/
- CastPlayer.prototype.mute = function () {
+ mute() {
this.setReceiverVolume(true);
- };
+ }
/**
* Callback function for media command success
*/
- CastPlayer.prototype.mediaCommandSuccessCallback = function (info, e) {
+ mediaCommandSuccessCallback(info, e) {
console.debug(info);
- };
+ }
+}
- function normalizeImages(state) {
- if (state && state.NowPlayingItem) {
- var item = state.NowPlayingItem;
+function alertText(text, title) {
+ import('alert').then(({default: alert}) => {
+ alert({
+ text: text,
+ title: title
+ });
+ });
+}
- if (!item.ImageTags || !item.ImageTags.Primary) {
- if (item.PrimaryImageTag) {
- item.ImageTags = item.ImageTags || {};
- item.ImageTags.Primary = item.PrimaryImageTag;
- }
- }
- if (item.BackdropImageTag && item.BackdropItemId === item.Id) {
- item.BackdropImageTags = [item.BackdropImageTag];
- }
- if (item.BackdropImageTag && item.BackdropItemId !== item.Id) {
- item.ParentBackdropImageTags = [item.BackdropImageTag];
- item.ParentBackdropItemId = item.BackdropItemId;
+function onVolumeUpKeyDown() {
+ playbackManager.volumeUp();
+}
+
+function onVolumeDownKeyDown() {
+ playbackManager.volumeDown();
+}
+
+function normalizeImages(state) {
+ if (state && state.NowPlayingItem) {
+ const item = state.NowPlayingItem;
+
+ if (!item.ImageTags || !item.ImageTags.Primary) {
+ if (item.PrimaryImageTag) {
+ item.ImageTags = item.ImageTags || {};
+ item.ImageTags.Primary = item.PrimaryImageTag;
}
}
+ if (item.BackdropImageTag && item.BackdropItemId === item.Id) {
+ item.BackdropImageTags = [item.BackdropImageTag];
+ }
+ if (item.BackdropImageTag && item.BackdropItemId !== item.Id) {
+ item.ParentBackdropImageTags = [item.BackdropImageTag];
+ item.ParentBackdropItemId = item.BackdropItemId;
+ }
}
+}
- function getItemsForPlayback(apiClient, query) {
- var userId = apiClient.getCurrentUserId();
+function getItemsForPlayback(apiClient, query) {
+ const userId = apiClient.getCurrentUserId();
- if (query.Ids && query.Ids.split(',').length === 1) {
- return apiClient.getItem(userId, query.Ids.split(',')).then(function (item) {
- return {
- Items: [item],
- TotalRecordCount: 1
- };
- });
+ if (query.Ids && query.Ids.split(',').length === 1) {
+ return apiClient.getItem(userId, query.Ids.split(',')).then(function (item) {
+ return {
+ Items: [item],
+ TotalRecordCount: 1
+ };
+ });
+ } else {
+ query.Limit = query.Limit || 100;
+ query.ExcludeLocationTypes = 'Virtual';
+ query.EnableTotalRecordCount = false;
+
+ return apiClient.getItems(userId, query);
+ }
+}
+
+function bindEventForRelay(instance, eventName) {
+ events.on(instance._castPlayer, eventName, function (e, data) {
+ console.debug('cc: ' + eventName);
+ const state = instance.getPlayerStateInternal(data);
+
+ events.trigger(instance, eventName, [state]);
+ });
+}
+
+function initializeChromecast() {
+ const instance = this;
+ instance._castPlayer = new CastPlayer();
+
+ // To allow the native android app to override
+ document.dispatchEvent(new CustomEvent('chromecastloaded', {
+ detail: {
+ player: instance
+ }
+ }));
+
+ events.on(instance._castPlayer, 'connect', function (e) {
+ if (currentResolve) {
+ sendConnectionResult(true);
} else {
- query.Limit = query.Limit || 100;
- query.ExcludeLocationTypes = 'Virtual';
- query.EnableTotalRecordCount = false;
-
- return apiClient.getItems(userId, query);
+ playbackManager.setActivePlayer(PlayerName, instance.getCurrentTargetInfo());
}
- }
- function bindEventForRelay(instance, eventName) {
- events.on(instance._castPlayer, eventName, function (e, data) {
- console.debug('cc: ' + eventName);
- var state = instance.getPlayerStateInternal(data);
+ console.debug('cc: connect');
+ // Reset this so that statechange will fire
+ instance.lastPlayerData = null;
+ });
- events.trigger(instance, eventName, [state]);
- });
- }
+ events.on(instance._castPlayer, 'playbackstart', function (e, data) {
+ console.debug('cc: playbackstart');
- function initializeChromecast() {
- var instance = this;
- instance._castPlayer = new CastPlayer();
+ instance._castPlayer.initializeCastPlayer();
- // To allow the native android app to override
- document.dispatchEvent(new CustomEvent('chromecastloaded', {
- detail: {
- player: instance
- }
- }));
+ const state = instance.getPlayerStateInternal(data);
+ events.trigger(instance, 'playbackstart', [state]);
+ });
- events.on(instance._castPlayer, 'connect', function (e) {
- if (currentResolve) {
- sendConnectionResult(true);
- } else {
- playbackManager.setActivePlayer(PlayerName, instance.getCurrentTargetInfo());
- }
+ events.on(instance._castPlayer, 'playbackstop', function (e, data) {
+ console.debug('cc: playbackstop');
+ let state = instance.getPlayerStateInternal(data);
- console.debug('cc: connect');
- // Reset this so that statechange will fire
- instance.lastPlayerData = null;
- });
+ events.trigger(instance, 'playbackstop', [state]);
- events.on(instance._castPlayer, 'playbackstart', function (e, data) {
- console.debug('cc: playbackstart');
+ state = instance.lastPlayerData.PlayState || {};
+ const volume = state.VolumeLevel || 0.5;
+ const mute = state.IsMuted || false;
- instance._castPlayer.initializeCastPlayer();
+ // Reset this so the next query doesn't make it appear like content is playing.
+ instance.lastPlayerData = {};
+ instance.lastPlayerData.PlayState = {};
+ instance.lastPlayerData.PlayState.VolumeLevel = volume;
+ instance.lastPlayerData.PlayState.IsMuted = mute;
+ });
- var state = instance.getPlayerStateInternal(data);
- events.trigger(instance, 'playbackstart', [state]);
- });
+ events.on(instance._castPlayer, 'playbackprogress', function (e, data) {
+ console.debug('cc: positionchange');
+ const state = instance.getPlayerStateInternal(data);
- events.on(instance._castPlayer, 'playbackstop', function (e, data) {
- console.debug('cc: playbackstop');
- var state = instance.getPlayerStateInternal(data);
+ events.trigger(instance, 'timeupdate', [state]);
+ });
- events.trigger(instance, 'playbackstop', [state]);
+ bindEventForRelay(instance, 'timeupdate');
+ bindEventForRelay(instance, 'pause');
+ bindEventForRelay(instance, 'unpause');
+ bindEventForRelay(instance, 'volumechange');
+ bindEventForRelay(instance, 'repeatmodechange');
+ bindEventForRelay(instance, 'shufflequeuemodechange');
- state = instance.lastPlayerData.PlayState || {};
- var volume = state.VolumeLevel || 0.5;
- var mute = state.IsMuted || false;
+ events.on(instance._castPlayer, 'playstatechange', function (e, data) {
+ console.debug('cc: playstatechange');
+ const state = instance.getPlayerStateInternal(data);
- // Reset this so the next query doesn't make it appear like content is playing.
- instance.lastPlayerData = {};
- instance.lastPlayerData.PlayState = {};
- instance.lastPlayerData.PlayState.VolumeLevel = volume;
- instance.lastPlayerData.PlayState.IsMuted = mute;
- });
+ events.trigger(instance, 'pause', [state]);
+ });
+}
- events.on(instance._castPlayer, 'playbackprogress', function (e, data) {
- console.debug('cc: positionchange');
- var state = instance.getPlayerStateInternal(data);
-
- events.trigger(instance, 'timeupdate', [state]);
- });
-
- bindEventForRelay(instance, 'timeupdate');
- bindEventForRelay(instance, 'pause');
- bindEventForRelay(instance, 'unpause');
- bindEventForRelay(instance, 'volumechange');
- bindEventForRelay(instance, 'repeatmodechange');
- bindEventForRelay(instance, 'shufflequeuemodechange');
-
- events.on(instance._castPlayer, 'playstatechange', function (e, data) {
- console.debug('cc: playstatechange');
- var state = instance.getPlayerStateInternal(data);
-
- events.trigger(instance, 'pause', [state]);
- });
- }
-
- function ChromecastPlayer() {
+class ChromecastPlayer {
+ constructor() {
// playbackManager needs this
this.name = PlayerName;
this.type = 'mediaplayer';
@@ -579,11 +584,11 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
this.isLocalPlayer = false;
this.lastPlayerData = {};
- new castSenderApiLoader.default().load().then(initializeChromecast.bind(this));
+ new castSenderApiLoader().load().then(initializeChromecast.bind(this));
}
- ChromecastPlayer.prototype.tryPair = function (target) {
- var castPlayer = this._castPlayer;
+ tryPair(target) {
+ const castPlayer = this._castPlayer;
if (castPlayer.deviceState !== DEVICE_STATE.ACTIVE && castPlayer.isInitialized) {
return new Promise(function (resolve, reject) {
@@ -597,23 +602,23 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
return Promise.reject();
}
- };
+ }
- ChromecastPlayer.prototype.getTargets = function () {
- var targets = [];
+ getTargets() {
+ const targets = [];
if (this._castPlayer && this._castPlayer.hasReceivers) {
targets.push(this.getCurrentTargetInfo());
}
return Promise.resolve(targets);
- };
+ }
// This is a privately used method
- ChromecastPlayer.prototype.getCurrentTargetInfo = function () {
- var appName = null;
+ getCurrentTargetInfo() {
+ let appName = null;
- var castPlayer = this._castPlayer;
+ const castPlayer = this._castPlayer;
if (castPlayer.session && castPlayer.session.receiver && castPlayer.session.receiver.friendlyName) {
appName = castPlayer.session.receiver.friendlyName;
@@ -644,10 +649,10 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
'PlayTrailers'
]
};
- };
+ }
- ChromecastPlayer.prototype.getPlayerStateInternal = function (data) {
- var triggerStateChange = false;
+ getPlayerStateInternal(data) {
+ let triggerStateChange = false;
if (data && !this.lastPlayerData) {
triggerStateChange = true;
}
@@ -664,12 +669,12 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
}
return data;
- };
+ }
- ChromecastPlayer.prototype.playWithCommand = function (options, command) {
+ playWithCommand(options, command) {
if (!options.items) {
- var apiClient = connectionManager.getApiClient(options.serverId);
- var instance = this;
+ const apiClient = connectionManager.getApiClient(options.serverId);
+ const instance = this;
return apiClient.getItem(apiClient.getCurrentUserId(), options.ids[0]).then(function (item) {
options.items = [item];
@@ -685,9 +690,9 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
}
return this._castPlayer.loadMedia(options, command);
- };
+ }
- ChromecastPlayer.prototype.seek = function (position) {
+ seek(position) {
position = parseInt(position);
position = position / 10000000;
@@ -698,55 +703,55 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
},
command: 'Seek'
});
- };
+ }
- ChromecastPlayer.prototype.setAudioStreamIndex = function (index) {
+ setAudioStreamIndex(index) {
this._castPlayer.sendMessage({
options: {
index: index
},
command: 'SetAudioStreamIndex'
});
- };
+ }
- ChromecastPlayer.prototype.setSubtitleStreamIndex = function (index) {
+ setSubtitleStreamIndex(index) {
this._castPlayer.sendMessage({
options: {
index: index
},
command: 'SetSubtitleStreamIndex'
});
- };
+ }
- ChromecastPlayer.prototype.setMaxStreamingBitrate = function (options) {
+ setMaxStreamingBitrate(options) {
this._castPlayer.sendMessage({
options: options,
command: 'SetMaxStreamingBitrate'
});
- };
+ }
- ChromecastPlayer.prototype.isFullscreen = function () {
- var state = this.lastPlayerData || {};
+ isFullscreen() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.IsFullscreen;
- };
+ }
- ChromecastPlayer.prototype.nextTrack = function () {
+ nextTrack() {
this._castPlayer.sendMessage({
options: {},
command: 'NextTrack'
});
- };
+ }
- ChromecastPlayer.prototype.previousTrack = function () {
+ previousTrack() {
this._castPlayer.sendMessage({
options: {},
command: 'PreviousTrack'
});
- };
+ }
- ChromecastPlayer.prototype.volumeDown = function () {
- var vol = this._castPlayer.session.receiver.volume.level;
+ volumeDown() {
+ let vol = this._castPlayer.session.receiver.volume.level;
if (vol == null) {
vol = 0.5;
}
@@ -754,20 +759,20 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
vol = Math.max(vol, 0);
this._castPlayer.session.setReceiverVolumeLevel(vol);
- };
+ }
- ChromecastPlayer.prototype.endSession = function () {
- var instance = this;
+ endSession() {
+ const instance = this;
this.stop().then(function () {
setTimeout(function () {
instance._castPlayer.stopApp();
}, 1000);
});
- };
+ }
- ChromecastPlayer.prototype.volumeUp = function () {
- var vol = this._castPlayer.session.receiver.volume.level;
+ volumeUp() {
+ let vol = this._castPlayer.session.receiver.volume.level;
if (vol == null) {
vol = 0.5;
}
@@ -775,53 +780,53 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
vol = Math.min(vol, 1);
this._castPlayer.session.setReceiverVolumeLevel(vol);
- };
+ }
- ChromecastPlayer.prototype.setVolume = function (vol) {
+ setVolume(vol) {
vol = Math.min(vol, 100);
vol = Math.max(vol, 0);
vol = vol / 100;
this._castPlayer.session.setReceiverVolumeLevel(vol);
- };
+ }
- ChromecastPlayer.prototype.unpause = function () {
+ unpause() {
this._castPlayer.sendMessage({
options: {},
command: 'Unpause'
});
- };
+ }
- ChromecastPlayer.prototype.playPause = function () {
+ playPause() {
this._castPlayer.sendMessage({
options: {},
command: 'PlayPause'
});
- };
+ }
- ChromecastPlayer.prototype.pause = function () {
+ pause() {
this._castPlayer.sendMessage({
options: {},
command: 'Pause'
});
- };
+ }
- ChromecastPlayer.prototype.stop = function () {
+ stop() {
return this._castPlayer.sendMessage({
options: {},
command: 'Stop'
});
- };
+ }
- ChromecastPlayer.prototype.displayContent = function (options) {
+ displayContent(options) {
this._castPlayer.sendMessage({
options: options,
command: 'DisplayContent'
});
- };
+ }
- ChromecastPlayer.prototype.setMute = function (isMuted) {
- var castPlayer = this._castPlayer;
+ setMute(isMuted) {
+ const castPlayer = this._castPlayer;
if (isMuted) {
castPlayer.sendMessage({
@@ -834,21 +839,21 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
command: 'Unmute'
});
}
- };
+ }
- ChromecastPlayer.prototype.getRepeatMode = function () {
- var state = this.lastPlayerData || {};
+ getRepeatMode() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.RepeatMode;
- };
+ }
- ChromecastPlayer.prototype.getQueueShuffleMode = function () {
- var state = this.lastPlayerData || {};
+ getQueueShuffleMode() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.ShuffleMode;
- };
+ }
- ChromecastPlayer.prototype.playTrailers = function (item) {
+ playTrailers(item) {
this._castPlayer.sendMessage({
options: {
ItemId: item.Id,
@@ -856,177 +861,173 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
},
command: 'PlayTrailers'
});
- };
+ }
- ChromecastPlayer.prototype.setRepeatMode = function (mode) {
+ setRepeatMode(mode) {
this._castPlayer.sendMessage({
options: {
RepeatMode: mode
},
command: 'SetRepeatMode'
});
- };
+ }
- ChromecastPlayer.prototype.setQueueShuffleMode = function (value) {
+ setQueueShuffleMode(value) {
this._castPlayer.sendMessage({
options: {
ShuffleMode: value
},
command: 'SetShuffleQueue'
});
- };
+ }
- ChromecastPlayer.prototype.toggleMute = function () {
+ toggleMute() {
this._castPlayer.sendMessage({
options: {},
command: 'ToggleMute'
});
- };
+ }
- ChromecastPlayer.prototype.audioTracks = function () {
- var state = this.lastPlayerData || {};
+ audioTracks() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
- var streams = state.MediaStreams || [];
+ const streams = state.MediaStreams || [];
return streams.filter(function (s) {
return s.Type === 'Audio';
});
- };
+ }
- ChromecastPlayer.prototype.getAudioStreamIndex = function () {
- var state = this.lastPlayerData || {};
+ getAudioStreamIndex() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.AudioStreamIndex;
- };
+ }
- ChromecastPlayer.prototype.subtitleTracks = function () {
- var state = this.lastPlayerData || {};
+ subtitleTracks() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
- var streams = state.MediaStreams || [];
+ const streams = state.MediaStreams || [];
return streams.filter(function (s) {
return s.Type === 'Subtitle';
});
- };
+ }
- ChromecastPlayer.prototype.getSubtitleStreamIndex = function () {
- var state = this.lastPlayerData || {};
+ getSubtitleStreamIndex() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.SubtitleStreamIndex;
- };
+ }
- ChromecastPlayer.prototype.getMaxStreamingBitrate = function () {
- var state = this.lastPlayerData || {};
+ getMaxStreamingBitrate() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.MaxStreamingBitrate;
- };
+ }
- ChromecastPlayer.prototype.getVolume = function () {
- var state = this.lastPlayerData || {};
+ getVolume() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.VolumeLevel == null ? 100 : state.VolumeLevel;
- };
+ }
- ChromecastPlayer.prototype.isPlaying = function () {
- var state = this.lastPlayerData || {};
+ isPlaying() {
+ const state = this.lastPlayerData || {};
return state.NowPlayingItem != null;
- };
+ }
- ChromecastPlayer.prototype.isPlayingVideo = function () {
- var state = this.lastPlayerData || {};
+ isPlayingVideo() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.MediaType === 'Video';
- };
+ }
- ChromecastPlayer.prototype.isPlayingAudio = function () {
- var state = this.lastPlayerData || {};
+ isPlayingAudio() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.MediaType === 'Audio';
- };
+ }
- ChromecastPlayer.prototype.currentTime = function (val) {
+ currentTime(val) {
if (val != null) {
return this.seek(val);
}
- var state = this.lastPlayerData || {};
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.PositionTicks;
- };
+ }
- ChromecastPlayer.prototype.duration = function () {
- var state = this.lastPlayerData || {};
+ duration() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.RunTimeTicks;
- };
+ }
- ChromecastPlayer.prototype.getBufferedRanges = function () {
- var state = this.lastPlayerData || {};
+ getBufferedRanges() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.BufferedRanges || [];
- };
+ }
- ChromecastPlayer.prototype.paused = function () {
- var state = this.lastPlayerData || {};
+ paused() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.IsPaused;
- };
+ }
- ChromecastPlayer.prototype.isMuted = function () {
- var state = this.lastPlayerData || {};
+ isMuted() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.IsMuted;
- };
+ }
- ChromecastPlayer.prototype.shuffle = function (item) {
- var apiClient = connectionManager.getApiClient(item.ServerId);
- var userId = apiClient.getCurrentUserId();
+ shuffle(item) {
+ const apiClient = connectionManager.getApiClient(item.ServerId);
+ const userId = apiClient.getCurrentUserId();
- var instance = this;
+ const instance = this;
apiClient.getItem(userId, item.Id).then(function (item) {
instance.playWithCommand({
-
items: [item]
-
}, 'Shuffle');
});
- };
+ }
- ChromecastPlayer.prototype.instantMix = function (item) {
- var apiClient = connectionManager.getApiClient(item.ServerId);
- var userId = apiClient.getCurrentUserId();
+ instantMix(item) {
+ const apiClient = connectionManager.getApiClient(item.ServerId);
+ const userId = apiClient.getCurrentUserId();
- var instance = this;
+ const instance = this;
apiClient.getItem(userId, item.Id).then(function (item) {
instance.playWithCommand({
-
items: [item]
-
}, 'InstantMix');
});
- };
+ }
- ChromecastPlayer.prototype.canPlayMediaType = function (mediaType) {
+ canPlayMediaType(mediaType) {
mediaType = (mediaType || '').toLowerCase();
return mediaType === 'audio' || mediaType === 'video';
- };
+ }
- ChromecastPlayer.prototype.canQueueMediaType = function (mediaType) {
+ canQueueMediaType(mediaType) {
return this.canPlayMediaType(mediaType);
- };
+ }
- ChromecastPlayer.prototype.queue = function (options) {
+ queue(options) {
this.playWithCommand(options, 'PlayLast');
- };
+ }
- ChromecastPlayer.prototype.queueNext = function (options) {
+ queueNext(options) {
this.playWithCommand(options, 'PlayNext');
- };
+ }
- ChromecastPlayer.prototype.play = function (options) {
+ play(options) {
if (options.items) {
return this.playWithCommand(options, 'PlayNow');
} else {
@@ -1034,50 +1035,48 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
throw new Error('serverId required!');
}
- var instance = this;
- var apiClient = connectionManager.getApiClient(options.serverId);
+ const instance = this;
+ const apiClient = connectionManager.getApiClient(options.serverId);
return getItemsForPlayback(apiClient, {
-
Ids: options.ids.join(',')
-
}).then(function (result) {
options.items = result.Items;
return instance.playWithCommand(options, 'PlayNow');
});
}
- };
+ }
- ChromecastPlayer.prototype.toggleFullscreen = function () {
+ toggleFullscreen() {
// not supported
- };
+ }
- ChromecastPlayer.prototype.beginPlayerUpdates = function () {
+ beginPlayerUpdates() {
// Setup polling here
- };
+ }
- ChromecastPlayer.prototype.endPlayerUpdates = function () {
+ endPlayerUpdates() {
// Stop polling here
- };
+ }
- ChromecastPlayer.prototype.getPlaylist = function () {
+ getPlaylist() {
return Promise.resolve([]);
- };
+ }
- ChromecastPlayer.prototype.getCurrentPlaylistItemId = function () {
- };
+ getCurrentPlaylistItemId() {
+ }
- ChromecastPlayer.prototype.setCurrentPlaylistItem = function (playlistItemId) {
+ setCurrentPlaylistItem(playlistItemId) {
return Promise.resolve();
- };
+ }
- ChromecastPlayer.prototype.removeFromPlaylist = function (playlistItemIds) {
+ removeFromPlaylist(playlistItemIds) {
return Promise.resolve();
- };
+ }
- ChromecastPlayer.prototype.getPlayerState = function () {
+ getPlayerState() {
return this.getPlayerStateInternal() || {};
- };
+ }
+}
- return ChromecastPlayer;
-});
+export default ChromecastPlayer;
diff --git a/src/plugins/experimentalWarnings/plugin.js b/src/plugins/experimentalWarnings/plugin.js
index c39612d45..bc301f01a 100644
--- a/src/plugins/experimentalWarnings/plugin.js
+++ b/src/plugins/experimentalWarnings/plugin.js
@@ -1,59 +1,61 @@
-define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (connectionManager, globalize, userSettings, appHost) {
- 'use strict';
+import globalize from 'globalize';
+import * as userSettings from 'userSettings';
+import appHost from 'apphost';
- // TODO: Replace with date-fns
- // https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
- function getWeek(date) {
- var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
- var dayNum = d.getUTCDay() || 7;
- d.setUTCDate(d.getUTCDate() + 4 - dayNum);
- var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
- return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
+// TODO: Replace with date-fns
+// https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
+function getWeek(date) {
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
+ const dayNum = d.getUTCDay() || 7;
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
+ return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
+}
+
+function showMessage(text, userSettingsKey, appHostFeature) {
+ if (appHost.supports(appHostFeature)) {
+ return Promise.resolve();
}
- function showMessage(text, userSettingsKey, appHostFeature) {
- if (appHost.supports(appHostFeature)) {
- return Promise.resolve();
- }
+ const now = new Date();
- var now = new Date();
+ // TODO: Use date-fns
+ userSettingsKey += now.getFullYear() + '-w' + getWeek(now);
- // TODO: Use date-fns
- userSettingsKey += now.getFullYear() + '-w' + getWeek(now);
+ if (userSettings.get(userSettingsKey, false) === '1') {
+ return Promise.resolve();
+ }
- if (userSettings.get(userSettingsKey, false) === '1') {
- return Promise.resolve();
- }
+ return new Promise(function (resolve, reject) {
+ userSettings.set(userSettingsKey, '1', false);
- return new Promise(function (resolve, reject) {
- userSettings.set(userSettingsKey, '1', false);
-
- require(['alert'], function (alert) {
- return alert(text).then(resolve, resolve);
- });
+ import('alert').then(({default: alert}) => {
+ return alert(text).then(resolve, resolve);
});
- }
+ });
+}
- function showBlurayMessage() {
- return showMessage(globalize.translate('UnsupportedPlayback'), 'blurayexpirementalinfo', 'nativeblurayplayback');
- }
+function showBlurayMessage() {
+ return showMessage(globalize.translate('UnsupportedPlayback'), 'blurayexpirementalinfo', 'nativeblurayplayback');
+}
- function showDvdMessage() {
- return showMessage(globalize.translate('UnsupportedPlayback'), 'dvdexpirementalinfo', 'nativedvdplayback');
- }
+function showDvdMessage() {
+ return showMessage(globalize.translate('UnsupportedPlayback'), 'dvdexpirementalinfo', 'nativedvdplayback');
+}
- function showIsoMessage() {
- return showMessage(globalize.translate('UnsupportedPlayback'), 'isoexpirementalinfo', 'nativeisoplayback');
- }
+function showIsoMessage() {
+ return showMessage(globalize.translate('UnsupportedPlayback'), 'isoexpirementalinfo', 'nativeisoplayback');
+}
- function ExpirementalPlaybackWarnings() {
+class ExpirementalPlaybackWarnings {
+ constructor() {
this.name = 'Experimental playback warnings';
this.type = 'preplayintercept';
this.id = 'expirementalplaybackwarnings';
}
- ExpirementalPlaybackWarnings.prototype.intercept = function (options) {
- var item = options.item;
+ intercept(options) {
+ const item = options.item;
if (!item) {
return Promise.resolve();
}
@@ -71,7 +73,7 @@ define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (
}
return Promise.resolve();
- };
+ }
+}
- return ExpirementalPlaybackWarnings;
-});
+export default ExpirementalPlaybackWarnings;
diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js
index 16fce8c9d..acce15df8 100644
--- a/src/plugins/htmlAudioPlayer/plugin.js
+++ b/src/plugins/htmlAudioPlayer/plugin.js
@@ -1,91 +1,92 @@
-define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelper'], function (events, browser, require, appHost, appSettings, htmlMediaHelper) {
- 'use strict';
+import events from 'events';
+import browser from 'browser';
+import appHost from 'apphost';
+import * as htmlMediaHelper from 'htmlMediaHelper';
- function getDefaultProfile() {
- return new Promise(function (resolve, reject) {
- require(['browserdeviceprofile'], function (profileBuilder) {
- resolve(profileBuilder({}));
- });
+function getDefaultProfile() {
+ return import('browserdeviceprofile').then(({ default: profileBuilder }) => {
+ return profileBuilder({});
+ });
+}
+
+let fadeTimeout;
+function fade(instance, elem, startingVolume) {
+ instance._isFadingOut = true;
+
+ // Need to record the starting volume on each pass rather than querying elem.volume
+ // This is due to iOS safari not allowing volume changes and always returning the system volume value
+ const newVolume = Math.max(0, startingVolume - 0.15);
+ console.debug('fading volume to ' + newVolume);
+ elem.volume = newVolume;
+
+ if (newVolume <= 0) {
+ instance._isFadingOut = false;
+ return Promise.resolve();
+ }
+
+ return new Promise(function (resolve, reject) {
+ cancelFadeTimeout();
+ fadeTimeout = setTimeout(function () {
+ fade(instance, elem, newVolume).then(resolve, reject);
+ }, 100);
+ });
+}
+
+function cancelFadeTimeout() {
+ const timeout = fadeTimeout;
+ if (timeout) {
+ clearTimeout(timeout);
+ fadeTimeout = null;
+ }
+}
+
+function supportsFade() {
+ if (browser.tv) {
+ // Not working on tizen.
+ // We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive
+ return false;
+ }
+
+ return true;
+}
+
+function requireHlsPlayer(callback) {
+ import('hlsjs').then(({ default: hls }) => {
+ window.Hls = hls;
+ callback();
+ });
+}
+
+function enableHlsPlayer(url, item, mediaSource, mediaType) {
+ if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) {
+ return Promise.reject();
+ }
+
+ if (url.indexOf('.m3u8') !== -1) {
+ return Promise.resolve();
+ }
+
+ // issue head request to get content type
+ return new Promise(function (resolve, reject) {
+ import('fetchHelper').then((fetchHelper) => {
+ fetchHelper.ajax({
+ url: url,
+ type: 'HEAD'
+ }).then(function (response) {
+ const contentType = (response.headers.get('Content-Type') || '').toLowerCase();
+ if (contentType === 'application/x-mpegurl') {
+ resolve();
+ } else {
+ reject();
+ }
+ }, reject);
});
- }
+ });
+}
- var fadeTimeout;
- function fade(instance, elem, startingVolume) {
- instance._isFadingOut = true;
-
- // Need to record the starting volume on each pass rather than querying elem.volume
- // This is due to iOS safari not allowing volume changes and always returning the system volume value
- var newVolume = Math.max(0, startingVolume - 0.15);
- console.debug('fading volume to ' + newVolume);
- elem.volume = newVolume;
-
- if (newVolume <= 0) {
- instance._isFadingOut = false;
- return Promise.resolve();
- }
-
- return new Promise(function (resolve, reject) {
- cancelFadeTimeout();
- fadeTimeout = setTimeout(function () {
- fade(instance, elem, newVolume).then(resolve, reject);
- }, 100);
- });
- }
-
- function cancelFadeTimeout() {
- var timeout = fadeTimeout;
- if (timeout) {
- clearTimeout(timeout);
- fadeTimeout = null;
- }
- }
-
- function supportsFade() {
- if (browser.tv) {
- // Not working on tizen.
- // We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive
- return false;
- }
-
- return true;
- }
-
- function requireHlsPlayer(callback) {
- require(['hlsjs'], function (hls) {
- window.Hls = hls;
- callback();
- });
- }
-
- function enableHlsPlayer(url, item, mediaSource, mediaType) {
- if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) {
- return Promise.reject();
- }
-
- if (url.indexOf('.m3u8') !== -1) {
- return Promise.resolve();
- }
-
- // issue head request to get content type
- return new Promise(function (resolve, reject) {
- require(['fetchHelper'], function (fetchHelper) {
- fetchHelper.ajax({
- url: url,
- type: 'HEAD'
- }).then(function (response) {
- var contentType = (response.headers.get('Content-Type') || '').toLowerCase();
- if (contentType === 'application/x-mpegurl') {
- resolve();
- } else {
- reject();
- }
- }, reject);
- });
- });
- }
-
- function HtmlAudioPlayer() {
- var self = this;
+class HtmlAudioPlayer {
+ constructor() {
+ const self = this;
self.name = 'Html Audio Player';
self.type = 'mediaplayer';
@@ -99,7 +100,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
self._timeUpdated = false;
self._currentTime = null;
- var elem = createMediaElement();
+ const elem = createMediaElement();
return setCurrentSrc(elem, options);
};
@@ -109,11 +110,11 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
unBindEvents(elem);
bindEvents(elem);
- var val = options.url;
+ let val = options.url;
console.debug('playing url: ' + val);
// Convert to seconds
- var seconds = (options.playerStartPositionTicks || 0) / 10000000;
+ const seconds = (options.playerStartPositionTicks || 0) / 10000000;
if (seconds) {
val += '#t=' + seconds;
}
@@ -122,7 +123,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
self._currentPlayOptions = options;
- var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
+ const crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
if (crossOrigin) {
elem.crossOrigin = crossOrigin;
}
@@ -130,9 +131,9 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
return enableHlsPlayer(val, options.item, options.mediaSource, 'Audio').then(function () {
return new Promise(function (resolve, reject) {
requireHlsPlayer(function () {
- var hls = new Hls({
+ const hls = new Hls({
manifestLoadingTimeOut: 20000,
- xhrSetup: function(xhr, url) {
+ xhrSetup: function (xhr, url) {
xhr.withCredentials = true;
}
});
@@ -183,8 +184,8 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
self.stop = function (destroyPlayer) {
cancelFadeTimeout();
- var elem = self._mediaElement;
- var src = self._currentSrc;
+ const elem = self._mediaElement;
+ const src = self._currentSrc;
if (elem && src) {
if (!destroyPlayer || !supportsFade()) {
@@ -198,7 +199,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
return Promise.resolve();
}
- var originalVolume = elem.volume;
+ const originalVolume = elem.volume;
return fade(self, elem, elem.volume).then(function () {
elem.pause();
@@ -219,7 +220,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
};
function createMediaElement() {
- var elem = self._mediaElement;
+ let elem = self._mediaElement;
if (elem) {
return elem;
@@ -248,7 +249,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
function onTimeUpdate() {
// Get the player position + the transcoding offset
- var time = this.currentTime;
+ const time = this.currentTime;
// Don't trigger events after user stop
if (!self._isFadingOut) {
@@ -287,11 +288,11 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
}
function onError() {
- var errorCode = this.error ? (this.error.code || 0) : 0;
- var errorMessage = this.error ? (this.error.message || '') : '';
+ const errorCode = this.error ? (this.error.code || 0) : 0;
+ const errorMessage = this.error ? (this.error.message || '') : '';
console.error('media element error: ' + errorCode.toString() + ' ' + errorMessage);
- var type;
+ let type;
switch (errorCode) {
case 1:
@@ -325,59 +326,59 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
}
}
- HtmlAudioPlayer.prototype.currentSrc = function () {
+ currentSrc() {
return this._currentSrc;
- };
+ }
- HtmlAudioPlayer.prototype.canPlayMediaType = function (mediaType) {
+ canPlayMediaType(mediaType) {
return (mediaType || '').toLowerCase() === 'audio';
- };
+ }
- HtmlAudioPlayer.prototype.getDeviceProfile = function (item) {
+ getDeviceProfile(item) {
if (appHost.getDeviceProfile) {
return appHost.getDeviceProfile(item);
}
return getDefaultProfile();
- };
+ }
// Save this for when playback stops, because querying the time at that point might return 0
- HtmlAudioPlayer.prototype.currentTime = function (val) {
- var mediaElement = this._mediaElement;
+ currentTime(val) {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
if (val != null) {
mediaElement.currentTime = val / 1000;
return;
}
- var currentTime = this._currentTime;
+ const currentTime = this._currentTime;
if (currentTime) {
return currentTime * 1000;
}
return (mediaElement.currentTime || 0) * 1000;
}
- };
+ }
- HtmlAudioPlayer.prototype.duration = function (val) {
- var mediaElement = this._mediaElement;
+ duration(val) {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
- var duration = mediaElement.duration;
+ const duration = mediaElement.duration;
if (htmlMediaHelper.isValidDuration(duration)) {
return duration * 1000;
}
}
return null;
- };
+ }
- HtmlAudioPlayer.prototype.seekable = function () {
- var mediaElement = this._mediaElement;
+ seekable() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
- var seekable = mediaElement.seekable;
+ const seekable = mediaElement.seekable;
if (seekable && seekable.length) {
- var start = seekable.start(0);
- var end = seekable.end(0);
+ let start = seekable.start(0);
+ let end = seekable.end(0);
if (!htmlMediaHelper.isValidDuration(start)) {
start = 0;
@@ -391,124 +392,120 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp
return false;
}
- };
+ }
- HtmlAudioPlayer.prototype.getBufferedRanges = function () {
- var mediaElement = this._mediaElement;
+ getBufferedRanges() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
return htmlMediaHelper.getBufferedRanges(this, mediaElement);
}
return [];
- };
+ }
- HtmlAudioPlayer.prototype.pause = function () {
- var mediaElement = this._mediaElement;
+ pause() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
mediaElement.pause();
}
- };
+ }
// This is a retry after error
- HtmlAudioPlayer.prototype.resume = function () {
- var mediaElement = this._mediaElement;
+ resume() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
mediaElement.play();
}
- };
+ }
- HtmlAudioPlayer.prototype.unpause = function () {
- var mediaElement = this._mediaElement;
+ unpause() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
mediaElement.play();
}
- };
+ }
- HtmlAudioPlayer.prototype.paused = function () {
- var mediaElement = this._mediaElement;
+ paused() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
return mediaElement.paused;
}
return false;
- };
+ }
- HtmlAudioPlayer.prototype.setPlaybackRate = function (value) {
- var mediaElement = this._mediaElement;
+ setPlaybackRate(value) {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
mediaElement.playbackRate = value;
}
- };
+ }
- HtmlAudioPlayer.prototype.getPlaybackRate = function () {
- var mediaElement = this._mediaElement;
+ getPlaybackRate() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
return mediaElement.playbackRate;
}
return null;
- };
+ }
- HtmlAudioPlayer.prototype.setVolume = function (val) {
- var mediaElement = this._mediaElement;
+ setVolume(val) {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
mediaElement.volume = val / 100;
}
- };
+ }
- HtmlAudioPlayer.prototype.getVolume = function () {
- var mediaElement = this._mediaElement;
+ getVolume() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
return Math.min(Math.round(mediaElement.volume * 100), 100);
}
- };
+ }
- HtmlAudioPlayer.prototype.volumeUp = function () {
+ volumeUp() {
this.setVolume(Math.min(this.getVolume() + 2, 100));
- };
+ }
- HtmlAudioPlayer.prototype.volumeDown = function () {
+ volumeDown() {
this.setVolume(Math.max(this.getVolume() - 2, 0));
- };
+ }
- HtmlAudioPlayer.prototype.setMute = function (mute) {
- var mediaElement = this._mediaElement;
+ setMute(mute) {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
mediaElement.muted = mute;
}
- };
+ }
- HtmlAudioPlayer.prototype.isMuted = function () {
- var mediaElement = this._mediaElement;
+ isMuted() {
+ const mediaElement = this._mediaElement;
if (mediaElement) {
return mediaElement.muted;
}
return false;
- };
-
- HtmlAudioPlayer.prototype.destroy = function () {
-
- };
-
- var supportedFeatures;
-
- function getSupportedFeatures() {
- var list = [];
- var audio = document.createElement('audio');
-
- if (typeof audio.playbackRate === 'number') {
- list.push('PlaybackRate');
- }
-
- return list;
}
- HtmlAudioPlayer.prototype.supports = function (feature) {
+ supports(feature) {
if (!supportedFeatures) {
supportedFeatures = getSupportedFeatures();
}
return supportedFeatures.indexOf(feature) !== -1;
- };
+ }
+}
- return HtmlAudioPlayer;
-});
+let supportedFeatures;
+
+function getSupportedFeatures() {
+ const list = [];
+ const audio = document.createElement('audio');
+
+ if (typeof audio.playbackRate === 'number') {
+ list.push('PlaybackRate');
+ }
+
+ return list;
+}
+
+export default HtmlAudioPlayer;
diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js
index 525372ac8..58c8624e3 100644
--- a/src/plugins/htmlVideoPlayer/plugin.js
+++ b/src/plugins/htmlVideoPlayer/plugin.js
@@ -105,7 +105,7 @@ function tryRemoveElement(elem) {
}
function hidePrePlaybackPage() {
- let animatedPage = document.querySelector('.page:not(.hide)');
+ const animatedPage = document.querySelector('.page:not(.hide)');
animatedPage.classList.add('hide');
// At this point, we must hide the scrollbar placeholder, so it's not being displayed while the item is being loaded
document.body.classList.remove('force-scroll');
@@ -150,7 +150,7 @@ function tryRemoveElement(elem) {
/**
* @type {string}
*/
- name
+ name;
/**
* @type {string}
*/
@@ -730,7 +730,7 @@ function tryRemoveElement(elem) {
const elem = e.target;
this.destroyCustomTrack(elem);
onEndedInternal(this, elem, this.onError);
- }
+ };
/**
* @private
@@ -760,7 +760,7 @@ function tryRemoveElement(elem) {
}
events.trigger(this, 'timeupdate');
- }
+ };
/**
* @private
@@ -773,7 +773,7 @@ function tryRemoveElement(elem) {
const elem = e.target;
saveVolume(elem.volume);
events.trigger(this, 'volumechange');
- }
+ };
/**
* @private
@@ -785,7 +785,7 @@ function tryRemoveElement(elem) {
this.onStartedAndNavigatedToOsd();
}
- }
+ };
/**
* @private
@@ -832,14 +832,14 @@ function tryRemoveElement(elem) {
}
}
events.trigger(this, 'playing');
- }
+ };
/**
* @private
*/
onPlay = () => {
events.trigger(this, 'unpause');
- }
+ };
/**
* @private
@@ -865,21 +865,21 @@ function tryRemoveElement(elem) {
*/
onClick = () => {
events.trigger(this, 'click');
- }
+ };
/**
* @private
*/
onDblClick = () => {
events.trigger(this, 'dblclick');
- }
+ };
/**
* @private
*/
onPause = () => {
events.trigger(this, 'pause');
- }
+ };
onWaiting() {
events.trigger(this, 'waiting');
@@ -929,7 +929,7 @@ function tryRemoveElement(elem) {
}
onErrorInternal(this, type);
- }
+ };
/**
* @private
@@ -1299,7 +1299,7 @@ function tryRemoveElement(elem) {
}
let html = '';
- let cssClass = 'htmlvideoplayer';
+ const cssClass = 'htmlvideoplayer';
// Can't autoplay in these browsers so we need to use the full controls, at least until playback starts
if (!appHost.supports('htmlvideoautoplay')) {
@@ -1634,6 +1634,31 @@ function tryRemoveElement(elem) {
return null;
}
+ getSupportedPlaybackRates() {
+ return [{
+ name: '0.5x',
+ id: 0.5
+ }, {
+ name: '0.75x',
+ id: 0.75
+ }, {
+ name: '1x',
+ id: 1.0
+ }, {
+ name: '1.25x',
+ id: 1.25
+ }, {
+ name: '1.5x',
+ id: 1.5
+ }, {
+ name: '1.75x',
+ id: 1.75
+ }, {
+ name: '2x',
+ id: 2.0
+ }];
+ }
+
setVolume(val) {
const mediaElement = this.#mediaElement;
if (mediaElement) {
diff --git a/src/plugins/logoScreensaver/plugin.js b/src/plugins/logoScreensaver/plugin.js
index bdd1d34e7..61b8f8a6d 100644
--- a/src/plugins/logoScreensaver/plugin.js
+++ b/src/plugins/logoScreensaver/plugin.js
@@ -1,165 +1,165 @@
-define(['pluginManager'], function (pluginManager) {
- return function () {
- var self = this;
+import pluginManager from 'pluginManager';
- self.name = 'Logo ScreenSaver';
- self.type = 'screensaver';
- self.id = 'logoscreensaver';
- self.supportsAnonymous = true;
+export default function () {
+ const self = this;
- var interval;
+ self.name = 'Logo ScreenSaver';
+ self.type = 'screensaver';
+ self.id = 'logoscreensaver';
+ self.supportsAnonymous = true;
- function animate() {
- var animations = [
+ let interval;
- bounceInLeft,
- bounceInRight,
- swing,
- tada,
- wobble,
- rotateIn,
- rotateOut
- ];
+ function animate() {
+ const animations = [
- var elem = document.querySelector('.logoScreenSaverImage');
+ bounceInLeft,
+ bounceInRight,
+ swing,
+ tada,
+ wobble,
+ rotateIn,
+ rotateOut
+ ];
- if (elem && elem.animate) {
- var random = getRandomInt(0, animations.length - 1);
+ const elem = document.querySelector('.logoScreenSaverImage');
- animations[random](elem, 1);
+ if (elem && elem.animate) {
+ const random = getRandomInt(0, animations.length - 1);
+
+ animations[random](elem, 1);
+ }
+ }
+
+ function getRandomInt(min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+ }
+
+ function bounceInLeft(elem, iterations) {
+ const keyframes = [
+ { transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 },
+ { transform: 'translate3d(25px, 0, 0)', opacity: '1', offset: 0.6 },
+ { transform: 'translate3d(-100px, 0, 0)', offset: 0.75 },
+ { transform: 'translate3d(5px, 0, 0)', offset: 0.9 },
+ { transform: 'none', opacity: '1', offset: 1 }];
+ const timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
+ return elem.animate(keyframes, timing);
+ }
+
+ function bounceInRight(elem, iterations) {
+ const keyframes = [
+ { transform: 'translate3d(3000px, 0, 0)', opacity: '0', offset: 0 },
+ { transform: 'translate3d(-25px, 0, 0)', opacity: '1', offset: 0.6 },
+ { transform: 'translate3d(100px, 0, 0)', offset: 0.75 },
+ { transform: 'translate3d(-5px, 0, 0)', offset: 0.9 },
+ { transform: 'none', opacity: '1', offset: 1 }];
+ const timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
+ return elem.animate(keyframes, timing);
+ }
+
+ function swing(elem, iterations) {
+ const keyframes = [
+ { transform: 'translate(0%)', offset: 0 },
+ { transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 },
+ { transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 },
+ { transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 },
+ { transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 },
+ { transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }];
+ const timing = { duration: 900, iterations: iterations };
+ return elem.animate(keyframes, timing);
+ }
+
+ function tada(elem, iterations) {
+ const keyframes = [
+ { transform: 'scale3d(1, 1, 1)', offset: 0 },
+ { transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.1 },
+ { transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.2 },
+ { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.3 },
+ { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.4 },
+ { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.5 },
+ { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.6 },
+ { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.7 },
+ { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.8 },
+ { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.9 },
+ { transform: 'scale3d(1, 1, 1)', offset: 1 }];
+ const timing = { duration: 900, iterations: iterations };
+ return elem.animate(keyframes, timing);
+ }
+
+ function wobble(elem, iterations) {
+ const keyframes = [
+ { transform: 'translate(0%)', offset: 0 },
+ { transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', offset: 0.15 },
+ { transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', offset: 0.45 },
+ { transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', offset: 0.6 },
+ { transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', offset: 0.75 },
+ { transform: 'translateX(0%)', offset: 1 }];
+ const timing = { duration: 900, iterations: iterations };
+ return elem.animate(keyframes, timing);
+ }
+
+ function rotateIn(elem, iterations) {
+ const keyframes = [{ transform: 'rotate3d(0, 0, 1, -200deg)', opacity: '0', transformOrigin: 'center', offset: 0 },
+ { transform: 'none', opacity: '1', transformOrigin: 'center', offset: 1 }];
+ const timing = { duration: 900, iterations: iterations };
+ return elem.animate(keyframes, timing);
+ }
+
+ function rotateOut(elem, iterations) {
+ const keyframes = [{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 0 },
+ { transform: 'rotate3d(0, 0, 1, 200deg)', opacity: '0', transformOrigin: 'center', offset: 1 }];
+ const timing = { duration: 900, iterations: iterations };
+ return elem.animate(keyframes, timing);
+ }
+
+ function fadeOut(elem, iterations) {
+ const keyframes = [
+ { opacity: '1', offset: 0 },
+ { opacity: '0', offset: 1 }];
+ const timing = { duration: 400, iterations: iterations };
+ return elem.animate(keyframes, timing);
+ }
+
+ function stopInterval() {
+ if (interval) {
+ clearInterval(interval);
+ interval = null;
+ }
+ }
+
+ self.show = function () {
+ import('css!' + pluginManager.mapPath(self, 'style.css')).then(() => {
+ let elem = document.querySelector('.logoScreenSaver');
+
+ if (!elem) {
+ elem = document.createElement('div');
+ elem.classList.add('logoScreenSaver');
+ document.body.appendChild(elem);
+
+ elem.innerHTML = '
';
}
- }
- function getRandomInt(min, max) {
- return Math.floor(Math.random() * (max - min + 1)) + min;
- }
-
- function bounceInLeft(elem, iterations) {
- var keyframes = [
- { transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 },
- { transform: 'translate3d(25px, 0, 0)', opacity: '1', offset: 0.6 },
- { transform: 'translate3d(-100px, 0, 0)', offset: 0.75 },
- { transform: 'translate3d(5px, 0, 0)', offset: 0.9 },
- { transform: 'none', opacity: '1', offset: 1 }];
- var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
- return elem.animate(keyframes, timing);
- }
-
- function bounceInRight(elem, iterations) {
- var keyframes = [
- { transform: 'translate3d(3000px, 0, 0)', opacity: '0', offset: 0 },
- { transform: 'translate3d(-25px, 0, 0)', opacity: '1', offset: 0.6 },
- { transform: 'translate3d(100px, 0, 0)', offset: 0.75 },
- { transform: 'translate3d(-5px, 0, 0)', offset: 0.9 },
- { transform: 'none', opacity: '1', offset: 1 }];
- var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
- return elem.animate(keyframes, timing);
- }
-
- function swing(elem, iterations) {
- var keyframes = [
- { transform: 'translate(0%)', offset: 0 },
- { transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 },
- { transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 },
- { transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 },
- { transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 },
- { transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }];
- var timing = { duration: 900, iterations: iterations };
- return elem.animate(keyframes, timing);
- }
-
- function tada(elem, iterations) {
- var keyframes = [
- { transform: 'scale3d(1, 1, 1)', offset: 0 },
- { transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.1 },
- { transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.2 },
- { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.3 },
- { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.4 },
- { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.5 },
- { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.6 },
- { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.7 },
- { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.8 },
- { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.9 },
- { transform: 'scale3d(1, 1, 1)', offset: 1 }];
- var timing = { duration: 900, iterations: iterations };
- return elem.animate(keyframes, timing);
- }
-
- function wobble(elem, iterations) {
- var keyframes = [
- { transform: 'translate(0%)', offset: 0 },
- { transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', offset: 0.15 },
- { transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', offset: 0.45 },
- { transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', offset: 0.6 },
- { transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', offset: 0.75 },
- { transform: 'translateX(0%)', offset: 1 }];
- var timing = { duration: 900, iterations: iterations };
- return elem.animate(keyframes, timing);
- }
-
- function rotateIn(elem, iterations) {
- var keyframes = [{ transform: 'rotate3d(0, 0, 1, -200deg)', opacity: '0', transformOrigin: 'center', offset: 0 },
- { transform: 'none', opacity: '1', transformOrigin: 'center', offset: 1 }];
- var timing = { duration: 900, iterations: iterations };
- return elem.animate(keyframes, timing);
- }
-
- function rotateOut(elem, iterations) {
- var keyframes = [{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 0 },
- { transform: 'rotate3d(0, 0, 1, 200deg)', opacity: '0', transformOrigin: 'center', offset: 1 }];
- var timing = { duration: 900, iterations: iterations };
- return elem.animate(keyframes, timing);
- }
-
- function fadeOut(elem, iterations) {
- var keyframes = [
- { opacity: '1', offset: 0 },
- { opacity: '0', offset: 1 }];
- var timing = { duration: 400, iterations: iterations };
- return elem.animate(keyframes, timing);
- }
-
- function stopInterval() {
- if (interval) {
- clearInterval(interval);
- interval = null;
- }
- }
-
- self.show = function () {
- require(['css!' + pluginManager.mapPath(self, 'style.css')], function () {
- var elem = document.querySelector('.logoScreenSaver');
-
- if (!elem) {
- elem = document.createElement('div');
- elem.classList.add('logoScreenSaver');
- document.body.appendChild(elem);
-
- elem.innerHTML = '
';
- }
-
- stopInterval();
- interval = setInterval(animate, 3000);
- });
- };
-
- self.hide = function () {
stopInterval();
-
- var elem = document.querySelector('.logoScreenSaver');
-
- if (elem) {
- var onAnimationFinish = function () {
- elem.parentNode.removeChild(elem);
- };
-
- if (elem.animate) {
- var animation = fadeOut(elem, 1);
- animation.onfinish = onAnimationFinish;
- } else {
- onAnimationFinish();
- }
- }
- };
+ interval = setInterval(animate, 3000);
+ });
};
-});
+
+ self.hide = function () {
+ stopInterval();
+
+ const elem = document.querySelector('.logoScreenSaver');
+
+ if (elem) {
+ const onAnimationFinish = function () {
+ elem.parentNode.removeChild(elem);
+ };
+
+ if (elem.animate) {
+ const animation = fadeOut(elem, 1);
+ animation.onfinish = onAnimationFinish;
+ } else {
+ onAnimationFinish();
+ }
+ }
+ };
+}
diff --git a/src/plugins/playAccessValidation/plugin.js b/src/plugins/playAccessValidation/plugin.js
index 5148d2b82..a9fbeda9a 100644
--- a/src/plugins/playAccessValidation/plugin.js
+++ b/src/plugins/playAccessValidation/plugin.js
@@ -1,33 +1,26 @@
-define(['connectionManager', 'globalize'], function (connectionManager, globalize) {
- 'use strict';
+import connectionManager from 'connectionManager';
+import globalize from 'globalize';
- function getRequirePromise(deps) {
- return new Promise(function (resolve, reject) {
- require(deps, resolve);
- });
- }
+function showErrorMessage() {
+ return import('alert').then(({default: alert}) => {
+ return alert(globalize.translate('MessagePlayAccessRestricted'));
+ });
+}
- function showErrorMessage() {
- return getRequirePromise(['alert']).then(function (alert) {
- return alert(globalize.translate('MessagePlayAccessRestricted')).then(function () {
- return Promise.reject();
- });
- });
- }
-
- function PlayAccessValidation() {
+class PlayAccessValidation {
+ constructor() {
this.name = 'Playback validation';
this.type = 'preplayintercept';
this.id = 'playaccessvalidation';
this.order = -2;
}
- PlayAccessValidation.prototype.intercept = function (options) {
- var item = options.item;
+ intercept(options) {
+ const item = options.item;
if (!item) {
return Promise.resolve();
}
- var serverId = item.ServerId;
+ const serverId = item.ServerId;
if (!serverId) {
return Promise.resolve();
}
@@ -44,7 +37,7 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz
return showErrorMessage();
});
- };
+ }
+}
- return PlayAccessValidation;
-});
+export default PlayAccessValidation;
diff --git a/src/plugins/sessionPlayer/plugin.js b/src/plugins/sessionPlayer/plugin.js
index fb1f745df..cbeb6f34b 100644
--- a/src/plugins/sessionPlayer/plugin.js
+++ b/src/plugins/sessionPlayer/plugin.js
@@ -1,131 +1,123 @@
-define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'], function (playbackManager, events, serverNotifications, connectionManager) {
- 'use strict';
+import playbackManager from 'playbackManager';
+import events from 'events';
+import serverNotifications from 'serverNotifications';
+import connectionManager from 'connectionManager';
- playbackManager = playbackManager.default || playbackManager;
+function getActivePlayerId() {
+ const info = playbackManager.getPlayerInfo();
+ return info ? info.id : null;
+}
- function getActivePlayerId() {
- var info = playbackManager.getPlayerInfo();
- return info ? info.id : null;
+function sendPlayCommand(apiClient, options, playType) {
+ const sessionId = getActivePlayerId();
+
+ const ids = options.ids || options.items.map(function (i) {
+ return i.Id;
+ });
+
+ const remoteOptions = {
+ ItemIds: ids.join(','),
+
+ PlayCommand: playType
+ };
+
+ if (options.startPositionTicks) {
+ remoteOptions.StartPositionTicks = options.startPositionTicks;
}
- function sendPlayCommand(apiClient, options, playType) {
- var sessionId = getActivePlayerId();
-
- var ids = options.ids || options.items.map(function (i) {
- return i.Id;
- });
-
- var remoteOptions = {
- ItemIds: ids.join(','),
-
- PlayCommand: playType
- };
-
- if (options.startPositionTicks) {
- remoteOptions.StartPositionTicks = options.startPositionTicks;
- }
-
- if (options.mediaSourceId) {
- remoteOptions.MediaSourceId = options.mediaSourceId;
- }
-
- if (options.audioStreamIndex != null) {
- remoteOptions.AudioStreamIndex = options.audioStreamIndex;
- }
-
- if (options.subtitleStreamIndex != null) {
- remoteOptions.SubtitleStreamIndex = options.subtitleStreamIndex;
- }
-
- if (options.startIndex != null) {
- remoteOptions.StartIndex = options.startIndex;
- }
-
- return apiClient.sendPlayCommand(sessionId, remoteOptions);
+ if (options.mediaSourceId) {
+ remoteOptions.MediaSourceId = options.mediaSourceId;
}
- function sendPlayStateCommand(apiClient, command, options) {
- var sessionId = getActivePlayerId();
-
- apiClient.sendPlayStateCommand(sessionId, command, options);
+ if (options.audioStreamIndex != null) {
+ remoteOptions.AudioStreamIndex = options.audioStreamIndex;
}
- function getCurrentApiClient(instance) {
- var currentServerId = instance.currentServerId;
-
- if (currentServerId) {
- return connectionManager.getApiClient(currentServerId);
- }
-
- return connectionManager.currentApiClient();
+ if (options.subtitleStreamIndex != null) {
+ remoteOptions.SubtitleStreamIndex = options.subtitleStreamIndex;
}
- function sendCommandByName(instance, name, options) {
- var command = {
- Name: name
- };
-
- if (options) {
- command.Arguments = options;
- }
-
- instance.sendCommand(command);
+ if (options.startIndex != null) {
+ remoteOptions.StartIndex = options.startIndex;
}
- function unsubscribeFromPlayerUpdates(instance) {
- instance.isUpdating = true;
+ return apiClient.sendPlayCommand(sessionId, remoteOptions);
+}
- var apiClient = getCurrentApiClient(instance);
- apiClient.sendMessage('SessionsStop');
- if (instance.pollInterval) {
- clearInterval(instance.pollInterval);
- instance.pollInterval = null;
- }
+function sendPlayStateCommand(apiClient, command, options) {
+ const sessionId = getActivePlayerId();
+
+ apiClient.sendPlayStateCommand(sessionId, command, options);
+}
+
+function getCurrentApiClient(instance) {
+ const currentServerId = instance.currentServerId;
+
+ if (currentServerId) {
+ return connectionManager.getApiClient(currentServerId);
}
- function processUpdatedSessions(instance, sessions, apiClient) {
- var serverId = apiClient.serverId();
+ return connectionManager.currentApiClient();
+}
- sessions.map(function (s) {
- if (s.NowPlayingItem) {
- s.NowPlayingItem.ServerId = serverId;
- }
- });
+function sendCommandByName(instance, name, options) {
+ const command = {
+ Name: name
+ };
- var currentTargetId = getActivePlayerId();
-
- var session = sessions.filter(function (s) {
- return s.Id === currentTargetId;
- })[0];
-
- if (session) {
- normalizeImages(session, apiClient);
-
- var eventNames = getChangedEvents(instance.lastPlayerData, session);
- instance.lastPlayerData = session;
-
- for (var i = 0, length = eventNames.length; i < length; i++) {
- events.trigger(instance, eventNames[i], [session]);
- }
- } else {
- instance.lastPlayerData = session;
-
- playbackManager.setDefaultPlayerActive();
- }
+ if (options) {
+ command.Arguments = options;
}
- function getChangedEvents(state1, state2) {
- var names = [];
+ instance.sendCommand(command);
+}
- if (!state1) {
- names.push('statechange');
- names.push('timeupdate');
- names.push('pause');
+function unsubscribeFromPlayerUpdates(instance) {
+ instance.isUpdating = true;
- return names;
+ const apiClient = getCurrentApiClient(instance);
+ apiClient.sendMessage('SessionsStop');
+ if (instance.pollInterval) {
+ clearInterval(instance.pollInterval);
+ instance.pollInterval = null;
+ }
+}
+
+function processUpdatedSessions(instance, sessions, apiClient) {
+ const serverId = apiClient.serverId();
+
+ sessions.map(function (s) {
+ if (s.NowPlayingItem) {
+ s.NowPlayingItem.ServerId = serverId;
}
+ });
- // TODO: Trim these down to prevent the UI from over-refreshing
+ const currentTargetId = getActivePlayerId();
+
+ const session = sessions.filter(function (s) {
+ return s.Id === currentTargetId;
+ })[0];
+
+ if (session) {
+ normalizeImages(session, apiClient);
+
+ const eventNames = getChangedEvents(instance.lastPlayerData, session);
+ instance.lastPlayerData = session;
+
+ for (let i = 0, length = eventNames.length; i < length; i++) {
+ events.trigger(instance, eventNames[i], [session]);
+ }
+ } else {
+ instance.lastPlayerData = session;
+
+ playbackManager.setDefaultPlayerActive();
+ }
+}
+
+function getChangedEvents(state1, state2) {
+ const names = [];
+
+ if (!state1) {
names.push('statechange');
names.push('timeupdate');
names.push('pause');
@@ -133,53 +125,62 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
return names;
}
- function onPollIntervalFired() {
- var instance = this;
- var apiClient = getCurrentApiClient(instance);
- if (!apiClient.isMessageChannelOpen()) {
- apiClient.getSessions().then(function (sessions) {
- processUpdatedSessions(instance, sessions, apiClient);
- });
- }
+ // TODO: Trim these down to prevent the UI from over-refreshing
+ names.push('statechange');
+ names.push('timeupdate');
+ names.push('pause');
+
+ return names;
+}
+
+function onPollIntervalFired() {
+ const instance = this;
+ const apiClient = getCurrentApiClient(instance);
+ if (!apiClient.isMessageChannelOpen()) {
+ apiClient.getSessions().then(function (sessions) {
+ processUpdatedSessions(instance, sessions, apiClient);
+ });
}
+}
- function subscribeToPlayerUpdates(instance) {
- instance.isUpdating = true;
+function subscribeToPlayerUpdates(instance) {
+ instance.isUpdating = true;
- var apiClient = getCurrentApiClient(instance);
- apiClient.sendMessage('SessionsStart', '100,800');
- if (instance.pollInterval) {
- clearInterval(instance.pollInterval);
- instance.pollInterval = null;
- }
- instance.pollInterval = setInterval(onPollIntervalFired.bind(instance), 5000);
+ const apiClient = getCurrentApiClient(instance);
+ apiClient.sendMessage('SessionsStart', '100,800');
+ if (instance.pollInterval) {
+ clearInterval(instance.pollInterval);
+ instance.pollInterval = null;
}
+ instance.pollInterval = setInterval(onPollIntervalFired.bind(instance), 5000);
+}
- function normalizeImages(state, apiClient) {
- if (state && state.NowPlayingItem) {
- var item = state.NowPlayingItem;
+function normalizeImages(state, apiClient) {
+ if (state && state.NowPlayingItem) {
+ const item = state.NowPlayingItem;
- if (!item.ImageTags || !item.ImageTags.Primary) {
- if (item.PrimaryImageTag) {
- item.ImageTags = item.ImageTags || {};
- item.ImageTags.Primary = item.PrimaryImageTag;
- }
- }
- if (item.BackdropImageTag && item.BackdropItemId === item.Id) {
- item.BackdropImageTags = [item.BackdropImageTag];
- }
- if (item.BackdropImageTag && item.BackdropItemId !== item.Id) {
- item.ParentBackdropImageTags = [item.BackdropImageTag];
- item.ParentBackdropItemId = item.BackdropItemId;
- }
- if (!item.ServerId) {
- item.ServerId = apiClient.serverId();
+ if (!item.ImageTags || !item.ImageTags.Primary) {
+ if (item.PrimaryImageTag) {
+ item.ImageTags = item.ImageTags || {};
+ item.ImageTags.Primary = item.PrimaryImageTag;
}
}
+ if (item.BackdropImageTag && item.BackdropItemId === item.Id) {
+ item.BackdropImageTags = [item.BackdropImageTag];
+ }
+ if (item.BackdropImageTag && item.BackdropItemId !== item.Id) {
+ item.ParentBackdropImageTags = [item.BackdropImageTag];
+ item.ParentBackdropItemId = item.BackdropItemId;
+ }
+ if (!item.ServerId) {
+ item.ServerId = apiClient.serverId();
+ }
}
+}
- function SessionPlayer() {
- var self = this;
+class SessionPlayer {
+ constructor() {
+ const self = this;
this.name = 'Remote Control';
this.type = 'mediaplayer';
@@ -191,7 +192,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
});
}
- SessionPlayer.prototype.beginPlayerUpdates = function () {
+ beginPlayerUpdates() {
this.playerListenerCount = this.playerListenerCount || 0;
if (this.playerListenerCount <= 0) {
@@ -201,9 +202,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
}
this.playerListenerCount++;
- };
+ }
- SessionPlayer.prototype.endPlayerUpdates = function () {
+ endPlayerUpdates() {
this.playerListenerCount = this.playerListenerCount || 0;
this.playerListenerCount--;
@@ -211,21 +212,21 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
unsubscribeFromPlayerUpdates(this);
this.playerListenerCount = 0;
}
- };
+ }
- SessionPlayer.prototype.getPlayerState = function () {
+ getPlayerState() {
return this.lastPlayerData || {};
- };
+ }
- SessionPlayer.prototype.getTargets = function () {
- var apiClient = getCurrentApiClient(this);
+ getTargets() {
+ const apiClient = getCurrentApiClient(this);
- var sessionQuery = {
+ const sessionQuery = {
ControllableByUserId: apiClient.getCurrentUserId()
};
if (apiClient) {
- var name = this.name;
+ const name = this.name;
return apiClient.getSessions(sessionQuery).then(function (sessions) {
return sessions.filter(function (s) {
@@ -242,11 +243,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
isLocalPlayer: false,
supportedCommands: s.Capabilities.SupportedCommands,
user: s.UserId ? {
-
Id: s.UserId,
Name: s.UserName,
PrimaryImageTag: s.UserPrimaryImageTag
-
} : null
};
});
@@ -254,16 +253,16 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} else {
return Promise.resolve([]);
}
- };
+ }
- SessionPlayer.prototype.sendCommand = function (command) {
- var sessionId = getActivePlayerId();
+ sendCommand(command) {
+ const sessionId = getActivePlayerId();
- var apiClient = getCurrentApiClient(this);
+ const apiClient = getCurrentApiClient(this);
apiClient.sendCommand(sessionId, command);
- };
+ }
- SessionPlayer.prototype.play = function (options) {
+ play(options) {
options = Object.assign({}, options);
if (options.items) {
@@ -275,251 +274,233 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
}
return sendPlayCommand(getCurrentApiClient(this), options, 'PlayNow');
- };
+ }
- SessionPlayer.prototype.shuffle = function (item) {
+ shuffle(item) {
sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayShuffle');
- };
+ }
- SessionPlayer.prototype.instantMix = function (item) {
+ instantMix(item) {
sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayInstantMix');
- };
+ }
- SessionPlayer.prototype.queue = function (options) {
+ queue(options) {
sendPlayCommand(getCurrentApiClient(this), options, 'PlayNext');
- };
+ }
- SessionPlayer.prototype.queueNext = function (options) {
+ queueNext(options) {
sendPlayCommand(getCurrentApiClient(this), options, 'PlayLast');
- };
+ }
- SessionPlayer.prototype.canPlayMediaType = function (mediaType) {
+ canPlayMediaType(mediaType) {
mediaType = (mediaType || '').toLowerCase();
return mediaType === 'audio' || mediaType === 'video';
- };
+ }
- SessionPlayer.prototype.canQueueMediaType = function (mediaType) {
+ canQueueMediaType(mediaType) {
return this.canPlayMediaType(mediaType);
- };
+ }
- SessionPlayer.prototype.stop = function () {
+ stop() {
sendPlayStateCommand(getCurrentApiClient(this), 'stop');
- };
+ }
- SessionPlayer.prototype.nextTrack = function () {
+ nextTrack() {
sendPlayStateCommand(getCurrentApiClient(this), 'nextTrack');
- };
+ }
- SessionPlayer.prototype.previousTrack = function () {
+ previousTrack() {
sendPlayStateCommand(getCurrentApiClient(this), 'previousTrack');
- };
+ }
- SessionPlayer.prototype.seek = function (positionTicks) {
+ seek(positionTicks) {
sendPlayStateCommand(getCurrentApiClient(this), 'seek',
{
SeekPositionTicks: positionTicks
});
- };
+ }
- SessionPlayer.prototype.currentTime = function (val) {
+ currentTime(val) {
if (val != null) {
return this.seek(val);
}
- var state = this.lastPlayerData || {};
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.PositionTicks;
- };
+ }
- SessionPlayer.prototype.duration = function () {
- var state = this.lastPlayerData || {};
+ duration() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.RunTimeTicks;
- };
+ }
- SessionPlayer.prototype.paused = function () {
- var state = this.lastPlayerData || {};
+ paused() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.IsPaused;
- };
+ }
- SessionPlayer.prototype.getVolume = function () {
- var state = this.lastPlayerData || {};
+ getVolume() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.VolumeLevel;
- };
+ }
- SessionPlayer.prototype.isMuted = function () {
- var state = this.lastPlayerData || {};
+ isMuted() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.IsMuted;
- };
+ }
- SessionPlayer.prototype.pause = function () {
+ pause() {
sendPlayStateCommand(getCurrentApiClient(this), 'Pause');
- };
+ }
- SessionPlayer.prototype.unpause = function () {
+ unpause() {
sendPlayStateCommand(getCurrentApiClient(this), 'Unpause');
- };
+ }
- SessionPlayer.prototype.playPause = function () {
+ playPause() {
sendPlayStateCommand(getCurrentApiClient(this), 'PlayPause');
- };
+ }
- SessionPlayer.prototype.setMute = function (isMuted) {
+ setMute(isMuted) {
if (isMuted) {
sendCommandByName(this, 'Mute');
} else {
sendCommandByName(this, 'Unmute');
}
- };
+ }
- SessionPlayer.prototype.toggleMute = function () {
+ toggleMute() {
sendCommandByName(this, 'ToggleMute');
- };
+ }
- SessionPlayer.prototype.setVolume = function (vol) {
+ setVolume(vol) {
sendCommandByName(this, 'SetVolume', {
Volume: vol
});
- };
+ }
- SessionPlayer.prototype.volumeUp = function () {
+ volumeUp() {
sendCommandByName(this, 'VolumeUp');
- };
+ }
- SessionPlayer.prototype.volumeDown = function () {
+ volumeDown() {
sendCommandByName(this, 'VolumeDown');
- };
+ }
- SessionPlayer.prototype.toggleFullscreen = function () {
+ toggleFullscreen() {
sendCommandByName(this, 'ToggleFullscreen');
- };
+ }
- SessionPlayer.prototype.audioTracks = function () {
- var state = this.lastPlayerData || {};
+ audioTracks() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
- var streams = state.MediaStreams || [];
+ const streams = state.MediaStreams || [];
return streams.filter(function (s) {
return s.Type === 'Audio';
});
- };
+ }
- SessionPlayer.prototype.getAudioStreamIndex = function () {
- var state = this.lastPlayerData || {};
+ getAudioStreamIndex() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.AudioStreamIndex;
- };
+ }
- SessionPlayer.prototype.playTrailers = function (item) {
+ playTrailers(item) {
sendCommandByName(this, 'PlayTrailers', {
ItemId: item.Id
});
- };
+ }
- SessionPlayer.prototype.setAudioStreamIndex = function (index) {
+ setAudioStreamIndex(index) {
sendCommandByName(this, 'SetAudioStreamIndex', {
Index: index
});
- };
+ }
- SessionPlayer.prototype.subtitleTracks = function () {
- var state = this.lastPlayerData || {};
+ subtitleTracks() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
- var streams = state.MediaStreams || [];
+ const streams = state.MediaStreams || [];
return streams.filter(function (s) {
return s.Type === 'Subtitle';
});
- };
+ }
- SessionPlayer.prototype.getSubtitleStreamIndex = function () {
- var state = this.lastPlayerData || {};
+ getSubtitleStreamIndex() {
+ let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.SubtitleStreamIndex;
- };
+ }
- SessionPlayer.prototype.setSubtitleStreamIndex = function (index) {
+ setSubtitleStreamIndex(index) {
sendCommandByName(this, 'SetSubtitleStreamIndex', {
Index: index
});
- };
+ }
- SessionPlayer.prototype.getMaxStreamingBitrate = function () {
-
- };
-
- SessionPlayer.prototype.setMaxStreamingBitrate = function (options) {
-
- };
-
- SessionPlayer.prototype.isFullscreen = function () {
-
- };
-
- SessionPlayer.prototype.toggleFullscreen = function () {
-
- };
-
- SessionPlayer.prototype.getRepeatMode = function () {
-
- };
-
- SessionPlayer.prototype.setRepeatMode = function (mode) {
+ setRepeatMode(mode) {
sendCommandByName(this, 'SetRepeatMode', {
RepeatMode: mode
});
- };
+ }
- SessionPlayer.prototype.setQueueShuffleMode = function (mode) {
+ getRepeatMode() {
+ }
+
+ setQueueShuffleMode(mode) {
sendCommandByName(this, 'SetShuffleQueue', {
ShuffleMode: mode
});
- };
+ }
- SessionPlayer.prototype.getQueueShuffleMode = function () {
+ getQueueShuffleMode() {
+ }
- };
-
- SessionPlayer.prototype.displayContent = function (options) {
+ displayContent(options) {
sendCommandByName(this, 'DisplayContent', options);
- };
+ }
- SessionPlayer.prototype.isPlaying = function () {
- var state = this.lastPlayerData || {};
+ isPlaying() {
+ const state = this.lastPlayerData || {};
return state.NowPlayingItem != null;
- };
+ }
- SessionPlayer.prototype.isPlayingVideo = function () {
- var state = this.lastPlayerData || {};
+ isPlayingVideo() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.MediaType === 'Video';
- };
+ }
- SessionPlayer.prototype.isPlayingAudio = function () {
- var state = this.lastPlayerData || {};
+ isPlayingAudio() {
+ let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.MediaType === 'Audio';
- };
+ }
- SessionPlayer.prototype.getPlaylist = function () {
+ getPlaylist() {
return Promise.resolve([]);
- };
+ }
- SessionPlayer.prototype.getCurrentPlaylistItemId = function () {
- };
+ getCurrentPlaylistItemId() {
+ }
- SessionPlayer.prototype.setCurrentPlaylistItem = function (playlistItemId) {
+ setCurrentPlaylistItem(playlistItemId) {
return Promise.resolve();
- };
+ }
- SessionPlayer.prototype.removeFromPlaylist = function (playlistItemIds) {
+ removeFromPlaylist(playlistItemIds) {
return Promise.resolve();
- };
+ }
- SessionPlayer.prototype.tryPair = function (target) {
+ tryPair(target) {
return Promise.resolve();
- };
+ }
+}
- return SessionPlayer;
-});
+export default SessionPlayer;
diff --git a/src/scripts/apploader.js b/src/scripts/apploader.js
index 183b765d1..e98c82e69 100644
--- a/src/scripts/apploader.js
+++ b/src/scripts/apploader.js
@@ -1,12 +1,10 @@
(function() {
- 'use strict';
-
function injectScriptElement(src, onload) {
if (!src) {
return;
}
- var script = document.createElement('script');
+ const script = document.createElement('script');
if (self.dashboardVersion) {
src += `?v=${self.dashboardVersion}`;
}
diff --git a/src/scripts/autoThemes.js b/src/scripts/autoThemes.js
index dad8c1032..75309f377 100644
--- a/src/scripts/autoThemes.js
+++ b/src/scripts/autoThemes.js
@@ -3,6 +3,10 @@ import skinManager from 'skinManager';
import connectionManager from 'connectionManager';
import events from 'events';
+// Set the default theme when loading
+skinManager.setTheme(userSettings.theme());
+
+// Set the user's prefered theme when signing in
events.on(connectionManager, 'localusersignedin', function (e, user) {
skinManager.setTheme(userSettings.theme());
});
diff --git a/src/scripts/clientUtils.js b/src/scripts/clientUtils.js
new file mode 100644
index 000000000..1bad8bc81
--- /dev/null
+++ b/src/scripts/clientUtils.js
@@ -0,0 +1,233 @@
+
+export function getCurrentUser() {
+ return window.ApiClient.getCurrentUser(false);
+}
+
+//TODO: investigate url prefix support for serverAddress function
+export function serverAddress() {
+ if (AppInfo.isNativeApp) {
+ const apiClient = window.ApiClient;
+
+ if (apiClient) {
+ return apiClient.serverAddress();
+ }
+
+ return null;
+ }
+
+ const urlLower = window.location.href.toLowerCase();
+ const index = urlLower.lastIndexOf('/web');
+
+ if (index != -1) {
+ return urlLower.substring(0, index);
+ }
+
+ const loc = window.location;
+ let address = loc.protocol + '//' + loc.hostname;
+
+ if (loc.port) {
+ address += ':' + loc.port;
+ }
+
+ return address;
+}
+
+export function getCurrentUserId() {
+ const apiClient = window.ApiClient;
+
+ if (apiClient) {
+ return apiClient.getCurrentUserId();
+ }
+
+ return null;
+}
+
+export function onServerChanged(userId, accessToken, apiClient) {
+ apiClient = apiClient || window.ApiClient;
+ window.ApiClient = apiClient;
+}
+
+export function logout() {
+ ConnectionManager.logout().then(function () {
+ let loginPage;
+
+ if (AppInfo.isNativeApp) {
+ loginPage = 'selectserver.html';
+ window.ApiClient = null;
+ } else {
+ loginPage = 'login.html';
+ }
+
+ navigate(loginPage);
+ });
+}
+
+export function getConfigurationPageUrl(name) {
+ return 'configurationpage?name=' + encodeURIComponent(name);
+}
+
+export function getConfigurationResourceUrl(name) {
+ if (AppInfo.isNativeApp) {
+ return ApiClient.getUrl('web/ConfigurationPage', {
+ name: name
+ });
+ }
+
+ return getConfigurationPageUrl(name);
+}
+
+export function navigate(url, preserveQueryString) {
+ if (!url) {
+ throw new Error('url cannot be null or empty');
+ }
+
+ const queryString = getWindowLocationSearch();
+
+ if (preserveQueryString && queryString) {
+ url += queryString;
+ }
+
+ return new Promise(function (resolve, reject) {
+ import('appRouter').then(({default: appRouter}) => {
+ return appRouter.show(url).then(resolve, reject);
+ });
+ });
+}
+
+export function processPluginConfigurationUpdateResult() {
+ Promise.all([
+ import('loading'),
+ import('toast')
+ ])
+ .then(([{default: loading}, {default: toast}]) => {
+ loading.hide();
+ toast(Globalize.translate('SettingsSaved'));
+ });
+}
+
+export function processServerConfigurationUpdateResult(result) {
+ Promise.all([
+ import('loading'),
+ import('toast')
+ ])
+ .then(([{default: loading}, {default: toast}]) => {
+ loading.hide();
+ toast(Globalize.translate('SettingsSaved'));
+ });
+}
+
+export function processErrorResponse(response) {
+ import('loading').then(({default: loading}) => {
+ loading.hide();
+ });
+
+ let status = '' + response.status;
+
+ if (response.statusText) {
+ status = response.statusText;
+ }
+
+ alert({
+ title: status,
+ message: response.headers ? response.headers.get('X-Application-Error-Code') : null
+ });
+}
+
+export function alert(options) {
+ if (typeof options == 'string') {
+ return void import('toast').then(({default: toast}) => {
+ toast({
+ text: options
+ });
+ });
+ }
+
+ import('alert').then(({default: alert}) => {
+ alert({
+ title: options.title || Globalize.translate('HeaderAlert'),
+ text: options.message
+ }).then(options.callback || function () {});
+ });
+}
+
+export function capabilities(appHost) {
+ let capabilities = {
+ PlayableMediaTypes: ['Audio', 'Video'],
+ SupportedCommands: ['MoveUp', 'MoveDown', 'MoveLeft', 'MoveRight', 'PageUp', 'PageDown', 'PreviousLetter', 'NextLetter', 'ToggleOsd', 'ToggleContextMenu', 'Select', 'Back', 'SendKey', 'SendString', 'GoHome', 'GoToSettings', 'VolumeUp', 'VolumeDown', 'Mute', 'Unmute', 'ToggleMute', 'SetVolume', 'SetAudioStreamIndex', 'SetSubtitleStreamIndex', 'DisplayContent', 'GoToSearch', 'DisplayMessage', 'SetRepeatMode', 'SetShuffleQueue', 'ChannelUp', 'ChannelDown', 'PlayMediaSource', 'PlayTrailers'],
+ SupportsPersistentIdentifier: self.appMode === 'cordova' || self.appMode === 'android',
+ SupportsMediaControl: true
+ };
+ return Object.assign(capabilities, appHost.getPushTokenInfo());
+}
+
+export function selectServer() {
+ if (window.NativeShell && typeof window.NativeShell.selectServer === 'function') {
+ window.NativeShell.selectServer();
+ } else {
+ navigate('selectserver.html');
+ }
+}
+
+export function hideLoadingMsg() {
+ import('loading').then(({default: loading}) => {
+ loading.hide();
+ });
+}
+
+export function showLoadingMsg() {
+ import('loading').then(({default: loading}) => {
+ loading.show();
+ });
+}
+
+export function confirm(message, title, callback) {
+ import('confirm').then(({default: confirm}) => {
+ confirm(message, title).then(function() {
+ callback(!0);
+ }).catch(function() {
+ callback(!1);
+ });
+ });
+}
+
+// This is used in plugins and templates, so keep it defined for now.
+// TODO: Remove once plugins don't need it
+window.Dashboard = {
+ alert,
+ capabilities,
+ confirm,
+ getConfigurationPageUrl,
+ getConfigurationResourceUrl,
+ getCurrentUser,
+ getCurrentUserId,
+ hideLoadingMsg,
+ logout,
+ navigate,
+ onServerChanged,
+ processErrorResponse,
+ processPluginConfigurationUpdateResult,
+ processServerConfigurationUpdateResult,
+ selectServer,
+ serverAddress,
+ showLoadingMsg
+};
+
+export default {
+ alert,
+ capabilities,
+ confirm,
+ getConfigurationPageUrl,
+ getConfigurationResourceUrl,
+ getCurrentUser,
+ getCurrentUserId,
+ hideLoadingMsg,
+ logout,
+ navigate,
+ onServerChanged,
+ processErrorResponse,
+ processPluginConfigurationUpdateResult,
+ processServerConfigurationUpdateResult,
+ selectServer,
+ serverAddress,
+ showLoadingMsg
+};
diff --git a/src/scripts/datetime.js b/src/scripts/datetime.js
index dcac41089..c6baa28ed 100644
--- a/src/scripts/datetime.js
+++ b/src/scripts/datetime.js
@@ -24,7 +24,7 @@ import globalize from 'globalize';
// parse strings, leading zeros into proper ints
const a = [1, 2, 3, 4, 5, 6, 10, 11];
- for (let i in a) {
+ for (const i in a) {
d[a[i]] = parseInt(d[a[i]], 10);
}
d[7] = parseFloat(d[7]);
diff --git a/src/scripts/deleteHelper.js b/src/scripts/deleteHelper.js
index e10a1568c..44876c75b 100644
--- a/src/scripts/deleteHelper.js
+++ b/src/scripts/deleteHelper.js
@@ -15,7 +15,7 @@ export function deleteItem(options) {
const item = options.item;
const parentId = item.SeasonId || item.SeriesId || item.ParentId;
- let apiClient = connectionManager.getApiClient(item.ServerId);
+ const apiClient = connectionManager.getApiClient(item.ServerId);
return confirm({
@@ -34,7 +34,7 @@ export function deleteItem(options) {
}
}
}, function (err) {
- let result = function () {
+ const result = function () {
return Promise.reject(err);
};
diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js
index 248933596..b6a45ccf2 100644
--- a/src/scripts/editorsidebar.js
+++ b/src/scripts/editorsidebar.js
@@ -86,7 +86,7 @@ import 'material-icons';
if (result.TotalRecordCount) {
nodes.push({
id: 'livetv',
- text: globalize.translate('HeaderLiveTV'),
+ text: globalize.translate('LiveTV'),
state: {
opened: false
},
@@ -302,7 +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 */
+ /* eslint-disable-next-line @babel/no-unused-expressions */
import('css!assets/css/metadataeditor.css');
}).on('pagebeforeshow', '.metadataEditorPage', function () {
var page = this;
diff --git a/src/scripts/globalize.js b/src/scripts/globalize.js
index 4af1ea6cb..d237fdcce 100644
--- a/src/scripts/globalize.js
+++ b/src/scripts/globalize.js
@@ -63,11 +63,11 @@ import events from 'events';
}
function ensureTranslations(culture) {
- for (let i in allTranslations) {
+ for (const i in allTranslations) {
ensureTranslation(allTranslations[i], culture);
}
if (culture !== fallbackCulture) {
- for (let i in allTranslations) {
+ for (const i in allTranslations) {
ensureTranslation(allTranslations[i], fallbackCulture);
}
}
diff --git a/src/scripts/inputManager.js b/src/scripts/inputManager.js
index 3432c9e35..baa3deb0a 100644
--- a/src/scripts/inputManager.js
+++ b/src/scripts/inputManager.js
@@ -39,7 +39,7 @@ import appHost from 'apphost';
dom.removeEventListener(scope, 'command', fn, {});
}
- let commandTimes = {};
+ const commandTimes = {};
function checkCommandTime(command) {
const last = commandTimes[command] || 0;
@@ -185,6 +185,12 @@ import appHost from 'apphost';
'changezoom': () => {
playbackManager.toggleAspectRatio();
},
+ 'increaseplaybackrate': () => {
+ playbackManager.increasePlaybackRate();
+ },
+ 'decreaseplaybackrate': () => {
+ playbackManager.decreasePlaybackRate();
+ },
'changeaudiotrack': () => {
playbackManager.changeAudioStream();
},
diff --git a/src/scripts/itembynamedetailpage.js b/src/scripts/itembynamedetailpage.js
index eaeecba27..f77bb7365 100644
--- a/src/scripts/itembynamedetailpage.js
+++ b/src/scripts/itembynamedetailpage.js
@@ -1,369 +1,374 @@
-define(['connectionManager', 'listView', 'cardBuilder', 'imageLoader', 'libraryBrowser', 'globalize', 'emby-itemscontainer', 'emby-button'], function (connectionManager, listView, cardBuilder, imageLoader, libraryBrowser, globalize) {
- 'use strict';
+import connectionManager from 'connectionManager';
+import listView from 'listView';
+import cardBuilder from 'cardBuilder';
+import imageLoader from 'imageLoader';
+import globalize from 'globalize';
+import 'emby-itemscontainer';
+import 'emby-button';
- function renderItems(page, item) {
- var sections = [];
+function renderItems(page, item) {
+ const sections = [];
- if (item.ArtistCount) {
- sections.push({
- name: globalize.translate('TabArtists'),
- type: 'MusicArtist'
- });
- }
-
- if (item.ProgramCount && item.Type == 'Person') {
- sections.push({
- name: globalize.translate('HeaderUpcomingOnTV'),
- type: 'Program'
- });
- }
-
- if (item.MovieCount) {
- sections.push({
- name: globalize.translate('TabMovies'),
- type: 'Movie'
- });
- }
-
- if (item.SeriesCount) {
- sections.push({
- name: globalize.translate('TabShows'),
- type: 'Series'
- });
- }
-
- if (item.EpisodeCount) {
- sections.push({
- name: globalize.translate('TabEpisodes'),
- type: 'Episode'
- });
- }
-
- if (item.TrailerCount) {
- sections.push({
- name: globalize.translate('TabTrailers'),
- type: 'Trailer'
- });
- }
-
- if (item.AlbumCount) {
- sections.push({
- name: globalize.translate('TabAlbums'),
- type: 'MusicAlbum'
- });
- }
-
- if (item.MusicVideoCount) {
- sections.push({
- name: globalize.translate('TabMusicVideos'),
- type: 'MusicVideo'
- });
- }
-
- var elem = page.querySelector('#childrenContent');
- elem.innerHTML = sections.map(function (section) {
- var html = '';
- var sectionClass = 'verticalSection';
-
- if (section.type === 'Audio') {
- sectionClass += ' verticalSection-extrabottompadding';
- }
-
- html += '
';
- html += '
';
- html += '
';
- html += '
';
- return html += '
';
- }).join('');
- var sectionElems = elem.querySelectorAll('.verticalSection');
-
- for (var i = 0, length = sectionElems.length; i < length; i++) {
- renderSection(page, item, sectionElems[i], sectionElems[i].getAttribute('data-type'));
- }
- }
-
- function renderSection(page, item, element, type) {
- switch (type) {
- case 'Program':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'Program',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- Limit: 10,
- SortBy: 'StartDate'
- }, {
- shape: 'overflowBackdrop',
- showTitle: true,
- centerText: true,
- overlayMoreButton: true,
- preferThumb: true,
- overlayText: false,
- showAirTime: true,
- showAirDateTime: true,
- showChannelName: true
- });
- break;
-
- case 'Movie':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'Movie',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- Limit: 10,
- SortBy: 'SortName'
- }, {
- shape: 'overflowPortrait',
- showTitle: true,
- centerText: true,
- overlayMoreButton: true,
- overlayText: false,
- showYear: true
- });
- break;
-
- case 'MusicVideo':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'MusicVideo',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- Limit: 10,
- SortBy: 'SortName'
- }, {
- shape: 'overflowPortrait',
- showTitle: true,
- centerText: true,
- overlayPlayButton: true
- });
- break;
-
- case 'Trailer':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'Trailer',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- Limit: 10,
- SortBy: 'SortName'
- }, {
- shape: 'overflowPortrait',
- showTitle: true,
- centerText: true,
- overlayPlayButton: true
- });
- break;
-
- case 'Series':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'Series',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- Limit: 10,
- SortBy: 'SortName'
- }, {
- shape: 'overflowPortrait',
- showTitle: true,
- centerText: true,
- overlayMoreButton: true
- });
- break;
-
- case 'MusicAlbum':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'MusicAlbum',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- SortOrder: 'Descending',
- SortBy: 'ProductionYear,Sortname'
- }, {
- shape: 'overflowSquare',
- playFromHere: true,
- showTitle: true,
- showYear: true,
- coverImage: true,
- centerText: true,
- overlayPlayButton: true
- });
- break;
-
- case 'MusicArtist':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'MusicArtist',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- Limit: 8,
- SortBy: 'SortName'
- }, {
- shape: 'overflowSquare',
- playFromHere: true,
- showTitle: true,
- showParentTitle: true,
- coverImage: true,
- centerText: true,
- overlayPlayButton: true
- });
- break;
-
- case 'Episode':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'Episode',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- Limit: 6,
- SortBy: 'SortName'
- }, {
- shape: 'overflowBackdrop',
- showTitle: true,
- showParentTitle: true,
- centerText: true,
- overlayPlayButton: true
- });
- break;
-
- case 'Audio':
- loadItems(element, item, type, {
- MediaTypes: '',
- IncludeItemTypes: 'Audio',
- PersonTypes: '',
- ArtistIds: '',
- AlbumArtistIds: '',
- SortBy: 'AlbumArtist,Album,SortName'
- }, {
- playFromHere: true,
- action: 'playallfromhere',
- smallIcon: true,
- artist: true
- });
- }
- }
-
- function loadItems(element, item, type, query, listOptions) {
- query = getQuery(query, item);
- getItemsFunction(query, item)(query.StartIndex, query.Limit, query.Fields).then(function (result) {
- var html = '';
-
- if (query.Limit && result.TotalRecordCount > query.Limit) {
- var link = element.querySelector('a');
- link.classList.remove('hide');
- link.setAttribute('href', getMoreItemsHref(item, type));
- } else {
- element.querySelector('a').classList.add('hide');
- }
-
- listOptions.items = result.Items;
- var itemsContainer = element.querySelector('.itemsContainer');
-
- if (type == 'Audio') {
- html = listView.getListViewHtml(listOptions);
- itemsContainer.classList.remove('vertical-wrap');
- itemsContainer.classList.add('vertical-list');
- } else {
- html = cardBuilder.getCardsHtml(listOptions);
- itemsContainer.classList.add('vertical-wrap');
- itemsContainer.classList.remove('vertical-list');
- }
-
- itemsContainer.innerHTML = html;
- imageLoader.lazyChildren(itemsContainer);
+ if (item.ArtistCount) {
+ sections.push({
+ name: globalize.translate('Artists'),
+ type: 'MusicArtist'
});
}
- function getMoreItemsHref(item, type) {
- if (item.Type == 'Genre') {
- return 'list.html?type=' + type + '&genreId=' + item.Id + '&serverId=' + item.ServerId;
- }
-
- if (item.Type == 'MusicGenre') {
- return 'list.html?type=' + type + '&musicGenreId=' + item.Id + '&serverId=' + item.ServerId;
- }
-
- if (item.Type == 'Studio') {
- return 'list.html?type=' + type + '&studioId=' + item.Id + '&serverId=' + item.ServerId;
- }
-
- if (item.Type == 'MusicArtist') {
- return 'list.html?type=' + type + '&artistId=' + item.Id + '&serverId=' + item.ServerId;
- }
-
- if (item.Type == 'Person') {
- return 'list.html?type=' + type + '&personId=' + item.Id + '&serverId=' + item.ServerId;
- }
-
- return 'list.html?type=' + type + '&parentId=' + item.Id + '&serverId=' + item.ServerId;
+ if (item.ProgramCount && item.Type === 'Person') {
+ sections.push({
+ name: globalize.translate('HeaderUpcomingOnTV'),
+ type: 'Program'
+ });
}
- function addCurrentItemToQuery(query, item) {
- if (item.Type == 'Person') {
- query.PersonIds = item.Id;
- } else if (item.Type == 'Genre') {
- query.Genres = item.Name;
- } else if (item.Type == 'MusicGenre') {
- query.Genres = item.Name;
- } else if (item.Type == 'GameGenre') {
- query.Genres = item.Name;
- } else if (item.Type == 'Studio') {
- query.StudioIds = item.Id;
- } else if (item.Type == 'MusicArtist') {
- query.AlbumArtistIds = item.Id;
+ if (item.MovieCount) {
+ sections.push({
+ name: globalize.translate('Movies'),
+ type: 'Movie'
+ });
+ }
+
+ if (item.SeriesCount) {
+ sections.push({
+ name: globalize.translate('Shows'),
+ type: 'Series'
+ });
+ }
+
+ if (item.EpisodeCount) {
+ sections.push({
+ name: globalize.translate('Episodes'),
+ type: 'Episode'
+ });
+ }
+
+ if (item.TrailerCount) {
+ sections.push({
+ name: globalize.translate('Trailers'),
+ type: 'Trailer'
+ });
+ }
+
+ if (item.AlbumCount) {
+ sections.push({
+ name: globalize.translate('Albums'),
+ type: 'MusicAlbum'
+ });
+ }
+
+ if (item.MusicVideoCount) {
+ sections.push({
+ name: globalize.translate('HeaderMusicVideos'),
+ type: 'MusicVideo'
+ });
+ }
+
+ const elem = page.querySelector('#childrenContent');
+ elem.innerHTML = sections.map(function (section) {
+ let html = '';
+ let sectionClass = 'verticalSection';
+
+ if (section.type === 'Audio') {
+ sectionClass += ' verticalSection-extrabottompadding';
}
+
+ html += '
';
+ html += '
';
+ html += '
';
+ html += '
';
+ html += '
';
+ return html;
+ }).join('');
+ const sectionElems = elem.querySelectorAll('.verticalSection');
+
+ for (let i = 0, length = sectionElems.length; i < length; i++) {
+ renderSection(page, item, sectionElems[i], sectionElems[i].getAttribute('data-type'));
+ }
+}
+
+function renderSection(page, item, element, type) {
+ switch (type) {
+ case 'Program':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'Program',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ Limit: 10,
+ SortBy: 'StartDate'
+ }, {
+ shape: 'overflowBackdrop',
+ showTitle: true,
+ centerText: true,
+ overlayMoreButton: true,
+ preferThumb: true,
+ overlayText: false,
+ showAirTime: true,
+ showAirDateTime: true,
+ showChannelName: true
+ });
+ break;
+
+ case 'Movie':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'Movie',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ Limit: 10,
+ SortBy: 'SortName'
+ }, {
+ shape: 'overflowPortrait',
+ showTitle: true,
+ centerText: true,
+ overlayMoreButton: true,
+ overlayText: false,
+ showYear: true
+ });
+ break;
+
+ case 'MusicVideo':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'MusicVideo',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ Limit: 10,
+ SortBy: 'SortName'
+ }, {
+ shape: 'overflowPortrait',
+ showTitle: true,
+ centerText: true,
+ overlayPlayButton: true
+ });
+ break;
+
+ case 'Trailer':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'Trailer',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ Limit: 10,
+ SortBy: 'SortName'
+ }, {
+ shape: 'overflowPortrait',
+ showTitle: true,
+ centerText: true,
+ overlayPlayButton: true
+ });
+ break;
+
+ case 'Series':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'Series',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ Limit: 10,
+ SortBy: 'SortName'
+ }, {
+ shape: 'overflowPortrait',
+ showTitle: true,
+ centerText: true,
+ overlayMoreButton: true
+ });
+ break;
+
+ case 'MusicAlbum':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'MusicAlbum',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ SortOrder: 'Descending',
+ SortBy: 'ProductionYear,Sortname'
+ }, {
+ shape: 'overflowSquare',
+ playFromHere: true,
+ showTitle: true,
+ showYear: true,
+ coverImage: true,
+ centerText: true,
+ overlayPlayButton: true
+ });
+ break;
+
+ case 'MusicArtist':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'MusicArtist',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ Limit: 8,
+ SortBy: 'SortName'
+ }, {
+ shape: 'overflowSquare',
+ playFromHere: true,
+ showTitle: true,
+ showParentTitle: true,
+ coverImage: true,
+ centerText: true,
+ overlayPlayButton: true
+ });
+ break;
+
+ case 'Episode':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'Episode',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ Limit: 6,
+ SortBy: 'SortName'
+ }, {
+ shape: 'overflowBackdrop',
+ showTitle: true,
+ showParentTitle: true,
+ centerText: true,
+ overlayPlayButton: true
+ });
+ break;
+
+ case 'Audio':
+ loadItems(element, item, type, {
+ MediaTypes: '',
+ IncludeItemTypes: 'Audio',
+ PersonTypes: '',
+ ArtistIds: '',
+ AlbumArtistIds: '',
+ SortBy: 'AlbumArtist,Album,SortName'
+ }, {
+ playFromHere: true,
+ action: 'playallfromhere',
+ smallIcon: true,
+ artist: true
+ });
+ }
+}
+
+function loadItems(element, item, type, query, listOptions) {
+ query = getQuery(query, item);
+ getItemsFunction(query, item)(query.StartIndex, query.Limit, query.Fields).then(function (result) {
+ let html = '';
+
+ if (query.Limit && result.TotalRecordCount > query.Limit) {
+ const link = element.querySelector('a');
+ link.classList.remove('hide');
+ link.setAttribute('href', getMoreItemsHref(item, type));
+ } else {
+ element.querySelector('a').classList.add('hide');
+ }
+
+ listOptions.items = result.Items;
+ const itemsContainer = element.querySelector('.itemsContainer');
+
+ if (type === 'Audio') {
+ html = listView.getListViewHtml(listOptions);
+ itemsContainer.classList.remove('vertical-wrap');
+ itemsContainer.classList.add('vertical-list');
+ } else {
+ html = cardBuilder.getCardsHtml(listOptions);
+ itemsContainer.classList.add('vertical-wrap');
+ itemsContainer.classList.remove('vertical-list');
+ }
+
+ itemsContainer.innerHTML = html;
+ imageLoader.lazyChildren(itemsContainer);
+ });
+}
+
+function getMoreItemsHref(item, type) {
+ if (item.Type === 'Genre') {
+ return 'list.html?type=' + type + '&genreId=' + item.Id + '&serverId=' + item.ServerId;
}
- function getQuery(options, item) {
- var query = {
- SortOrder: 'Ascending',
- IncludeItemTypes: '',
- Recursive: true,
- Fields: 'AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio,BasicSyncInfo',
- Limit: 100,
- StartIndex: 0,
- CollapseBoxSetItems: false
- };
- query = Object.assign(query, options || {});
- addCurrentItemToQuery(query, item);
- return query;
+ if (item.Type === 'MusicGenre') {
+ return 'list.html?type=' + type + '&musicGenreId=' + item.Id + '&serverId=' + item.ServerId;
}
- function getItemsFunction(options, item) {
- var query = getQuery(options, item);
- return function (index, limit, fields) {
- query.StartIndex = index;
- query.Limit = limit;
-
- if (fields) {
- query.Fields += ',' + fields;
- }
-
- var apiClient = connectionManager.getApiClient(item.ServerId);
-
- if (query.IncludeItemTypes === 'MusicArtist') {
- query.IncludeItemTypes = null;
- return apiClient.getAlbumArtists(apiClient.getCurrentUserId(), query);
- }
-
- return apiClient.getItems(apiClient.getCurrentUserId(), query);
- };
+ if (item.Type === 'Studio') {
+ return 'list.html?type=' + type + '&studioId=' + item.Id + '&serverId=' + item.ServerId;
}
- window.ItemsByName = {
- renderItems: renderItems
+ if (item.Type === 'MusicArtist') {
+ return 'list.html?type=' + type + '&artistId=' + item.Id + '&serverId=' + item.ServerId;
+ }
+
+ if (item.Type === 'Person') {
+ return 'list.html?type=' + type + '&personId=' + item.Id + '&serverId=' + item.ServerId;
+ }
+
+ return 'list.html?type=' + type + '&parentId=' + item.Id + '&serverId=' + item.ServerId;
+}
+
+function addCurrentItemToQuery(query, item) {
+ if (item.Type === 'Person') {
+ query.PersonIds = item.Id;
+ } else if (item.Type === 'Genre') {
+ query.Genres = item.Name;
+ } else if (item.Type === 'MusicGenre') {
+ query.Genres = item.Name;
+ } else if (item.Type === 'GameGenre') {
+ query.Genres = item.Name;
+ } else if (item.Type === 'Studio') {
+ query.StudioIds = item.Id;
+ } else if (item.Type === 'MusicArtist') {
+ query.AlbumArtistIds = item.Id;
+ }
+}
+
+function getQuery(options, item) {
+ let query = {
+ SortOrder: 'Ascending',
+ IncludeItemTypes: '',
+ Recursive: true,
+ Fields: 'AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio,BasicSyncInfo',
+ Limit: 100,
+ StartIndex: 0,
+ CollapseBoxSetItems: false
};
-});
+ query = Object.assign(query, options || {});
+ addCurrentItemToQuery(query, item);
+ return query;
+}
+
+function getItemsFunction(options, item) {
+ const query = getQuery(options, item);
+ return function (index, limit, fields) {
+ query.StartIndex = index;
+ query.Limit = limit;
+
+ if (fields) {
+ query.Fields += ',' + fields;
+ }
+
+ const apiClient = connectionManager.getApiClient(item.ServerId);
+
+ if (query.IncludeItemTypes === 'MusicArtist') {
+ query.IncludeItemTypes = null;
+ return apiClient.getAlbumArtists(apiClient.getCurrentUserId(), query);
+ }
+
+ return apiClient.getItems(apiClient.getCurrentUserId(), query);
+ };
+}
+
+window.ItemsByName = {
+ renderItems: renderItems
+};
diff --git a/src/scripts/keyboardNavigation.js b/src/scripts/keyboardNavigation.js
index 10a9611c3..ec354a7ba 100644
--- a/src/scripts/keyboardNavigation.js
+++ b/src/scripts/keyboardNavigation.js
@@ -155,7 +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 */
+ /* eslint-disable-next-line @babel/no-unused-expressions */
import('scripts/gamepadtokey');
}
diff --git a/src/scripts/libraryBrowser.js b/src/scripts/libraryBrowser.js
index 46cda51e5..5b5a1aad8 100644
--- a/src/scripts/libraryBrowser.js
+++ b/src/scripts/libraryBrowser.js
@@ -105,11 +105,11 @@ export function getQueryPagingHtml (options) {
}
if (options.sortButton) {
- html += '
';
+ html += '
';
}
if (options.filterButton) {
- html += '
';
+ html += '
';
}
html += '
';
@@ -119,7 +119,10 @@ export function getQueryPagingHtml (options) {
}
export function showSortMenu (options) {
- require(['dialogHelper', 'emby-radio'], function (dialogHelper) {
+ Promise.all([
+ import('dialogHelper'),
+ import('emby-radio')
+ ]).then(([{default: dialogHelper}]) => {
function onSortByChange() {
var newValue = this.value;
diff --git a/src/scripts/libraryMenu.js b/src/scripts/libraryMenu.js
index bbe01276b..e1b0ff780 100644
--- a/src/scripts/libraryMenu.js
+++ b/src/scripts/libraryMenu.js
@@ -1,11 +1,26 @@
-define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', 'viewManager', 'libraryBrowser', 'appRouter', 'apphost', 'playbackManager', 'syncPlayManager', 'groupSelectionMenu', 'browser', 'globalize', 'scripts/imagehelper', 'paper-icon-button-light', 'material-icons', 'scrollStyles', 'flexStyles'], function (dom, layoutManager, inputManager, connectionManager, events, viewManager, libraryBrowser, appRouter, appHost, playbackManager, syncPlayManager, groupSelectionMenu, browser, globalize, imageHelper) {
- 'use strict';
+import dom from 'dom';
+import layoutManager from 'layoutManager';
+import inputManager from 'inputManager';
+import connectionManager from 'connectionManager';
+import events from 'events';
+import viewManager from 'viewManager';
+import appRouter from 'appRouter';
+import appHost from 'apphost';
+import playbackManager from 'playbackManager';
+import syncPlayManager from 'syncPlayManager';
+import * as groupSelectionMenu from 'groupSelectionMenu';
+import browser from 'browser';
+import globalize from 'globalize';
+import imageHelper from 'scripts/imagehelper';
+import 'paper-icon-button-light';
+import 'material-icons';
+import 'scrollStyles';
+import 'flexStyles';
- playbackManager = playbackManager.default || playbackManager;
- browser = browser.default || browser;
+/* eslint-disable indent */
function renderHeader() {
- var html = '';
+ let html = '';
html += '';
@@ -49,7 +64,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
}
function lazyLoadViewMenuBarImages() {
- require(['imageLoader'], function (imageLoader) {
+ import('imageLoader').then(({default: imageLoader}) => {
imageLoader.lazyChildren(skinHeader);
});
}
@@ -59,11 +74,11 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
}
function updateUserInHeader(user) {
- var hasImage;
+ let hasImage;
if (user && user.name) {
if (user.imageUrl) {
- var url = user.imageUrl;
+ const url = user.imageUrl;
updateHeaderUserButton(url);
hasImage = true;
}
@@ -90,9 +105,9 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
headerCastButton.classList.remove('hide');
}
- var policy = user.Policy ? user.Policy : user.localUser.Policy;
+ const policy = user.Policy ? user.Policy : user.localUser.Policy;
- var apiClient = getCurrentApiClient();
+ const apiClient = getCurrentApiClient();
if (headerSyncButton && policy && policy.SyncPlayAccess !== 'None' && apiClient.isMinServerVersion('10.6.0')) {
headerSyncButton.classList.remove('hide');
}
@@ -142,7 +157,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
mainDrawerButton.addEventListener('click', toggleMainDrawer);
}
- var headerBackButton = skinHeader.querySelector('.headerBackButton');
+ const headerBackButton = skinHeader.querySelector('.headerBackButton');
if (headerBackButton) {
headerBackButton.addEventListener('click', onBackClick);
@@ -184,20 +199,20 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
}
function onCastButtonClicked() {
- var btn = this;
+ const btn = this;
- require(['playerSelectionMenu'], function (playerSelectionMenu) {
+ import('playerSelectionMenu').then(({default: playerSelectionMenu}) => {
playerSelectionMenu.show(btn);
});
}
function onSyncButtonClicked() {
- var btn = this;
+ const btn = this;
groupSelectionMenu.show(btn);
}
function onSyncPlayEnabled(event, enabled) {
- var icon = headerSyncButton.querySelector('span');
+ const icon = headerSyncButton.querySelector('span');
icon.classList.remove('sync', 'sync_disabled', 'sync_problem');
if (enabled) {
icon.classList.add('sync');
@@ -207,7 +222,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
}
function onSyncPlaySyncing(event, is_syncing, syncMethod) {
- var icon = headerSyncButton.querySelector('span');
+ const icon = headerSyncButton.querySelector('span');
icon.classList.remove('sync', 'sync_disabled', 'sync_problem');
if (is_syncing) {
icon.classList.add('sync_problem');
@@ -253,9 +268,9 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
}
function refreshLibraryInfoInDrawer(user, drawer) {
- var html = '';
+ let html = '';
html += '