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

Merge branch 'master' into migrate-to-ES6-46

This commit is contained in:
Cameron 2020-08-07 09:17:59 +01:00 committed by GitHub
commit 9843422e55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 1904 additions and 1835 deletions

View file

@ -2,4 +2,3 @@ node_modules
dist dist
.idea .idea
.vscode .vscode
src/libraries

View file

@ -17,7 +17,7 @@
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"browser-sync": "^2.26.12", "browser-sync": "^2.26.12",
"copy-webpack-plugin": "^5.1.1", "copy-webpack-plugin": "^5.1.1",
"css-loader": "^4.2.0", "css-loader": "^4.2.1",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
"del": "^5.1.0", "del": "^5.1.0",
"eslint": "^7.6.0", "eslint": "^7.6.0",
@ -170,6 +170,7 @@
"src/components/syncPlay/syncPlayManager.js", "src/components/syncPlay/syncPlayManager.js",
"src/components/syncPlay/timeSyncManager.js", "src/components/syncPlay/timeSyncManager.js",
"src/components/tabbedview/tabbedview.js", "src/components/tabbedview/tabbedview.js",
"src/components/viewManager/viewManager.js",
"src/components/tvproviders/schedulesdirect.js", "src/components/tvproviders/schedulesdirect.js",
"src/components/tvproviders/xmltv.js", "src/components/tvproviders/xmltv.js",
"src/components/toast/toast.js", "src/components/toast/toast.js",
@ -277,6 +278,8 @@
"src/elements/emby-tabs/emby-tabs.js", "src/elements/emby-tabs/emby-tabs.js",
"src/elements/emby-textarea/emby-textarea.js", "src/elements/emby-textarea/emby-textarea.js",
"src/elements/emby-toggle/emby-toggle.js", "src/elements/emby-toggle/emby-toggle.js",
"src/libraries/navdrawer/navdrawer.js",
"src/libraries/scroller.js",
"src/plugins/backdropScreensaver/plugin.js", "src/plugins/backdropScreensaver/plugin.js",
"src/plugins/bookPlayer/plugin.js", "src/plugins/bookPlayer/plugin.js",
"src/plugins/bookPlayer/tableOfContents.js", "src/plugins/bookPlayer/tableOfContents.js",
@ -303,10 +306,13 @@
"src/scripts/mouseManager.js", "src/scripts/mouseManager.js",
"src/scripts/multiDownload.js", "src/scripts/multiDownload.js",
"src/scripts/playlists.js", "src/scripts/playlists.js",
"src/scripts/scrollHelper.js",
"src/scripts/serverNotifications.js",
"src/scripts/routes.js", "src/scripts/routes.js",
"src/scripts/settings/appSettings.js", "src/scripts/settings/appSettings.js",
"src/scripts/settings/userSettings.js", "src/scripts/settings/userSettings.js",
"src/scripts/settings/webSettings.js", "src/scripts/settings/webSettings.js",
"src/scripts/shell.js",
"src/scripts/taskbutton.js", "src/scripts/taskbutton.js",
"src/scripts/themeLoader.js", "src/scripts/themeLoader.js",
"src/scripts/touchHelper.js" "src/scripts/touchHelper.js"

View file

@ -236,12 +236,6 @@
text-align: center; text-align: center;
} }
.layout-desktop .searchTabButton,
.layout-mobile .searchTabButton,
.layout-tv .headerSearchButton {
display: none !important;
}
.mainDrawer-scrollContainer { .mainDrawer-scrollContainer {
padding-bottom: 10vh; padding-bottom: 10vh;
} }

View file

@ -1,6 +1,7 @@
define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdrop', 'browser', 'page', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, skinManager, backdrop, browser, page, appSettings, appHost, connectionManager) { define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdrop', 'browser', 'page', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, skinManager, backdrop, browser, page, appSettings, appHost, connectionManager) {
'use strict'; 'use strict';
viewManager = viewManager.default || viewManager;
browser = browser.default || browser; browser = browser.default || browser;
loading = loading.default || loading; loading = loading.default || loading;

View file

@ -200,7 +200,7 @@ import 'flexStyles';
} }
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
import('scrollHelper').then(scrollHelper => { import('scrollHelper').then((scrollHelper) => {
const fn = on ? 'on' : 'off'; const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });

View file

@ -354,7 +354,7 @@ import 'scrollStyles';
} }
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
import('scrollHelper').then(scrollHelper => { import('scrollHelper').then((scrollHelper) => {
const fn = on ? 'on' : 'off'; const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });

View file

@ -151,6 +151,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
scrollHelper = scrollHelper.default || scrollHelper;
var fn = on ? 'on' : 'off'; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });

View file

@ -1,6 +1,8 @@
define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) { define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
'use strict'; 'use strict';
scrollHelper = scrollHelper.default || scrollHelper;
function saveCategories(context, options) { function saveCategories(context, options) {
var categories = []; var categories = [];

View file

@ -5,6 +5,8 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
browser = browser.default || browser; browser = browser.default || browser;
loading = loading.default || loading; loading = loading.default || loading;
focusManager = focusManager.default || focusManager; focusManager = focusManager.default || focusManager;
scrollHelper = scrollHelper.default || scrollHelper;
serverNotifications = serverNotifications.default || serverNotifications;
function showViewSettings(instance) { function showViewSettings(instance) {
require(['guide-settings-dialog'], function (guideSettingsDialog) { require(['guide-settings-dialog'], function (guideSettingsDialog) {

View file

@ -1,6 +1,7 @@
define(['playbackManager', 'serverNotifications', 'events'], function (playbackManager, serverNotifications, events) { define(['playbackManager', 'serverNotifications', 'events'], function (playbackManager, serverNotifications, events) {
'use strict'; 'use strict';
serverNotifications = serverNotifications.default || serverNotifications;
playbackManager = playbackManager.default || playbackManager; playbackManager = playbackManager.default || playbackManager;
function onUserDataChanged(e, apiClient, userData) { function onUserDataChanged(e, apiClient, userData) {

View file

@ -2,6 +2,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
'use strict'; 'use strict';
playbackManager = playbackManager.default || playbackManager; playbackManager = playbackManager.default || playbackManager;
serverNotifications = serverNotifications.default || serverNotifications;
function onOneDocumentClick() { function onOneDocumentClick() {
document.removeEventListener('click', onOneDocumentClick); document.removeEventListener('click', onOneDocumentClick);

View file

@ -210,7 +210,7 @@ import 'emby-button';
} }
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
import('scrollHelper').then(scrollHelper => { import('scrollHelper').then((scrollHelper) => {
const fn = on ? 'on' : 'off'; const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });

View file

@ -1,6 +1,8 @@
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'datetime', 'imageLoader', 'recordingFields', 'events', 'emby-checkbox', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, datetime, imageLoader, recordingFields, events) { define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'datetime', 'imageLoader', 'recordingFields', 'events', 'emby-checkbox', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, datetime, imageLoader, recordingFields, events) {
'use strict'; 'use strict';
scrollHelper = scrollHelper.default || scrollHelper;
var currentDialog; var currentDialog;
var closeAction; var closeAction;
var currentRecordingFields; var currentRecordingFields;

View file

@ -1,6 +1,7 @@
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'scrollStyles', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader) { define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'scrollStyles', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader) {
'use strict'; 'use strict';
scrollHelper = scrollHelper.default || scrollHelper;
loading = loading.default || loading; loading = loading.default || loading;
var currentDialog; var currentDialog;

View file

@ -1,6 +1,7 @@
define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields', 'flexStyles'], function (globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events) { define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields', 'flexStyles'], function (globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events) {
'use strict'; 'use strict';
serverNotifications = serverNotifications.default || serverNotifications;
recordingHelper = recordingHelper.default || recordingHelper; recordingHelper = recordingHelper.default || recordingHelper;
loading = loading.default || loading; loading = loading.default || loading;

View file

@ -17,6 +17,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutMana
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
scrollHelper = scrollHelper.default || scrollHelper;
var fn = on ? 'on' : 'off'; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });

View file

@ -337,6 +337,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
scrollHelper = scrollHelper.default || scrollHelper;
var fn = on ? 'on' : 'off'; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });

View file

@ -3,31 +3,9 @@
* @module components/subtitleSettings/subtitleAppearanceHelper * @module components/subtitleSettings/subtitleAppearanceHelper
*/ */
function getTextStyles(settings, isCue) { function getTextStyles(settings, preview) {
let list = []; let list = [];
if (isCue) {
switch (settings.textSize || '') {
case 'smaller':
list.push({ name: 'font-size', value: '.5em' });
break;
case 'small':
list.push({ name: 'font-size', value: '.7em' });
break;
case 'large':
list.push({ name: 'font-size', value: '1.3em' });
break;
case 'larger':
list.push({ name: 'font-size', value: '1.72em' });
break;
case 'extralarge':
list.push({ name: 'font-size', value: '2em' });
break;
default:
case 'medium':
break;
}
} else {
switch (settings.textSize || '') { switch (settings.textSize || '') {
case 'smaller': case 'smaller':
list.push({ name: 'font-size', value: '.8em' }); list.push({ name: 'font-size', value: '.8em' });
@ -49,7 +27,6 @@ function getTextStyles(settings, isCue) {
list.push({ name: 'font-size', value: '1.36em' }); list.push({ name: 'font-size', value: '1.36em' });
break; break;
} }
}
switch (settings.dropShadow || '') { switch (settings.dropShadow || '') {
case 'raised': case 'raised':
@ -111,13 +88,43 @@ function getTextStyles(settings, isCue) {
break; break;
} }
if (!preview) {
const pos = parseInt(settings.verticalPosition, 10);
const lineHeight = 1.35; // FIXME: It is better to read this value from element
const line = Math.abs(pos * lineHeight);
if (pos < 0) {
list.push({ name: 'min-height', value: `${line}em` });
list.push({ name: 'margin-top', value: '' });
} else {
list.push({ name: 'min-height', value: '' });
list.push({ name: 'margin-top', value: `${line}em` });
}
}
return list; return list;
} }
export function getStyles(settings, isCue) { function getWindowStyles(settings, preview) {
const list = [];
if (!preview) {
const pos = parseInt(settings.verticalPosition, 10);
if (pos < 0) {
list.push({ name: 'top', value: '' });
list.push({ name: 'bottom', value: '0' });
} else {
list.push({ name: 'top', value: '0' });
list.push({ name: 'bottom', value: '' });
}
}
return list;
}
export function getStyles(settings, preview) {
return { return {
text: getTextStyles(settings, isCue), text: getTextStyles(settings, preview),
window: [] window: getWindowStyles(settings, preview)
}; };
} }
@ -130,7 +137,7 @@ function applyStyleList(styles, elem) {
} }
export function applyStyles(elements, appearanceSettings) { export function applyStyles(elements, appearanceSettings) {
let styles = getStyles(appearanceSettings); let styles = getStyles(appearanceSettings, !!elements.preview);
if (elements.text) { if (elements.text) {
applyStyleList(styles.text, elements.text); applyStyleList(styles.text, elements.text);

View file

@ -0,0 +1,26 @@
.subtitleappearance-fullpreview {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1000;
pointer-events: none;
transition: 0.2s;
}
.subtitleappearance-fullpreview-hide {
opacity: 0;
}
.subtitleappearance-fullpreview-window {
position: absolute;
width: 100%;
font-size: 170%;
text-align: center;
}
.subtitleappearance-fullpreview-text {
display: inline-block;
max-width: 70%;
}

View file

@ -2,6 +2,7 @@ import globalize from 'globalize';
import appHost from 'apphost'; import appHost from 'apphost';
import appSettings from 'appSettings'; import appSettings from 'appSettings';
import focusManager from 'focusManager'; import focusManager from 'focusManager';
import layoutManager from 'layoutManager';
import loading from 'loading'; import loading from 'loading';
import connectionManager from 'connectionManager'; import connectionManager from 'connectionManager';
import subtitleAppearanceHelper from 'subtitleAppearanceHelper'; import subtitleAppearanceHelper from 'subtitleAppearanceHelper';
@ -10,9 +11,11 @@ import dom from 'dom';
import events from 'events'; import events from 'events';
import 'listViewStyle'; import 'listViewStyle';
import 'emby-select'; import 'emby-select';
import 'emby-slider';
import 'emby-input'; import 'emby-input';
import 'emby-checkbox'; import 'emby-checkbox';
import 'flexStyles'; import 'flexStyles';
import 'css!./subtitlesettings';
/** /**
* Subtitle settings. * Subtitle settings.
@ -27,6 +30,7 @@ function getSubtitleAppearanceObject(context) {
appearanceSettings.font = context.querySelector('#selectFont').value; appearanceSettings.font = context.querySelector('#selectFont').value;
appearanceSettings.textBackground = context.querySelector('#inputTextBackground').value; appearanceSettings.textBackground = context.querySelector('#inputTextBackground').value;
appearanceSettings.textColor = context.querySelector('#inputTextColor').value; appearanceSettings.textColor = context.querySelector('#inputTextColor').value;
appearanceSettings.verticalPosition = context.querySelector('#sliderVerticalPosition').value;
return appearanceSettings; return appearanceSettings;
} }
@ -51,6 +55,7 @@ function loadForm(context, user, userSettings, appearanceSettings, apiClient) {
context.querySelector('#inputTextBackground').value = appearanceSettings.textBackground || 'transparent'; context.querySelector('#inputTextBackground').value = appearanceSettings.textBackground || 'transparent';
context.querySelector('#inputTextColor').value = appearanceSettings.textColor || '#ffffff'; context.querySelector('#inputTextColor').value = appearanceSettings.textColor || '#ffffff';
context.querySelector('#selectFont').value = appearanceSettings.font || ''; context.querySelector('#selectFont').value = appearanceSettings.font || '';
context.querySelector('#sliderVerticalPosition').value = appearanceSettings.verticalPosition;
context.querySelector('#selectSubtitleBurnIn').value = appSettings.get('subtitleburnin') || ''; context.querySelector('#selectSubtitleBurnIn').value = appSettings.get('subtitleburnin') || '';
@ -112,10 +117,45 @@ function onAppearanceFieldChange(e) {
let elements = { let elements = {
window: view.querySelector('.subtitleappearance-preview-window'), window: view.querySelector('.subtitleappearance-preview-window'),
text: view.querySelector('.subtitleappearance-preview-text') text: view.querySelector('.subtitleappearance-preview-text'),
preview: true
}; };
subtitleAppearanceHelper.applyStyles(elements, appearanceSettings); subtitleAppearanceHelper.applyStyles(elements, appearanceSettings);
subtitleAppearanceHelper.applyStyles({
window: view.querySelector('.subtitleappearance-fullpreview-window'),
text: view.querySelector('.subtitleappearance-fullpreview-text')
}, appearanceSettings);
}
const subtitlePreviewDelay = 1000;
let subtitlePreviewTimer;
function showSubtitlePreview(persistent) {
clearTimeout(subtitlePreviewTimer);
this._fullPreview.classList.remove('subtitleappearance-fullpreview-hide');
if (persistent) {
this._refFullPreview++;
}
if (this._refFullPreview === 0) {
subtitlePreviewTimer = setTimeout(hideSubtitlePreview.bind(this), subtitlePreviewDelay);
}
}
function hideSubtitlePreview(persistent) {
clearTimeout(subtitlePreviewTimer);
if (persistent) {
this._refFullPreview--;
}
if (this._refFullPreview === 0) {
this._fullPreview.classList.add('subtitleappearance-fullpreview-hide');
}
} }
function embed(options, self) { function embed(options, self) {
@ -138,6 +178,36 @@ function embed(options, self) {
if (appHost.supports('subtitleappearancesettings')) { if (appHost.supports('subtitleappearancesettings')) {
options.element.querySelector('.subtitleAppearanceSection').classList.remove('hide'); options.element.querySelector('.subtitleAppearanceSection').classList.remove('hide');
self._fullPreview = options.element.querySelector('.subtitleappearance-fullpreview');
self._refFullPreview = 0;
const sliderVerticalPosition = options.element.querySelector('#sliderVerticalPosition');
sliderVerticalPosition.addEventListener('input', onAppearanceFieldChange);
sliderVerticalPosition.addEventListener('input', () => showSubtitlePreview.call(self));
const eventPrefix = window.PointerEvent ? 'pointer' : 'mouse';
sliderVerticalPosition.addEventListener(`${eventPrefix}enter`, () => showSubtitlePreview.call(self, true));
sliderVerticalPosition.addEventListener(`${eventPrefix}leave`, () => hideSubtitlePreview.call(self, true));
if (layoutManager.tv) {
sliderVerticalPosition.addEventListener('focus', () => showSubtitlePreview.call(self, true));
sliderVerticalPosition.addEventListener('blur', () => hideSubtitlePreview.call(self, true));
// Give CustomElements time to attach
setTimeout(() => {
sliderVerticalPosition.classList.add('focusable');
sliderVerticalPosition.enableKeyboardDragging();
}, 0);
}
options.element.querySelector('.chkPreview').addEventListener('change', (e) => {
if (e.target.checked) {
showSubtitlePreview.call(self, true);
} else {
hideSubtitlePreview.call(self, true);
}
});
} }
self.loadData(); self.loadData();

View file

@ -38,6 +38,16 @@
${HeaderSubtitleAppearance} ${HeaderSubtitleAppearance}
</h2> </h2>
<div class="subtitleappearance-fullpreview subtitleappearance-fullpreview-hide">
<div class="subtitleappearance-fullpreview-window">
<div class="subtitleappearance-fullpreview-text">
${HeaderSubtitleAppearance}
<br>
${TheseSettingsAffectSubtitlesOnThisDevice}
</div>
</div>
</div>
<div style="margin: 2em 0 2em;"> <div style="margin: 2em 0 2em;">
<div class="subtitleappearance-preview flex align-items-center justify-content-center" style="margin:2em 0;padding:1.6em;color:black;background:linear-gradient(140deg,#aa5cc3,#00a4dc);"> <div class="subtitleappearance-preview flex align-items-center justify-content-center" style="margin:2em 0;padding:1.6em;color:black;background:linear-gradient(140deg,#aa5cc3,#00a4dc);">
<div class="subtitleappearance-preview-window flex align-items-center justify-content-center" style="width: 90%; padding: .25em;"> <div class="subtitleappearance-preview-window flex align-items-center justify-content-center" style="width: 90%; padding: .25em;">
@ -89,6 +99,20 @@
<option value="">${DropShadow}</option> <option value="">${DropShadow}</option>
</select> </select>
</div> </div>
<div class="sliderContainer-settings">
<div class="sliderContainer">
<input is="emby-slider" id="sliderVerticalPosition" label="${LabelSubtitleVerticalPosition}" type="range" min="-16" max="16" />
</div>
<div class="fieldDescription">${SubtitleVerticalPositionHelp}</div>
</div>
<div class="checkboxContainer">
<label>
<input is="emby-checkbox" type="checkbox" class="chkPreview" />
<span>${Preview}</span>
</label>
</div>
</div> </div>
<button is="emby-button" type="submit" class="raised button-submit block btnSave hide"> <button is="emby-button" type="submit" class="raised button-submit block btnSave hide">

View file

@ -4,6 +4,7 @@ define(['dialogHelper', 'dom', 'layoutManager', 'connectionManager', 'globalize'
browser = browser.default || browser; browser = browser.default || browser;
loading = loading.default || loading; loading = loading.default || loading;
focusManager = focusManager.default || focusManager; focusManager = focusManager.default || focusManager;
scrollHelper = scrollHelper.default || scrollHelper;
var enableFocusTransform = !browser.slow && !browser.edge; var enableFocusTransform = !browser.slow && !browser.edge;

View file

@ -1,22 +1,22 @@
define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], function (viewContainer, focusManager, queryString, layoutManager) { import viewContainer from 'viewContainer';
'use strict'; import focusManager from 'focusManager';
import queryString from 'queryString';
import layoutManager from 'layoutManager';
focusManager = focusManager.default || focusManager; let currentView;
let dispatchPageEvents;
var currentView; viewContainer.setOnBeforeChange(function (newView, isRestored, options) {
var dispatchPageEvents; const lastView = currentView;
viewContainer.setOnBeforeChange(function (newView, isRestored, options) {
var lastView = currentView;
if (lastView) { if (lastView) {
var beforeHideResult = dispatchViewEvent(lastView, null, 'viewbeforehide', true); const beforeHideResult = dispatchViewEvent(lastView, null, 'viewbeforehide', true);
if (!beforeHideResult) { if (!beforeHideResult) {
// todo: cancel // todo: cancel
} }
} }
var eventDetail = getViewEventDetail(newView, options, isRestored); const eventDetail = getViewEventDetail(newView, options, isRestored);
if (!newView.initComplete) { if (!newView.initComplete) {
newView.initComplete = true; newView.initComplete = true;
@ -33,17 +33,17 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
} }
dispatchViewEvent(newView, eventDetail, 'viewbeforeshow'); dispatchViewEvent(newView, eventDetail, 'viewbeforeshow');
}); });
function onViewChange(view, options, isRestore) { function onViewChange(view, options, isRestore) {
var lastView = currentView; const lastView = currentView;
if (lastView) { if (lastView) {
dispatchViewEvent(lastView, null, 'viewhide'); dispatchViewEvent(lastView, null, 'viewhide');
} }
currentView = view; currentView = view;
var eventDetail = getViewEventDetail(view, options, isRestore); const eventDetail = getViewEventDetail(view, options, isRestore);
if (!isRestore) { if (!isRestore) {
if (options.autoFocus !== false) { if (options.autoFocus !== false) {
@ -62,19 +62,19 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
if (dispatchPageEvents) { if (dispatchPageEvents) {
view.dispatchEvent(new CustomEvent('pageshow', eventDetail)); view.dispatchEvent(new CustomEvent('pageshow', eventDetail));
} }
} }
function getProperties(view) { function getProperties(view) {
var props = view.getAttribute('data-properties'); const props = view.getAttribute('data-properties');
if (props) { if (props) {
return props.split(','); return props.split(',');
} }
return []; return [];
} }
function dispatchViewEvent(view, eventInfo, eventName, isCancellable) { function dispatchViewEvent(view, eventInfo, eventName, isCancellable) {
if (!eventInfo) { if (!eventInfo) {
eventInfo = { eventInfo = {
detail: { detail: {
@ -88,7 +88,7 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
eventInfo.cancelable = isCancellable || false; eventInfo.cancelable = isCancellable || false;
var eventResult = view.dispatchEvent(new CustomEvent(eventName, eventInfo)); const eventResult = view.dispatchEvent(new CustomEvent(eventName, eventInfo));
if (dispatchPageEvents) { if (dispatchPageEvents) {
eventInfo.cancelable = false; eventInfo.cancelable = false;
@ -96,12 +96,12 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
} }
return eventResult; return eventResult;
} }
function getViewEventDetail(view, options, isRestore) { function getViewEventDetail(view, options, isRestore) {
var url = options.url; const url = options.url;
var index = url.indexOf('?'); const index = url.indexOf('?');
var params = index === -1 ? {} : queryString.parse(url.substring(index + 1)); const params = index === -1 ? {} : queryString.parse(url.substring(index + 1));
return { return {
detail: { detail: {
@ -117,20 +117,18 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
bubbles: true, bubbles: true,
cancelable: false cancelable: false
}; };
} }
function resetCachedViews() { function resetCachedViews() {
// Reset all cached views whenever the skin changes // Reset all cached views whenever the skin changes
viewContainer.reset(); viewContainer.reset();
} }
document.addEventListener('skinunload', resetCachedViews); document.addEventListener('skinunload', resetCachedViews);
function ViewManager() { class ViewManager {
} loadView(options) {
const lastView = currentView;
ViewManager.prototype.loadView = function (options) {
var lastView = currentView;
// Record the element that has focus // Record the element that has focus
if (lastView) { if (lastView) {
@ -144,9 +142,9 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
viewContainer.loadView(options).then(function (view) { viewContainer.loadView(options).then(function (view) {
onViewChange(view, options); onViewChange(view, options);
}); });
}; }
ViewManager.prototype.tryRestoreView = function (options, onViewChanging) { tryRestoreView(options, onViewChanging) {
if (options.cancel) { if (options.cancel) {
return Promise.reject({ cancelled: true }); return Promise.reject({ cancelled: true });
} }
@ -160,15 +158,15 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
onViewChanging(); onViewChanging();
onViewChange(view, options, true); onViewChange(view, options, true);
}); });
}; }
ViewManager.prototype.currentView = function () { currentView() {
return currentView; return currentView;
}; }
ViewManager.prototype.dispatchPageEvents = function (value) { dispatchPageEvents(value) {
dispatchPageEvents = value; dispatchPageEvents = value;
}; }
}
return new ViewManager(); export default new ViewManager();
});

View file

@ -29,6 +29,7 @@ define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'conne
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) { require(['scrollHelper'], function (scrollHelper) {
scrollHelper = scrollHelper.default || scrollHelper;
var fn = on ? 'on' : 'off'; var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });

View file

@ -1,4 +1,4 @@
define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager', 'cardBuilder', 'loading', 'connectionManager', 'alphaNumericShortcuts', 'scroller', 'playbackManager', 'alphaPicker', 'emby-itemscontainer', 'emby-scroller'], function (globalize, listView, layoutManager, userSettings, focusManager, cardBuilder, loading, connectionManager, AlphaNumericShortcuts, scroller, playbackManager, AlphaPicker) { define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager', 'cardBuilder', 'loading', 'connectionManager', 'alphaNumericShortcuts', 'playbackManager', 'alphaPicker', 'emby-itemscontainer', 'emby-scroller'], function (globalize, listView, layoutManager, userSettings, focusManager, cardBuilder, loading, connectionManager, AlphaNumericShortcuts, playbackManager, AlphaPicker) {
'use strict'; 'use strict';
playbackManager = playbackManager.default || playbackManager; playbackManager = playbackManager.default || playbackManager;

View file

@ -169,9 +169,6 @@ define(['layoutManager', 'userSettings', 'inputManager', 'loading', 'globalize',
name: globalize.translate('HeaderSchedule') name: globalize.translate('HeaderSchedule')
}, { }, {
name: globalize.translate('TabSeries') name: globalize.translate('TabSeries')
}, {
name: globalize.translate('ButtonSearch'),
cssClass: 'searchTabButton'
}]; }];
} }
@ -255,9 +252,6 @@ define(['layoutManager', 'userSettings', 'inputManager', 'loading', 'globalize',
case 5: case 5:
depends.push('controllers/livetv/livetvseriestimers'); depends.push('controllers/livetv/livetvseriestimers');
break; break;
case 6:
depends.push('scripts/searchtab');
} }
require(depends, function (controllerFactory) { require(depends, function (controllerFactory) {

View file

@ -236,9 +236,6 @@ import 'emby-button';
name: globalize.translate('TabCollections') name: globalize.translate('TabCollections')
}, { }, {
name: globalize.translate('TabGenres') name: globalize.translate('TabGenres')
}, {
name: globalize.translate('ButtonSearch'),
cssClass: 'searchTabButton'
}]; }];
} }
@ -306,10 +303,6 @@ import 'emby-button';
case 5: case 5:
depends = 'controllers/movies/moviegenres'; depends = 'controllers/movies/moviegenres';
break; break;
case 6:
depends = 'scripts/searchtab';
break;
} }
import(depends).then(({default: controllerFactory}) => { import(depends).then(({default: controllerFactory}) => {

View file

@ -191,9 +191,6 @@ import 'flexStyles';
name: globalize.translate('TabSongs') name: globalize.translate('TabSongs')
}, { }, {
name: globalize.translate('TabGenres') name: globalize.translate('TabGenres')
}, {
name: globalize.translate('ButtonSearch'),
cssClass: 'searchTabButton'
}]; }];
} }
@ -295,10 +292,6 @@ import 'flexStyles';
case 6: case 6:
depends = 'controllers/music/musicgenres'; depends = 'controllers/music/musicgenres';
break; break;
case 7:
depends = 'scripts/searchtab';
break;
} }
import(depends).then(({default: controllerFactory}) => { import(depends).then(({default: controllerFactory}) => {

View file

@ -30,9 +30,6 @@ import 'emby-button';
name: globalize.translate('TabNetworks') name: globalize.translate('TabNetworks')
}, { }, {
name: globalize.translate('TabEpisodes') name: globalize.translate('TabEpisodes')
}, {
name: globalize.translate('ButtonSearch'),
cssClass: 'searchTabButton'
}]; }];
} }
@ -217,10 +214,6 @@ import 'emby-button';
case 6: case 6:
depends = 'controllers/shows/episodes'; depends = 'controllers/shows/episodes';
break; break;
case 7:
depends = 'scripts/searchtab';
break;
} }
import(depends).then(({default: controllerFactory}) => { import(depends).then(({default: controllerFactory}) => {

View file

@ -230,3 +230,18 @@
margin: 0; margin: 0;
padding: 0.5em 0.75em; padding: 0.5em 0.75em;
} }
/* FIXME: 'sliderContainer' is used to wrap slider's pieces */
.sliderContainer-settings {
margin-bottom: 1.8em;
position: relative;
}
.sliderContainer-settings .mdl-slider-container {
height: 2.83em; /* similar to emby-input with its 110% font-size */
}
.sliderLabel {
display: block;
margin-bottom: 0.25em;
}

View file

@ -150,6 +150,16 @@ import 'emby-input';
this.classList.add('show-focus'); this.classList.add('show-focus');
} }
const topContainer = dom.parentWithClass(this, 'sliderContainer-settings');
if (topContainer && this.getAttribute('label')) {
const label = this.ownerDocument.createElement('label');
label.innerHTML = this.getAttribute('label');
label.classList.add('sliderLabel');
label.htmlFor = this.id;
topContainer.insertBefore(label, topContainer.firstChild);
}
const containerElement = this.parentNode; const containerElement = this.parentNode;
containerElement.classList.add('mdl-slider-container'); containerElement.classList.add('mdl-slider-container');

View file

@ -1,15 +1,19 @@
define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser, dom) { /* Cleaning this file properly is not neecessary, since it's an outdated library
"use strict"; * 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) { export default function (options) {
function getTouches(e) { function getTouches(e) {
return e.changedTouches || e.targetTouches || e.touches; return e.changedTouches || e.targetTouches || e.touches;
} }
function onMenuTouchStart(e) { function onMenuTouchStart(e) {
options.target.classList.remove("transition"); options.target.classList.remove('transition');
var touches = getTouches(e); var touches = getTouches(e);
var touch = touches[0] || {}; var touch = touches[0] || {};
menuTouchStartX = touch.clientX; menuTouchStartX = touch.clientX;
@ -32,27 +36,27 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
var deltaY = endY - (menuTouchStartY || 0); var deltaY = endY - (menuTouchStartY || 0);
setVelocity(deltaX); setVelocity(deltaX);
if (isOpen && 1 !== dragMode && deltaX > 0) { if (isOpen && dragMode !== 1 && deltaX > 0) {
dragMode = 2; dragMode = 2;
} }
if (0 === dragMode && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5) { if (dragMode === 0 && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5) {
dragMode = 1; dragMode = 1;
scrollContainer.addEventListener("scroll", disableEvent); scrollContainer.addEventListener('scroll', disableEvent);
self.showMask(); self.showMask();
} else if (0 === dragMode && Math.abs(deltaY) >= 5) { } else if (dragMode === 0 && Math.abs(deltaY) >= 5) {
dragMode = 2; dragMode = 2;
} }
if (1 === dragMode) { if (dragMode === 1) {
newPos = currentPos + deltaX; newPos = currentPos + deltaX;
self.changeMenuPos(); self.changeMenuPos();
} }
} }
function onMenuTouchEnd(e) { function onMenuTouchEnd(e) {
options.target.classList.add("transition"); options.target.classList.add('transition');
scrollContainer.removeEventListener("scroll", disableEvent); scrollContainer.removeEventListener('scroll', disableEvent);
dragMode = 0; dragMode = 0;
var touches = getTouches(e); var touches = getTouches(e);
var touch = touches[0] || {}; var touch = touches[0] || {};
@ -71,9 +75,9 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
if (((getTouches(e)[0] || {}).clientX || 0) <= options.handleSize) { if (((getTouches(e)[0] || {}).clientX || 0) <= options.handleSize) {
isPeeking = true; isPeeking = true;
if (e.type === "touchstart") { if (e.type === 'touchstart') {
dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}); dom.removeEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
dom.addEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}); dom.addEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
} }
onMenuTouchStart(e); onMenuTouchStart(e);
@ -90,7 +94,7 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
function onEdgeTouchEnd(e) { function onEdgeTouchEnd(e) {
if (isPeeking) { if (isPeeking) {
isPeeking = false; isPeeking = false;
dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}); dom.removeEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
onMenuTouchEnd(e); onMenuTouchEnd(e);
} }
} }
@ -144,8 +148,8 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
function onMaskTransitionEnd() { function onMaskTransitionEnd() {
var classList = mask.classList; var classList = mask.classList;
if (!classList.contains("backdrop")) { if (!classList.contains('backdrop')) {
classList.add("hide"); classList.add('hide');
} }
} }
@ -157,10 +161,10 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
var startPoint = 0; var startPoint = 0;
var countStart = 0; var countStart = 0;
var velocity = 0; var velocity = 0;
options.target.classList.add("transition"); options.target.classList.add('transition');
var dragMode = 0; var dragMode = 0;
var scrollContainer = options.target.querySelector(".mainDrawer-scrollContainer"); var scrollContainer = options.target.querySelector('.mainDrawer-scrollContainer');
scrollContainer.classList.add("scrollY"); scrollContainer.classList.add('scrollY');
var TouchMenuLA = function () { var TouchMenuLA = function () {
self = this; self = this;
@ -175,13 +179,13 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
}; };
TouchMenuLA.prototype.initElements = function () { TouchMenuLA.prototype.initElements = function () {
options.target.classList.add("touch-menu-la"); options.target.classList.add('touch-menu-la');
options.target.style.width = options.width + "px"; options.target.style.width = options.width + 'px';
options.target.style.left = -options.width + "px"; options.target.style.left = -options.width + 'px';
if (!options.disableMask) { if (!options.disableMask) {
mask = document.createElement("div"); mask = document.createElement('div');
mask.className = "tmla-mask hide"; mask.className = 'tmla-mask hide';
document.body.appendChild(mask); document.body.appendChild(mask);
dom.addEventListener(mask, dom.whichTransitionEvent(), onMaskTransitionEnd, { dom.addEventListener(mask, dom.whichTransitionEvent(), onMaskTransitionEnd, {
passive: true passive: true
@ -192,12 +196,12 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
var menuTouchStartX; var menuTouchStartX;
var menuTouchStartY; var menuTouchStartY;
var menuTouchStartTime; var menuTouchStartTime;
var edgeContainer = document.querySelector(".mainDrawerHandle"); var edgeContainer = document.querySelector('.mainDrawerHandle');
var isPeeking = false; var isPeeking = false;
TouchMenuLA.prototype.animateToPosition = function (pos) { TouchMenuLA.prototype.animateToPosition = function (pos) {
requestAnimationFrame(function () { requestAnimationFrame(function () {
options.target.style.transform = pos ? "translateX(" + pos + "px)" : "none"; options.target.style.transform = pos ? 'translateX(' + pos + 'px)' : 'none';
}); });
}; };
@ -208,7 +212,7 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
}; };
TouchMenuLA.prototype.clickMaskClose = function () { TouchMenuLA.prototype.clickMaskClose = function () {
mask.addEventListener("click", function () { mask.addEventListener('click', function () {
self.close(); self.close();
}); });
}; };
@ -235,7 +239,7 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
this.animateToPosition(options.width); this.animateToPosition(options.width);
currentPos = options.width; currentPos = options.width;
this.isVisible = true; this.isVisible = true;
options.target.classList.add("drawer-open"); options.target.classList.add('drawer-open');
self.showMask(); self.showMask();
self.invoke(options.onChange); self.invoke(options.onChange);
}; };
@ -244,7 +248,7 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
this.animateToPosition(0); this.animateToPosition(0);
currentPos = 0; currentPos = 0;
self.isVisible = false; self.isVisible = false;
options.target.classList.remove("drawer-open"); options.target.classList.remove('drawer-open');
self.hideMask(); self.hideMask();
self.invoke(options.onChange); self.invoke(options.onChange);
}; };
@ -261,13 +265,13 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
var backgroundTouchStartTime; var backgroundTouchStartTime;
TouchMenuLA.prototype.showMask = function () { TouchMenuLA.prototype.showMask = function () {
mask.classList.remove("hide"); mask.classList.remove('hide');
mask.classList.add("backdrop"); mask.classList.add('backdrop');
}; };
TouchMenuLA.prototype.hideMask = function () { TouchMenuLA.prototype.hideMask = function () {
mask.classList.add("hide"); mask.classList.add('hide');
mask.classList.remove("backdrop"); mask.classList.remove('backdrop');
}; };
TouchMenuLA.prototype.invoke = function (fn) { TouchMenuLA.prototype.invoke = function (fn) {
@ -284,26 +288,26 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
if (enabled) { if (enabled) {
if (!_edgeSwipeEnabled) { if (!_edgeSwipeEnabled) {
_edgeSwipeEnabled = true; _edgeSwipeEnabled = true;
dom.addEventListener(edgeContainer, "touchstart", onEdgeTouchStart, { dom.addEventListener(edgeContainer, 'touchstart', onEdgeTouchStart, {
passive: true passive: true
}); });
dom.addEventListener(edgeContainer, "touchend", onEdgeTouchEnd, { dom.addEventListener(edgeContainer, 'touchend', onEdgeTouchEnd, {
passive: true passive: true
}); });
dom.addEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, { dom.addEventListener(edgeContainer, 'touchcancel', onEdgeTouchEnd, {
passive: true passive: true
}); });
} }
} else { } else {
if (_edgeSwipeEnabled) { if (_edgeSwipeEnabled) {
_edgeSwipeEnabled = false; _edgeSwipeEnabled = false;
dom.removeEventListener(edgeContainer, "touchstart", onEdgeTouchStart, { dom.removeEventListener(edgeContainer, 'touchstart', onEdgeTouchStart, {
passive: true passive: true
}); });
dom.removeEventListener(edgeContainer, "touchend", onEdgeTouchEnd, { dom.removeEventListener(edgeContainer, 'touchend', onEdgeTouchEnd, {
passive: true passive: true
}); });
dom.removeEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, { dom.removeEventListener(edgeContainer, 'touchcancel', onEdgeTouchEnd, {
passive: true passive: true
}); });
} }
@ -322,26 +326,26 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
self.initElements(); self.initElements();
if (browser.touch) { if (browser.touch) {
dom.addEventListener(options.target, "touchstart", onMenuTouchStart, { dom.addEventListener(options.target, 'touchstart', onMenuTouchStart, {
passive: true passive: true
}); });
dom.addEventListener(options.target, "touchmove", onMenuTouchMove, { dom.addEventListener(options.target, 'touchmove', onMenuTouchMove, {
passive: true passive: true
}); });
dom.addEventListener(options.target, "touchend", onMenuTouchEnd, { dom.addEventListener(options.target, 'touchend', onMenuTouchEnd, {
passive: true passive: true
}); });
dom.addEventListener(options.target, "touchcancel", onMenuTouchEnd, { dom.addEventListener(options.target, 'touchcancel', onMenuTouchEnd, {
passive: true passive: true
}); });
dom.addEventListener(mask, "touchstart", onBackgroundTouchStart, { dom.addEventListener(mask, 'touchstart', onBackgroundTouchStart, {
passive: true passive: true
}); });
dom.addEventListener(mask, "touchmove", onBackgroundTouchMove, {}); dom.addEventListener(mask, 'touchmove', onBackgroundTouchMove, {});
dom.addEventListener(mask, "touchend", onBackgroundTouchEnd, { dom.addEventListener(mask, 'touchend', onBackgroundTouchEnd, {
passive: true passive: true
}); });
dom.addEventListener(mask, "touchcancel", onBackgroundTouchEnd, { dom.addEventListener(mask, 'touchcancel', onBackgroundTouchEnd, {
passive: true passive: true
}); });
} }
@ -350,5 +354,4 @@ define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser,
}; };
return new TouchMenuLA(); return new TouchMenuLA();
}; }
});

View file

@ -1,17 +1,22 @@
define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'scrollStyles'], function (browser, layoutManager, dom, focusManager, ResizeObserver) { /* Cleaning this file properly is not neecessary, since it's an outdated library
'use strict'; * and will be replaced soon by a Vue component.
*/
browser = browser.default || browser; import browser from 'browser';
focusManager = focusManager.default || focusManager; import layoutManager from 'layoutManager';
import dom from 'dom';
import focusManager from 'focusManager';
import ResizeObserver from 'ResizeObserver';
import 'scrollStyles';
/** /**
* Return type of the value. * Return type of the value.
* *
* @param {Mixed} value * @param {Mixed} value
* *
* @return {String} * @return {String}
*/ */
function type(value) { function type(value) {
if (value == null) { if (value == null) {
return String(value); return String(value);
} }
@ -21,23 +26,23 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} }
return typeof value; return typeof value;
} }
/** /**
* Disables an event it was triggered on and unbinds itself. * Disables an event it was triggered on and unbinds itself.
* *
* @param {Event} event * @param {Event} event
* *
* @return {Void} * @return {Void}
*/ */
function disableOneEvent(event) { function disableOneEvent(event) {
/*jshint validthis:true */ /*jshint validthis:true */
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.removeEventListener(event.type, disableOneEvent); this.removeEventListener(event.type, disableOneEvent);
} }
/** /**
* Make sure that number is within the limits. * Make sure that number is within the limits.
* *
* @param {Number} number * @param {Number} number
@ -46,28 +51,17 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* *
* @return {Number} * @return {Number}
*/ */
function within(number, min, max) { function within(number, min, max) {
return number < min ? min : number > max ? max : number; return number < min ? min : number > max ? max : number;
} }
// Other global values // Other global values
var dragMouseEvents = ['mousemove', 'mouseup']; var dragMouseEvents = ['mousemove', 'mouseup'];
var dragTouchEvents = ['touchmove', 'touchend']; var dragTouchEvents = ['touchmove', 'touchend'];
var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
var interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA']; 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) {
var scrollerFactory = function (frame, options) {
// Extend options // Extend options
var o = Object.assign({}, { var o = Object.assign({}, {
slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE. slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
@ -100,11 +94,9 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
// native smooth scroll // native smooth scroll
options.enableNativeScroll = true; options.enableNativeScroll = true;
} else if (options.requireAnimation && (browser.animate || browser.supportsCssAnimation())) { } else if (options.requireAnimation && (browser.animate || browser.supportsCssAnimation())) {
// transform is the only way to guarantee animation // transform is the only way to guarantee animation
options.enableNativeScroll = false; options.enableNativeScroll = false;
} else if (!layoutManager.tv || !browser.animate) { } else if (!layoutManager.tv || !browser.animate) {
options.enableNativeScroll = true; options.enableNativeScroll = true;
} }
@ -165,9 +157,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
var frameSize = 0; var frameSize = 0;
var slideeSize = 0; var slideeSize = 0;
function ensureSizeInfo() { function ensureSizeInfo() {
if (requiresReflow) { if (requiresReflow) {
requiresReflow = false; requiresReflow = false;
// Reset global variables // Reset global variables
@ -176,7 +166,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
slideeSize = o.scrollWidth || Math.max(slideeElement[o.horizontal ? 'offsetWidth' : 'offsetHeight'], slideeElement[o.horizontal ? 'scrollWidth' : 'scrollHeight']); slideeSize = o.scrollWidth || Math.max(slideeElement[o.horizontal ? 'offsetWidth' : 'offsetHeight'], slideeElement[o.horizontal ? 'scrollWidth' : 'scrollHeight']);
// Set position limits & relativess // Set position limits & relativess
self._pos.end = max(slideeSize - frameSize, 0); self._pos.end = Math.max(slideeSize - frameSize, 0);
} }
} }
@ -189,11 +179,9 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* @return {Void} * @return {Void}
*/ */
function load(isInit) { function load(isInit) {
requiresReflow = true; requiresReflow = true;
if (!isInit) { if (!isInit) {
ensureSizeInfo(); ensureSizeInfo();
// Fix possible overflowing // Fix possible overflowing
@ -203,7 +191,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} }
function initFrameResizeObserver() { function initFrameResizeObserver() {
var observerOptions = {}; var observerOptions = {};
self.frameResizeObserver = new ResizeObserver(onResize, observerOptions); self.frameResizeObserver = new ResizeObserver(onResize, observerOptions);
@ -228,16 +215,13 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
}; };
function nativeScrollTo(container, pos, immediate) { function nativeScrollTo(container, pos, immediate) {
if (container.scroll) { if (container.scroll) {
if (o.horizontal) { if (o.horizontal) {
container.scroll({ container.scroll({
left: pos, left: pos,
behavior: immediate ? 'instant' : 'smooth' behavior: immediate ? 'instant' : 'smooth'
}); });
} else { } else {
container.scroll({ container.scroll({
top: pos, top: pos,
behavior: immediate ? 'instant' : 'smooth' behavior: immediate ? 'instant' : 'smooth'
@ -269,14 +253,12 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* @return {Void} * @return {Void}
*/ */
self.slideTo = function (newPos, immediate, fullItemPos) { self.slideTo = function (newPos, immediate, fullItemPos) {
ensureSizeInfo(); ensureSizeInfo();
var pos = self._pos; var pos = self._pos;
newPos = within(newPos, pos.start, pos.end); newPos = within(newPos, pos.start, pos.end);
if (!transform) { if (!transform) {
nativeScrollTo(nativeScrollElement, newPos, immediate); nativeScrollTo(nativeScrollElement, newPos, immediate);
return; return;
} }
@ -294,7 +276,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} }
if (!immediate && o.skipSlideToWhenVisible && fullItemPos && fullItemPos.isVisible) { if (!immediate && o.skipSlideToWhenVisible && fullItemPos && fullItemPos.isVisible) {
return; return;
} }
@ -306,7 +287,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
}; };
function setStyleProperty(elem, name, value, speed, resetTransition) { function setStyleProperty(elem, name, value, speed, resetTransition) {
var style = elem.style; var style = elem.style;
if (resetTransition || browser.edge) { if (resetTransition || browser.edge) {
@ -328,7 +308,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} }
function renderAnimateWithTransform(fromPosition, toPosition, immediate) { function renderAnimateWithTransform(fromPosition, toPosition, immediate) {
var speed = o.speed; var speed = o.speed;
if (immediate) { if (immediate) {
@ -336,9 +315,9 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} }
if (o.horizontal) { if (o.horizontal) {
setStyleProperty(slideeElement, 'transform', 'translateX(' + (-round(toPosition)) + 'px)', speed); setStyleProperty(slideeElement, 'transform', 'translateX(' + (-Math.round(toPosition)) + 'px)', speed);
} else { } else {
setStyleProperty(slideeElement, 'transform', 'translateY(' + (-round(toPosition)) + 'px)', speed); setStyleProperty(slideeElement, 'transform', 'translateY(' + (-Math.round(toPosition)) + 'px)', speed);
} }
self._pos.cur = toPosition; self._pos.cur = toPosition;
@ -346,7 +325,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} }
function getBoundingClientRect(elem) { function getBoundingClientRect(elem) {
// Support: BlackBerry 5, iOS 3 (original iPhone) // Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error // If we don't have gBCR, just use 0,0 rather than error
if (elem.getBoundingClientRect) { if (elem.getBoundingClientRect) {
@ -364,14 +342,10 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* @return {Object} * @return {Object}
*/ */
self.getPos = function (item) { self.getPos = function (item) {
var scrollElement = transform ? slideeElement : nativeScrollElement; var scrollElement = transform ? slideeElement : nativeScrollElement;
var slideeOffset = getBoundingClientRect(scrollElement); var slideeOffset = getBoundingClientRect(scrollElement);
var itemOffset = getBoundingClientRect(item); 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 offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
var size = o.horizontal ? itemOffset.width : itemOffset.height; var size = o.horizontal ? itemOffset.width : itemOffset.height;
@ -408,7 +382,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
}; };
self.getCenterPosition = function (item) { self.getCenterPosition = function (item) {
ensureSizeInfo(); ensureSizeInfo();
var pos = self.getPos(item); var pos = self.getPos(item);
@ -453,7 +426,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
// Bind dragging events // Bind dragging events
if (transform) { if (transform) {
if (isTouch) { if (isTouch) {
dragTouchEvents.forEach(function (eventName) { dragTouchEvents.forEach(function (eventName) {
dom.addEventListener(document, eventName, dragHandler, { dom.addEventListener(document, eventName, dragHandler, {
@ -482,7 +454,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
var pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event; var pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event;
dragging.pathX = pointer.pageX - dragging.initX; dragging.pathX = pointer.pageX - dragging.initX;
dragging.pathY = pointer.pageY - dragging.initY; dragging.pathY = pointer.pageY - dragging.initY;
dragging.path = sqrt(pow(dragging.pathX, 2) + pow(dragging.pathY, 2)); dragging.path = Math.sqrt(Math.pow(dragging.pathX, 2) + Math.pow(dragging.pathY, 2));
dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY; dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY;
if (!dragging.released && dragging.path < 1) { if (!dragging.released && dragging.path < 1) {
@ -499,7 +471,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} else { } else {
// If dragging path is sufficiently long we can confidently start a drag // If dragging path is sufficiently long we can confidently start a drag
// if drag is in different direction than scroll, ignore it // 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)) { if (o.horizontal ? Math.abs(dragging.pathX) > Math.abs(dragging.pathY) : Math.abs(dragging.pathX) < Math.abs(dragging.pathY)) {
dragging.init = 1; dragging.init = 1;
} else { } else {
return dragEnd(); return dragEnd();
@ -520,7 +492,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
dragEnd(); dragEnd();
} }
self.slideTo(round(dragging.initPos - dragging.delta)); self.slideTo(Math.round(dragging.initPos - dragging.delta));
} }
/** /**
@ -557,9 +529,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* @return {Boolean} * @return {Boolean}
*/ */
function isInteractive(element) { function isInteractive(element) {
while (element) { while (element) {
if (interactiveElements.indexOf(element.tagName) !== -1) { if (interactiveElements.indexOf(element.tagName) !== -1) {
return true; return true;
} }
@ -595,7 +565,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* @return {Void} * @return {Void}
*/ */
function scrollHandler(event) { function scrollHandler(event) {
ensureSizeInfo(); ensureSizeInfo();
var pos = self._pos; var pos = self._pos;
// Ignore if there is no scrolling to be done // Ignore if there is no scrolling to be done
@ -612,7 +581,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
self.slideBy(o.scrollBy * delta); self.slideBy(o.scrollBy * delta);
} else { } else {
if (isSmoothScrollSupported) { if (isSmoothScrollSupported) {
delta *= 12; delta *= 12;
} }
@ -631,7 +599,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* @return {Void} * @return {Void}
*/ */
self.destroy = function () { self.destroy = function () {
if (self.frameResizeObserver) { if (self.frameResizeObserver) {
self.frameResizeObserver.disconnect(); self.frameResizeObserver.disconnect();
self.frameResizeObserver = null; self.frameResizeObserver = null;
@ -667,11 +634,9 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
var contentRect = {}; var contentRect = {};
function onResize(entries) { function onResize(entries) {
var entry = entries[0]; var entry = entries[0];
if (entry) { if (entry) {
var newRect = entry.contentRect; var newRect = entry.contentRect;
// handle element being hidden // handle element being hidden
@ -680,7 +645,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} }
if (newRect.width !== contentRect.width || newRect.height !== contentRect.height) { if (newRect.width !== contentRect.width || newRect.height !== contentRect.height) {
contentRect = newRect; contentRect = newRect;
load(false); load(false);
@ -706,7 +670,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
} }
self.getScrollPosition = function () { self.getScrollPosition = function () {
if (transform) { if (transform) {
return self._pos.cur; return self._pos.cur;
} }
@ -719,7 +682,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
}; };
self.getScrollSize = function () { self.getScrollSize = function () {
if (transform) { if (transform) {
return slideeSize; return slideeSize;
} }
@ -795,7 +757,6 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
initFrameResizeObserver(); initFrameResizeObserver();
if (transform) { if (transform) {
dom.addEventListener(dragSourceElement, 'touchstart', dragInitSlidee, { dom.addEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
passive: true passive: true
}); });
@ -812,9 +773,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
passive: true passive: true
}); });
} }
} else if (o.horizontal) { } else if (o.horizontal) {
// Don't bind to mouse events with vertical scroll since the mouse wheel can handle this natively // Don't bind to mouse events with vertical scroll since the mouse wheel can handle this natively
if (o.mouseWheel) { if (o.mouseWheel) {
@ -839,9 +798,9 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
// Return instance // Return instance
return self; return self;
}; };
}; };
/** /**
* Slide SLIDEE by amount of pixels. * Slide SLIDEE by amount of pixels.
* *
* @param {Int} delta Pixels/Items. Positive means forward, negative means backward. * @param {Int} delta Pixels/Items. Positive means forward, negative means backward.
@ -849,14 +808,14 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* *
* @return {Void} * @return {Void}
*/ */
scrollerFactory.prototype.slideBy = function (delta, immediate) { scrollerFactory.prototype.slideBy = function (delta, immediate) {
if (!delta) { if (!delta) {
return; return;
} }
this.slideTo(this._pos.dest + delta, immediate); this.slideTo(this._pos.dest + delta, immediate);
}; };
/** /**
* Core method for handling `toLocation` methods. * Core method for handling `toLocation` methods.
* *
* @param {String} location * @param {String} location
@ -865,7 +824,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* *
* @return {Void} * @return {Void}
*/ */
scrollerFactory.prototype.to = function (location, item, immediate) { scrollerFactory.prototype.to = function (location, item, immediate) {
// Optional arguments logic // Optional arguments logic
if (type(item) === 'boolean') { if (type(item) === 'boolean') {
immediate = item; immediate = item;
@ -881,9 +840,9 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
this.slideTo(itemPos[location], immediate, itemPos); this.slideTo(itemPos[location], immediate, itemPos);
} }
} }
}; };
/** /**
* Animate element or the whole SLIDEE to the start of the frame. * 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 {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
@ -891,11 +850,11 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* *
* @return {Void} * @return {Void}
*/ */
scrollerFactory.prototype.toStart = function (item, immediate) { scrollerFactory.prototype.toStart = function (item, immediate) {
this.to('start', item, immediate); this.to('start', item, immediate);
}; };
/** /**
* Animate element or the whole SLIDEE to the end of the frame. * 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 {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
@ -903,11 +862,11 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* *
* @return {Void} * @return {Void}
*/ */
scrollerFactory.prototype.toEnd = function (item, immediate) { scrollerFactory.prototype.toEnd = function (item, immediate) {
this.to('end', item, immediate); this.to('end', item, immediate);
}; };
/** /**
* Animate element or the whole SLIDEE to the center of the frame. * 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 {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
@ -915,14 +874,13 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc
* *
* @return {Void} * @return {Void}
*/ */
scrollerFactory.prototype.toCenter = function (item, immediate) { scrollerFactory.prototype.toCenter = function (item, immediate) {
this.to('center', item, immediate); this.to('center', item, immediate);
}; };
scrollerFactory.create = function (frame, options) { scrollerFactory.create = function (frame, options) {
var instance = new scrollerFactory(frame, options); var instance = new scrollerFactory(frame, options);
return Promise.resolve(instance); return Promise.resolve(instance);
}; };
return scrollerFactory; export default scrollerFactory;
});

View file

@ -1132,7 +1132,7 @@ function tryRemoveElement(elem) {
*/ */
getCueCss(appearance, selector) { getCueCss(appearance, selector) {
return `${selector}::cue { return `${selector}::cue {
${appearance.text.map((s) => `${s.name}:${s.value}!important;`).join('')} ${appearance.text.map((s) => s.value !== undefined && s.value !== '' ? `${s.name}:${s.value}!important;` : '').join('')}
}`; }`;
} }
@ -1150,7 +1150,7 @@ function tryRemoveElement(elem) {
document.getElementsByTagName('head')[0].appendChild(styleElem); document.getElementsByTagName('head')[0].appendChild(styleElem);
} }
styleElem.innerHTML = this.getCueCss(subtitleAppearanceHelper.getStyles(userSettings.getSubtitleAppearanceSettings(), true), '.htmlvideoplayer'); styleElem.innerHTML = this.getCueCss(subtitleAppearanceHelper.getStyles(userSettings.getSubtitleAppearanceSettings()), '.htmlvideoplayer');
}); });
} }
@ -1195,18 +1195,29 @@ function tryRemoveElement(elem) {
// download the track json // download the track json
this.fetchSubtitles(track, item).then(function (data) { this.fetchSubtitles(track, item).then(function (data) {
import('userSettings').then((userSettings) => {
// show in ui // show in ui
console.debug(`downloaded ${data.TrackEvents.length} track events`); console.debug(`downloaded ${data.TrackEvents.length} track events`);
const subtitleAppearance = userSettings.getSubtitleAppearanceSettings();
const cueLine = parseInt(subtitleAppearance.verticalPosition, 10);
// add some cues to show the text // add some cues to show the text
// in safari, the cues need to be added before setting the track mode to showing // in safari, the cues need to be added before setting the track mode to showing
for (const trackEvent of data.TrackEvents) { for (const trackEvent of data.TrackEvents) {
const trackCueObject = window.VTTCue || window.TextTrackCue; const trackCueObject = window.VTTCue || window.TextTrackCue;
const cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false)); const cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false));
if (cue.line === 'auto') {
cue.line = cueLine;
}
trackElement.addCue(cue); trackElement.addCue(cue);
} }
trackElement.mode = 'showing'; trackElement.mode = 'showing';
}); });
});
} }
/** /**

View file

@ -33,16 +33,22 @@ video::-webkit-media-controls {
text-shadow: 0.14em 0.14em 0.14em rgba(0, 0, 0, 1); text-shadow: 0.14em 0.14em 0.14em rgba(0, 0, 0, 1);
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
font-family: inherit; font-family: inherit;
line-height: normal; /* Restore value. See -webkit-media-text-track-container 'line-height' */
} }
.htmlvideoplayer-moveupsubtitles::-webkit-media-text-track-display { .htmlvideoplayer::-webkit-media-text-track-container {
/* style the text itself */ font-size: 170% !important; /* Override element inline style */
margin-top: -2em; line-height: 50%; /* Child element cannot set line height smaller than its parent has. This allow smaller values for children */
}
.htmlvideoplayer::-webkit-media-text-track-display {
max-width: 70%;
margin-left: 15%;
} }
.videoSubtitles { .videoSubtitles {
position: fixed; position: fixed;
bottom: 10%; bottom: 0;
text-align: center; text-align: center;
left: 0; left: 0;
right: 0; right: 0;
@ -53,7 +59,6 @@ video::-webkit-media-controls {
.videoSubtitlesInner { .videoSubtitlesInner {
max-width: 70%; max-width: 70%;
background-color: rgba(0, 0, 0, 0.8); background-color: rgba(0, 0, 0, 0.8);
padding: 0.25em;
margin: auto; margin: auto;
display: inline-block; display: inline-block;
} }

View file

@ -1,6 +1,7 @@
define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'], function (playbackManager, events, serverNotifications, connectionManager) { define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'], function (playbackManager, events, serverNotifications, connectionManager) {
'use strict'; 'use strict';
serverNotifications = serverNotifications.default || serverNotifications;
playbackManager = playbackManager.default || playbackManager; playbackManager = playbackManager.default || playbackManager;
function getActivePlayerId() { function getActivePlayerId() {

View file

@ -1,9 +1,8 @@
define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) { import focusManager from 'focusManager';
'use strict'; import dom from 'dom';
import 'scrollStyles';
focusManager = focusManager.default || focusManager; function getBoundingClientRect(elem) {
function getBoundingClientRect(elem) {
// Support: BlackBerry 5, iOS 3 (original iPhone) // Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error // If we don't have gBCR, just use 0,0 rather than error
if (elem.getBoundingClientRect) { if (elem.getBoundingClientRect) {
@ -11,27 +10,27 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
} else { } else {
return { top: 0, left: 0 }; return { top: 0, left: 0 };
} }
} }
function getPosition(scrollContainer, item, horizontal) { export function getPosition(scrollContainer, item, horizontal) {
var slideeOffset = getBoundingClientRect(scrollContainer); const slideeOffset = getBoundingClientRect(scrollContainer);
var itemOffset = getBoundingClientRect(item); const itemOffset = getBoundingClientRect(item);
var offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top; let offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
var size = horizontal ? itemOffset.width : itemOffset.height; let size = horizontal ? itemOffset.width : itemOffset.height;
if (!size && size !== 0) { if (!size && size !== 0) {
size = item[horizontal ? 'offsetWidth' : 'offsetHeight']; size = item[horizontal ? 'offsetWidth' : 'offsetHeight'];
} }
var currentStart = horizontal ? scrollContainer.scrollLeft : scrollContainer.scrollTop; const currentStart = horizontal ? scrollContainer.scrollLeft : scrollContainer.scrollTop;
offset += currentStart; offset += currentStart;
var frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight; const frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight;
var currentEnd = currentStart + frameSize; const currentEnd = currentStart + frameSize;
var isVisible = offset >= currentStart && (offset + size) <= currentEnd; const isVisible = offset >= currentStart && (offset + size) <= currentEnd;
return { return {
start: offset, start: offset,
@ -40,10 +39,10 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
size: size, size: size,
isVisible: isVisible isVisible: isVisible
}; };
} }
function toCenter(container, elem, horizontal, skipWhenVisible) { export function toCenter(container, elem, horizontal, skipWhenVisible) {
var pos = getPosition(container, elem, horizontal); const pos = getPosition(container, elem, horizontal);
if (skipWhenVisible && pos.isVisible) { if (skipWhenVisible && pos.isVisible) {
return; return;
@ -62,10 +61,10 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
container.scrollTop = Math.round(pos.center); container.scrollTop = Math.round(pos.center);
} }
} }
} }
function toStart(container, elem, horizontal, skipWhenVisible) { export function toStart(container, elem, horizontal, skipWhenVisible) {
var pos = getPosition(container, elem, horizontal); const pos = getPosition(container, elem, horizontal);
if (skipWhenVisible && pos.isVisible) { if (skipWhenVisible && pos.isVisible) {
return; return;
@ -84,26 +83,25 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
container.scrollTop = Math.round(pos.start); container.scrollTop = Math.round(pos.start);
} }
} }
} }
function centerOnFocus(e, scrollSlider, horizontal) { function centerOnFocus(e, scrollSlider, horizontal) {
var focused = focusManager.focusableParent(e.target); const focused = focusManager.focusableParent(e.target);
if (focused) { if (focused) {
toCenter(scrollSlider, focused, horizontal); toCenter(scrollSlider, focused, horizontal);
} }
} }
function centerOnFocusHorizontal(e) { function centerOnFocusHorizontal(e) {
centerOnFocus(e, this, true); centerOnFocus(e, this, true);
} }
function centerOnFocusVertical(e) {
centerOnFocus(e, this, false);
}
return { function centerOnFocusVertical(e) {
getPosition: getPosition, centerOnFocus(e, this, false);
centerFocus: { }
export const centerFocus = {
on: function (element, horizontal) { on: function (element, horizontal) {
if (horizontal) { if (horizontal) {
dom.addEventListener(element, 'focus', centerOnFocusHorizontal, { dom.addEventListener(element, 'focus', centerOnFocusHorizontal, {
@ -130,8 +128,11 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) {
}); });
} }
} }
}, };
export default {
getPosition: getPosition,
centerFocus: centerFocus,
toCenter: toCenter, toCenter: toCenter,
toStart: toStart toStart: toStart
}; };
});

View file

@ -1,57 +0,0 @@
define(['searchFields', 'searchResults', 'events'], function (SearchFields, SearchResults, events) {
'use strict';
SearchFields = SearchFields.default || SearchFields;
SearchResults = SearchResults.default || SearchResults;
function init(instance, tabContent, options) {
tabContent.innerHTML = '<div class="padded-left padded-right searchFields"></div><div class="searchResults padded-top" style="padding-top:1.5em;"></div>';
instance.searchFields = new SearchFields({
element: tabContent.querySelector('.searchFields')
});
instance.searchResults = new SearchResults({
element: tabContent.querySelector('.searchResults'),
serverId: ApiClient.serverId(),
parentId: options.parentId,
collectionType: options.collectionType
});
events.on(instance.searchFields, 'search', function (e, value) {
instance.searchResults.search(value);
});
}
function SearchTab(view, tabContent, options) {
var self = this;
options = options || {};
init(this, tabContent, options);
self.preRender = function () {};
self.renderTab = function () {
var searchFields = this.searchFields;
if (searchFields) {
searchFields.focus();
}
};
}
SearchTab.prototype.destroy = function () {
var searchFields = this.searchFields;
if (searchFields) {
searchFields.destroy();
}
this.searchFields = null;
var searchResults = this.searchResults;
if (searchResults) {
searchResults.destroy();
}
this.searchResults = null;
};
return SearchTab;
});

View file

@ -1,41 +1,43 @@
define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'inputManager', 'focusManager', 'appRouter'], function (connectionManager, playbackManager, syncPlayManager, events, inputManager, focusManager, appRouter) { import connectionManager from 'connectionManager';
'use strict'; import playbackManager from 'playbackManager';
import syncPlayManager from 'syncPlayManager';
import events from 'events';
import inputManager from 'inputManager';
import focusManager from 'focusManager';
import appRouter from 'appRouter';
playbackManager = playbackManager.default || playbackManager; const serverNotifications = {};
focusManager = focusManager.default || focusManager;
var serverNotifications = {}; function notifyApp() {
function notifyApp() {
inputManager.notify(); inputManager.notify();
} }
function displayMessage(cmd) { function displayMessage(cmd) {
var args = cmd.Arguments; const args = cmd.Arguments;
if (args.TimeoutMs) { if (args.TimeoutMs) {
require(['toast'], function (toast) { import('toast').then(({default: toast}) => {
toast({ title: args.Header, text: args.Text }); toast({ title: args.Header, text: args.Text });
}); });
} else { } else {
require(['alert'], function (alert) { import('alert').then(({default: alert}) => {
alert.default({ title: args.Header, text: args.Text }); alert({ title: args.Header, text: args.Text });
}); });
} }
} }
function displayContent(cmd, apiClient) { function displayContent(cmd, apiClient) {
if (!playbackManager.isPlayingLocally(['Video', 'Book'])) { if (!playbackManager.isPlayingLocally(['Video', 'Book'])) {
appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId()); appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId());
} }
} }
function playTrailers(apiClient, itemId) { function playTrailers(apiClient, itemId) {
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
playbackManager.playTrailers(item); playbackManager.playTrailers(item);
}); });
} }
function processGeneralCommand(cmd, apiClient) { function processGeneralCommand(cmd, apiClient) {
console.debug('Received command: ' + cmd.Name); console.debug('Received command: ' + cmd.Name);
switch (cmd.Name) { switch (cmd.Name) {
case 'Select': case 'Select':
@ -144,13 +146,13 @@ define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'in
} }
notifyApp(); notifyApp();
} }
function onMessageReceived(e, msg) { function onMessageReceived(e, msg) {
var apiClient = this; const apiClient = this;
if (msg.MessageType === 'Play') { if (msg.MessageType === 'Play') {
notifyApp(); notifyApp();
var serverId = apiClient.serverInfo().Id; const serverId = apiClient.serverInfo().Id;
if (msg.Data.PlayCommand === 'PlayNext') { if (msg.Data.PlayCommand === 'PlayNext') {
playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId }); playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId });
} else if (msg.Data.PlayCommand === 'PlayLast') { } else if (msg.Data.PlayCommand === 'PlayLast') {
@ -185,11 +187,11 @@ define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'in
notifyApp(); notifyApp();
} }
} else if (msg.MessageType === 'GeneralCommand') { } else if (msg.MessageType === 'GeneralCommand') {
var cmd = msg.Data; const cmd = msg.Data;
processGeneralCommand(cmd, apiClient); processGeneralCommand(cmd, apiClient);
} else if (msg.MessageType === 'UserDataChanged') { } else if (msg.MessageType === 'UserDataChanged') {
if (msg.Data.UserId === apiClient.getCurrentUserId()) { if (msg.Data.UserId === apiClient.getCurrentUserId()) {
for (var i = 0, length = msg.Data.UserDataList.length; i < length; i++) { for (let i = 0, length = msg.Data.UserDataList.length; i < length; i++) {
events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]); events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]);
} }
} }
@ -200,15 +202,15 @@ define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'in
} else { } else {
events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]); events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]);
} }
} }
function bindEvents(apiClient) { function bindEvents(apiClient) {
events.off(apiClient, 'message', onMessageReceived); events.off(apiClient, 'message', onMessageReceived);
events.on(apiClient, 'message', onMessageReceived); events.on(apiClient, 'message', onMessageReceived);
} }
connectionManager.getApiClients().forEach(bindEvents); connectionManager.getApiClients().forEach(bindEvents);
events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) { events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {
bindEvents(newApiClient); bindEvents(newApiClient);
});
return serverNotifications;
}); });
export default serverNotifications;

View file

@ -15,6 +15,10 @@ function saveServerPreferences(instance) {
instance.saveTimeout = setTimeout(onSaveTimeout.bind(instance), 50); instance.saveTimeout = setTimeout(onSaveTimeout.bind(instance), 50);
} }
const defaultSubtitleAppearanceSettings = {
verticalPosition: -3
};
export class UserSettings { export class UserSettings {
constructor() { constructor() {
} }
@ -412,7 +416,7 @@ export class UserSettings {
*/ */
getSubtitleAppearanceSettings(key) { getSubtitleAppearanceSettings(key) {
key = key || 'localplayersubtitleappearance3'; key = key || 'localplayersubtitleappearance3';
return JSON.parse(this.get(key, false) || '{}'); return Object.assign(defaultSubtitleAppearanceSettings, JSON.parse(this.get(key, false) || '{}'));
} }
/** /**

View file

@ -1,7 +1,5 @@
define([], function () { // TODO: This seems like a good candidate for deprecation
'use strict'; export default {
return {
openUrl: function (url, target) { openUrl: function (url, target) {
if (window.NativeShell) { if (window.NativeShell) {
window.NativeShell.openUrl(url, target); window.NativeShell.openUrl(url, target);
@ -19,5 +17,4 @@ define([], function () {
window.NativeShell.disableFullscreen(); window.NativeShell.disableFullscreen();
} }
} }
}; };
});

View file

@ -813,8 +813,8 @@ function initClient() {
define('tvguide', [componentsPath + '/guide/guide'], returnFirstDependency); define('tvguide', [componentsPath + '/guide/guide'], returnFirstDependency);
define('guide-settings-dialog', [componentsPath + '/guide/guide-settings'], returnFirstDependency); define('guide-settings-dialog', [componentsPath + '/guide/guide-settings'], returnFirstDependency);
define('viewManager', [componentsPath + '/viewManager/viewManager'], function (viewManager) { define('viewManager', [componentsPath + '/viewManager/viewManager'], function (viewManager) {
window.ViewManager = viewManager; window.ViewManager = viewManager.default;
viewManager.dispatchPageEvents(true); viewManager.default.dispatchPageEvents(true);
return viewManager; return viewManager;
}); });
define('slideshow', [componentsPath + '/slideshow/slideshow'], returnFirstDependency); define('slideshow', [componentsPath + '/slideshow/slideshow'], returnFirstDependency);

View file

@ -1542,5 +1542,8 @@
"ButtonCast": "Cast", "ButtonCast": "Cast",
"ButtonPlayer": "Player", "ButtonPlayer": "Player",
"StopPlayback": "Stop playback", "StopPlayback": "Stop playback",
"ClearQueue": "Clear queue" "ClearQueue": "Clear queue",
"LabelSubtitleVerticalPosition": "Vertical position:",
"SubtitleVerticalPositionHelp": "Line number where text appears. Positive numbers indicate top down. Negative numbers indicate bottom up.",
"Preview": "Preview"
} }

View file

@ -1542,5 +1542,8 @@
"ButtonPlayer": "Проигрыватель", "ButtonPlayer": "Проигрыватель",
"PreviousTrack": "Перейти к предыдущему", "PreviousTrack": "Перейти к предыдущему",
"NextTrack": "Перейти к следующему", "NextTrack": "Перейти к следующему",
"LabelUnstable": "Нестабильная" "LabelUnstable": "Нестабильная",
"LabelSubtitleVerticalPosition": "Вертикальная позиция:",
"SubtitleVerticalPositionHelp": "Номер строки, где появляется текст. Положительные числа означают сверху вниз. Отрицательные числа означают снизу вверх.",
"Preview": "Предварительный просмотр"
} }

View file

@ -3020,10 +3020,10 @@ css-has-pseudo@^0.10.0:
postcss "^7.0.6" postcss "^7.0.6"
postcss-selector-parser "^5.0.0-rc.4" postcss-selector-parser "^5.0.0-rc.4"
css-loader@^4.2.0: css-loader@^4.2.1:
version "4.2.0" version "4.2.1"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.2.0.tgz#b57efb92ac8f0cd85bf92d89df9634ef1f51b8bf" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.2.1.tgz#9f48fd7eae1219d629a3f085ba9a9102ca1141a7"
integrity sha512-ko7a9b0iFpWtk9eSI/C8IICvZeGtYnjxYjw45rJprokXj/+kBd/siX4vAIBq9Uij8Jubc4jL1EvSnTjCEwaHSw== integrity sha512-MoqmF1if7Z0pZIEXA4ZF9PgtCXxWbfzfJM+3p+OYfhcrwcqhaCRb74DSnfzRl7e024xEiCRn5hCvfUbTf2sgFA==
dependencies: dependencies:
camelcase "^6.0.0" camelcase "^6.0.0"
cssesc "^3.0.0" cssesc "^3.0.0"