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:
commit
9843422e55
45 changed files with 1904 additions and 1835 deletions
|
@ -2,4 +2,3 @@ node_modules
|
||||||
dist
|
dist
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
src/libraries
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 = [];
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,52 +3,29 @@
|
||||||
* @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 || '') {
|
||||||
switch (settings.textSize || '') {
|
case 'smaller':
|
||||||
case 'smaller':
|
list.push({ name: 'font-size', value: '.8em' });
|
||||||
list.push({ name: 'font-size', value: '.5em' });
|
break;
|
||||||
break;
|
case 'small':
|
||||||
case 'small':
|
list.push({ name: 'font-size', value: 'inherit' });
|
||||||
list.push({ name: 'font-size', value: '.7em' });
|
break;
|
||||||
break;
|
case 'larger':
|
||||||
case 'large':
|
list.push({ name: 'font-size', value: '2em' });
|
||||||
list.push({ name: 'font-size', value: '1.3em' });
|
break;
|
||||||
break;
|
case 'extralarge':
|
||||||
case 'larger':
|
list.push({ name: 'font-size', value: '2.2em' });
|
||||||
list.push({ name: 'font-size', value: '1.72em' });
|
break;
|
||||||
break;
|
case 'large':
|
||||||
case 'extralarge':
|
list.push({ name: 'font-size', value: '1.72em' });
|
||||||
list.push({ name: 'font-size', value: '2em' });
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
case 'medium':
|
||||||
case 'medium':
|
list.push({ name: 'font-size', value: '1.36em' });
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (settings.textSize || '') {
|
|
||||||
case 'smaller':
|
|
||||||
list.push({ name: 'font-size', value: '.8em' });
|
|
||||||
break;
|
|
||||||
case 'small':
|
|
||||||
list.push({ name: 'font-size', value: 'inherit' });
|
|
||||||
break;
|
|
||||||
case 'larger':
|
|
||||||
list.push({ name: 'font-size', value: '2em' });
|
|
||||||
break;
|
|
||||||
case 'extralarge':
|
|
||||||
list.push({ name: 'font-size', value: '2.2em' });
|
|
||||||
break;
|
|
||||||
case 'large':
|
|
||||||
list.push({ name: 'font-size', value: '1.72em' });
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case 'medium':
|
|
||||||
list.push({ name: 'font-size', value: '1.36em' });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (settings.dropShadow || '') {
|
switch (settings.dropShadow || '') {
|
||||||
|
@ -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);
|
||||||
|
|
26
src/components/subtitlesettings/subtitlesettings.css
Normal file
26
src/components/subtitlesettings/subtitlesettings.css
Normal 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%;
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -1,136 +1,134 @@
|
||||||
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;
|
||||||
|
if (lastView) {
|
||||||
|
const beforeHideResult = dispatchViewEvent(lastView, null, 'viewbeforehide', true);
|
||||||
|
|
||||||
viewContainer.setOnBeforeChange(function (newView, isRestored, options) {
|
if (!beforeHideResult) {
|
||||||
var lastView = currentView;
|
// todo: cancel
|
||||||
if (lastView) {
|
|
||||||
var beforeHideResult = dispatchViewEvent(lastView, null, 'viewbeforehide', true);
|
|
||||||
|
|
||||||
if (!beforeHideResult) {
|
|
||||||
// todo: cancel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventDetail = getViewEventDetail(newView, options, isRestored);
|
|
||||||
|
|
||||||
if (!newView.initComplete) {
|
|
||||||
newView.initComplete = true;
|
|
||||||
|
|
||||||
if (typeof options.controllerFactory === 'function') {
|
|
||||||
new options.controllerFactory(newView, eventDetail.detail.params);
|
|
||||||
} else if (options.controllerFactory && typeof options.controllerFactory.default === 'function') {
|
|
||||||
new options.controllerFactory.default(newView, eventDetail.detail.params);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.controllerFactory || dispatchPageEvents) {
|
|
||||||
dispatchViewEvent(newView, eventDetail, 'viewinit');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchViewEvent(newView, eventDetail, 'viewbeforeshow');
|
|
||||||
});
|
|
||||||
|
|
||||||
function onViewChange(view, options, isRestore) {
|
|
||||||
var lastView = currentView;
|
|
||||||
if (lastView) {
|
|
||||||
dispatchViewEvent(lastView, null, 'viewhide');
|
|
||||||
}
|
|
||||||
|
|
||||||
currentView = view;
|
|
||||||
|
|
||||||
var eventDetail = getViewEventDetail(view, options, isRestore);
|
|
||||||
|
|
||||||
if (!isRestore) {
|
|
||||||
if (options.autoFocus !== false) {
|
|
||||||
focusManager.autoFocus(view);
|
|
||||||
}
|
|
||||||
} else if (!layoutManager.mobile) {
|
|
||||||
if (view.activeElement && document.body.contains(view.activeElement) && focusManager.isCurrentlyFocusable(view.activeElement)) {
|
|
||||||
focusManager.focus(view.activeElement);
|
|
||||||
} else {
|
|
||||||
focusManager.autoFocus(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view.dispatchEvent(new CustomEvent('viewshow', eventDetail));
|
|
||||||
|
|
||||||
if (dispatchPageEvents) {
|
|
||||||
view.dispatchEvent(new CustomEvent('pageshow', eventDetail));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProperties(view) {
|
const eventDetail = getViewEventDetail(newView, options, isRestored);
|
||||||
var props = view.getAttribute('data-properties');
|
|
||||||
|
|
||||||
if (props) {
|
if (!newView.initComplete) {
|
||||||
return props.split(',');
|
newView.initComplete = true;
|
||||||
|
|
||||||
|
if (typeof options.controllerFactory === 'function') {
|
||||||
|
new options.controllerFactory(newView, eventDetail.detail.params);
|
||||||
|
} else if (options.controllerFactory && typeof options.controllerFactory.default === 'function') {
|
||||||
|
new options.controllerFactory.default(newView, eventDetail.detail.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
if (!options.controllerFactory || dispatchPageEvents) {
|
||||||
|
dispatchViewEvent(newView, eventDetail, 'viewinit');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispatchViewEvent(view, eventInfo, eventName, isCancellable) {
|
dispatchViewEvent(newView, eventDetail, 'viewbeforeshow');
|
||||||
if (!eventInfo) {
|
});
|
||||||
eventInfo = {
|
|
||||||
detail: {
|
|
||||||
type: view.getAttribute('data-type'),
|
|
||||||
properties: getProperties(view)
|
|
||||||
},
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: isCancellable
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
eventInfo.cancelable = isCancellable || false;
|
function onViewChange(view, options, isRestore) {
|
||||||
|
const lastView = currentView;
|
||||||
var eventResult = view.dispatchEvent(new CustomEvent(eventName, eventInfo));
|
if (lastView) {
|
||||||
|
dispatchViewEvent(lastView, null, 'viewhide');
|
||||||
if (dispatchPageEvents) {
|
|
||||||
eventInfo.cancelable = false;
|
|
||||||
view.dispatchEvent(new CustomEvent(eventName.replace('view', 'page'), eventInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
return eventResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getViewEventDetail(view, options, isRestore) {
|
currentView = view;
|
||||||
var url = options.url;
|
|
||||||
var index = url.indexOf('?');
|
|
||||||
var params = index === -1 ? {} : queryString.parse(url.substring(index + 1));
|
|
||||||
|
|
||||||
return {
|
const eventDetail = getViewEventDetail(view, options, isRestore);
|
||||||
|
|
||||||
|
if (!isRestore) {
|
||||||
|
if (options.autoFocus !== false) {
|
||||||
|
focusManager.autoFocus(view);
|
||||||
|
}
|
||||||
|
} else if (!layoutManager.mobile) {
|
||||||
|
if (view.activeElement && document.body.contains(view.activeElement) && focusManager.isCurrentlyFocusable(view.activeElement)) {
|
||||||
|
focusManager.focus(view.activeElement);
|
||||||
|
} else {
|
||||||
|
focusManager.autoFocus(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.dispatchEvent(new CustomEvent('viewshow', eventDetail));
|
||||||
|
|
||||||
|
if (dispatchPageEvents) {
|
||||||
|
view.dispatchEvent(new CustomEvent('pageshow', eventDetail));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProperties(view) {
|
||||||
|
const props = view.getAttribute('data-properties');
|
||||||
|
|
||||||
|
if (props) {
|
||||||
|
return props.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function dispatchViewEvent(view, eventInfo, eventName, isCancellable) {
|
||||||
|
if (!eventInfo) {
|
||||||
|
eventInfo = {
|
||||||
detail: {
|
detail: {
|
||||||
type: view.getAttribute('data-type'),
|
type: view.getAttribute('data-type'),
|
||||||
properties: getProperties(view),
|
properties: getProperties(view)
|
||||||
params: params,
|
|
||||||
isRestored: isRestore,
|
|
||||||
state: options.state,
|
|
||||||
|
|
||||||
// The route options
|
|
||||||
options: options.options || {}
|
|
||||||
},
|
},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: false
|
cancelable: isCancellable
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetCachedViews() {
|
eventInfo.cancelable = isCancellable || false;
|
||||||
// Reset all cached views whenever the skin changes
|
|
||||||
viewContainer.reset();
|
const eventResult = view.dispatchEvent(new CustomEvent(eventName, eventInfo));
|
||||||
|
|
||||||
|
if (dispatchPageEvents) {
|
||||||
|
eventInfo.cancelable = false;
|
||||||
|
view.dispatchEvent(new CustomEvent(eventName.replace('view', 'page'), eventInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('skinunload', resetCachedViews);
|
return eventResult;
|
||||||
|
}
|
||||||
|
|
||||||
function ViewManager() {
|
function getViewEventDetail(view, options, isRestore) {
|
||||||
}
|
const url = options.url;
|
||||||
|
const index = url.indexOf('?');
|
||||||
|
const params = index === -1 ? {} : queryString.parse(url.substring(index + 1));
|
||||||
|
|
||||||
ViewManager.prototype.loadView = function (options) {
|
return {
|
||||||
var lastView = currentView;
|
detail: {
|
||||||
|
type: view.getAttribute('data-type'),
|
||||||
|
properties: getProperties(view),
|
||||||
|
params: params,
|
||||||
|
isRestored: isRestore,
|
||||||
|
state: options.state,
|
||||||
|
|
||||||
|
// The route options
|
||||||
|
options: options.options || {}
|
||||||
|
},
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetCachedViews() {
|
||||||
|
// Reset all cached views whenever the skin changes
|
||||||
|
viewContainer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('skinunload', resetCachedViews);
|
||||||
|
|
||||||
|
class ViewManager {
|
||||||
|
loadView(options) {
|
||||||
|
const 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();
|
||||||
});
|
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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}) => {
|
||||||
|
|
|
@ -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}) => {
|
||||||
|
|
|
@ -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}) => {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
|
||||||
|
|
|
@ -1,354 +1,357 @@
|
||||||
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) {
|
||||||
|
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) {
|
if (dragMode === 0 && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5) {
|
||||||
options.target.classList.remove("transition");
|
dragMode = 1;
|
||||||
var touches = getTouches(e);
|
scrollContainer.addEventListener('scroll', disableEvent);
|
||||||
var touch = touches[0] || {};
|
self.showMask();
|
||||||
menuTouchStartX = touch.clientX;
|
} else if (dragMode === 0 && Math.abs(deltaY) >= 5) {
|
||||||
menuTouchStartY = touch.clientY;
|
dragMode = 2;
|
||||||
menuTouchStartTime = new Date().getTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setVelocity(deltaX) {
|
if (dragMode === 1) {
|
||||||
var time = new Date().getTime() - (menuTouchStartTime || 0);
|
newPos = currentPos + deltaX;
|
||||||
velocity = Math.abs(deltaX) / time;
|
self.changeMenuPos();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onMenuTouchMove(e) {
|
function onMenuTouchEnd(e) {
|
||||||
var isOpen = self.visible;
|
options.target.classList.add('transition');
|
||||||
var touches = getTouches(e);
|
scrollContainer.removeEventListener('scroll', disableEvent);
|
||||||
var touch = touches[0] || {};
|
dragMode = 0;
|
||||||
var endX = touch.clientX || 0;
|
var touches = getTouches(e);
|
||||||
var endY = touch.clientY || 0;
|
var touch = touches[0] || {};
|
||||||
var deltaX = endX - (menuTouchStartX || 0);
|
var endX = touch.clientX || 0;
|
||||||
var deltaY = endY - (menuTouchStartY || 0);
|
var endY = touch.clientY || 0;
|
||||||
setVelocity(deltaX);
|
var deltaX = endX - (menuTouchStartX || 0);
|
||||||
|
var deltaY = endY - (menuTouchStartY || 0);
|
||||||
|
currentPos = deltaX;
|
||||||
|
self.checkMenuState(deltaX, deltaY);
|
||||||
|
}
|
||||||
|
|
||||||
if (isOpen && 1 !== dragMode && deltaX > 0) {
|
function onEdgeTouchStart(e) {
|
||||||
dragMode = 2;
|
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) {
|
if (e.type === 'touchstart') {
|
||||||
dragMode = 1;
|
dom.removeEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
|
||||||
scrollContainer.addEventListener("scroll", disableEvent);
|
dom.addEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMenuTouchStart(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onEdgeTouchMove(e) {
|
function onEdgeTouchMove(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onEdgeTouchStart(e);
|
onEdgeTouchStart(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEdgeTouchEnd(e) {
|
||||||
|
if (isPeeking) {
|
||||||
|
isPeeking = false;
|
||||||
|
dom.removeEventListener(edgeContainer, 'touchmove', onEdgeTouchMove, {});
|
||||||
|
onMenuTouchEnd(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onEdgeTouchEnd(e) {
|
function disableEvent(e) {
|
||||||
if (isPeeking) {
|
e.preventDefault();
|
||||||
isPeeking = false;
|
e.stopPropagation();
|
||||||
dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {});
|
}
|
||||||
onMenuTouchEnd(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function disableEvent(e) {
|
function onBackgroundTouchStart(e) {
|
||||||
e.preventDefault();
|
var touches = getTouches(e);
|
||||||
e.stopPropagation();
|
var touch = touches[0] || {};
|
||||||
}
|
backgroundTouchStartX = touch.clientX;
|
||||||
|
backgroundTouchStartTime = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
function onBackgroundTouchStart(e) {
|
function onBackgroundTouchMove(e) {
|
||||||
var touches = getTouches(e);
|
var touches = getTouches(e);
|
||||||
var touch = touches[0] || {};
|
var touch = touches[0] || {};
|
||||||
backgroundTouchStartX = touch.clientX;
|
var endX = touch.clientX || 0;
|
||||||
backgroundTouchStartTime = new Date().getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onBackgroundTouchMove(e) {
|
if (endX <= options.width && self.isVisible) {
|
||||||
var touches = getTouches(e);
|
countStart++;
|
||||||
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;
|
|
||||||
var deltaX = endX - (backgroundTouchStartX || 0);
|
var deltaX = endX - (backgroundTouchStartX || 0);
|
||||||
self.checkMenuState(deltaX);
|
|
||||||
countStart = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onMaskTransitionEnd() {
|
if (countStart == 1) {
|
||||||
var classList = mask.classList;
|
startPoint = deltaX;
|
||||||
|
}
|
||||||
if (!classList.contains("backdrop")) {
|
if (deltaX < 0 && dragMode !== 2) {
|
||||||
classList.add("hide");
|
dragMode = 1;
|
||||||
|
newPos = deltaX - startPoint + options.width;
|
||||||
|
self.changeMenuPos();
|
||||||
|
var time = new Date().getTime() - (backgroundTouchStartTime || 0);
|
||||||
|
velocity = Math.abs(deltaX) / time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var self;
|
e.preventDefault();
|
||||||
var defaults;
|
e.stopPropagation();
|
||||||
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 () {
|
function onBackgroundTouchEnd(e) {
|
||||||
self = this;
|
var touches = getTouches(e);
|
||||||
defaults = {
|
var touch = touches[0] || {};
|
||||||
width: 260,
|
var endX = touch.clientX || 0;
|
||||||
handleSize: 10,
|
var deltaX = endX - (backgroundTouchStartX || 0);
|
||||||
disableMask: false,
|
self.checkMenuState(deltaX);
|
||||||
maxMaskOpacity: 0.5
|
countStart = 0;
|
||||||
};
|
}
|
||||||
this.isVisible = false;
|
|
||||||
this.initialize();
|
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 () {
|
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
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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";
|
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
TouchMenuLA.prototype.changeMenuPos = function () {
|
var menuTouchStartX;
|
||||||
if (newPos <= options.width) {
|
var menuTouchStartY;
|
||||||
this.animateToPosition(newPos);
|
var menuTouchStartTime;
|
||||||
}
|
var edgeContainer = document.querySelector('.mainDrawerHandle');
|
||||||
};
|
var isPeeking = false;
|
||||||
|
|
||||||
TouchMenuLA.prototype.clickMaskClose = function () {
|
TouchMenuLA.prototype.animateToPosition = function (pos) {
|
||||||
mask.addEventListener("click", function () {
|
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();
|
self.close();
|
||||||
});
|
}
|
||||||
};
|
} else {
|
||||||
|
if (newPos >= 100) {
|
||||||
TouchMenuLA.prototype.checkMenuState = function (deltaX, deltaY) {
|
self.open();
|
||||||
if (velocity >= 0.4) {
|
} else {
|
||||||
if (deltaX >= 0 || Math.abs(deltaY || 0) >= 70) {
|
if (newPos) {
|
||||||
self.open();
|
|
||||||
} else {
|
|
||||||
self.close();
|
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();
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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,17 +1195,28 @@ 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) {
|
||||||
// show in ui
|
import('userSettings').then((userSettings) => {
|
||||||
console.debug(`downloaded ${data.TrackEvents.length} track events`);
|
// show in ui
|
||||||
// add some cues to show the text
|
console.debug(`downloaded ${data.TrackEvents.length} track events`);
|
||||||
// in safari, the cues need to be added before setting the track mode to showing
|
|
||||||
for (const trackEvent of data.TrackEvents) {
|
|
||||||
const trackCueObject = window.VTTCue || window.TextTrackCue;
|
|
||||||
const cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false));
|
|
||||||
|
|
||||||
trackElement.addCue(cue);
|
const subtitleAppearance = userSettings.getSubtitleAppearanceSettings();
|
||||||
}
|
const cueLine = parseInt(subtitleAppearance.verticalPosition, 10);
|
||||||
trackElement.mode = 'showing';
|
|
||||||
|
// add some cues to show the text
|
||||||
|
// in safari, the cues need to be added before setting the track mode to showing
|
||||||
|
for (const trackEvent of data.TrackEvents) {
|
||||||
|
const trackCueObject = window.VTTCue || window.TextTrackCue;
|
||||||
|
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.mode = 'showing';
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -1,137 +1,138 @@
|
||||||
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) {
|
||||||
|
// 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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getBoundingClientRect(elem) {
|
export function getPosition(scrollContainer, item, horizontal) {
|
||||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
const slideeOffset = getBoundingClientRect(scrollContainer);
|
||||||
// If we don't have gBCR, just use 0,0 rather than error
|
const itemOffset = getBoundingClientRect(item);
|
||||||
if (elem.getBoundingClientRect) {
|
|
||||||
return elem.getBoundingClientRect();
|
let offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
|
||||||
} else {
|
let size = horizontal ? itemOffset.width : itemOffset.height;
|
||||||
return { top: 0, left: 0 };
|
if (!size && size !== 0) {
|
||||||
}
|
size = item[horizontal ? 'offsetWidth' : 'offsetHeight'];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPosition(scrollContainer, item, horizontal) {
|
const currentStart = horizontal ? scrollContainer.scrollLeft : scrollContainer.scrollTop;
|
||||||
var slideeOffset = getBoundingClientRect(scrollContainer);
|
|
||||||
var itemOffset = getBoundingClientRect(item);
|
|
||||||
|
|
||||||
var offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
|
offset += currentStart;
|
||||||
var size = horizontal ? itemOffset.width : itemOffset.height;
|
|
||||||
if (!size && size !== 0) {
|
|
||||||
size = item[horizontal ? 'offsetWidth' : 'offsetHeight'];
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentStart = horizontal ? scrollContainer.scrollLeft : scrollContainer.scrollTop;
|
const frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight;
|
||||||
|
|
||||||
offset += currentStart;
|
const currentEnd = currentStart + frameSize;
|
||||||
|
|
||||||
var frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight;
|
const isVisible = offset >= currentStart && (offset + size) <= currentEnd;
|
||||||
|
|
||||||
var currentEnd = currentStart + frameSize;
|
|
||||||
|
|
||||||
var isVisible = offset >= currentStart && (offset + size) <= currentEnd;
|
|
||||||
|
|
||||||
return {
|
|
||||||
start: offset,
|
|
||||||
center: (offset - (frameSize / 2) + (size / 2)),
|
|
||||||
end: offset - frameSize + size,
|
|
||||||
size: size,
|
|
||||||
isVisible: isVisible
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function toCenter(container, elem, horizontal, skipWhenVisible) {
|
|
||||||
var pos = getPosition(container, elem, horizontal);
|
|
||||||
|
|
||||||
if (skipWhenVisible && pos.isVisible) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (container.scrollTo) {
|
|
||||||
if (horizontal) {
|
|
||||||
container.scrollTo(pos.center, 0);
|
|
||||||
} else {
|
|
||||||
container.scrollTo(0, pos.center);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (horizontal) {
|
|
||||||
container.scrollLeft = Math.round(pos.center);
|
|
||||||
} else {
|
|
||||||
container.scrollTop = Math.round(pos.center);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toStart(container, elem, horizontal, skipWhenVisible) {
|
|
||||||
var pos = getPosition(container, elem, horizontal);
|
|
||||||
|
|
||||||
if (skipWhenVisible && pos.isVisible) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (container.scrollTo) {
|
|
||||||
if (horizontal) {
|
|
||||||
container.scrollTo(pos.start, 0);
|
|
||||||
} else {
|
|
||||||
container.scrollTo(0, pos.start);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (horizontal) {
|
|
||||||
container.scrollLeft = Math.round(pos.start);
|
|
||||||
} else {
|
|
||||||
container.scrollTop = Math.round(pos.start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function centerOnFocus(e, scrollSlider, horizontal) {
|
|
||||||
var focused = focusManager.focusableParent(e.target);
|
|
||||||
|
|
||||||
if (focused) {
|
|
||||||
toCenter(scrollSlider, focused, horizontal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function centerOnFocusHorizontal(e) {
|
|
||||||
centerOnFocus(e, this, true);
|
|
||||||
}
|
|
||||||
function centerOnFocusVertical(e) {
|
|
||||||
centerOnFocus(e, this, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getPosition: getPosition,
|
start: offset,
|
||||||
centerFocus: {
|
center: (offset - (frameSize / 2) + (size / 2)),
|
||||||
on: function (element, horizontal) {
|
end: offset - frameSize + size,
|
||||||
if (horizontal) {
|
size: size,
|
||||||
dom.addEventListener(element, 'focus', centerOnFocusHorizontal, {
|
isVisible: isVisible
|
||||||
capture: true,
|
|
||||||
passive: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
dom.addEventListener(element, 'focus', centerOnFocusVertical, {
|
|
||||||
capture: true,
|
|
||||||
passive: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
off: function (element, horizontal) {
|
|
||||||
if (horizontal) {
|
|
||||||
dom.removeEventListener(element, 'focus', centerOnFocusHorizontal, {
|
|
||||||
capture: true,
|
|
||||||
passive: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
dom.removeEventListener(element, 'focus', centerOnFocusVertical, {
|
|
||||||
capture: true,
|
|
||||||
passive: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toCenter: toCenter,
|
|
||||||
toStart: toStart
|
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export function toCenter(container, elem, horizontal, skipWhenVisible) {
|
||||||
|
const pos = getPosition(container, elem, horizontal);
|
||||||
|
|
||||||
|
if (skipWhenVisible && pos.isVisible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container.scrollTo) {
|
||||||
|
if (horizontal) {
|
||||||
|
container.scrollTo(pos.center, 0);
|
||||||
|
} else {
|
||||||
|
container.scrollTo(0, pos.center);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (horizontal) {
|
||||||
|
container.scrollLeft = Math.round(pos.center);
|
||||||
|
} else {
|
||||||
|
container.scrollTop = Math.round(pos.center);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toStart(container, elem, horizontal, skipWhenVisible) {
|
||||||
|
const pos = getPosition(container, elem, horizontal);
|
||||||
|
|
||||||
|
if (skipWhenVisible && pos.isVisible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container.scrollTo) {
|
||||||
|
if (horizontal) {
|
||||||
|
container.scrollTo(pos.start, 0);
|
||||||
|
} else {
|
||||||
|
container.scrollTo(0, pos.start);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (horizontal) {
|
||||||
|
container.scrollLeft = Math.round(pos.start);
|
||||||
|
} else {
|
||||||
|
container.scrollTop = Math.round(pos.start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function centerOnFocus(e, scrollSlider, horizontal) {
|
||||||
|
const focused = focusManager.focusableParent(e.target);
|
||||||
|
|
||||||
|
if (focused) {
|
||||||
|
toCenter(scrollSlider, focused, horizontal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function centerOnFocusHorizontal(e) {
|
||||||
|
centerOnFocus(e, this, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function centerOnFocusVertical(e) {
|
||||||
|
centerOnFocus(e, this, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const centerFocus = {
|
||||||
|
on: function (element, horizontal) {
|
||||||
|
if (horizontal) {
|
||||||
|
dom.addEventListener(element, 'focus', centerOnFocusHorizontal, {
|
||||||
|
capture: true,
|
||||||
|
passive: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dom.addEventListener(element, 'focus', centerOnFocusVertical, {
|
||||||
|
capture: true,
|
||||||
|
passive: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
off: function (element, horizontal) {
|
||||||
|
if (horizontal) {
|
||||||
|
dom.removeEventListener(element, 'focus', centerOnFocusHorizontal, {
|
||||||
|
capture: true,
|
||||||
|
passive: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dom.removeEventListener(element, 'focus', centerOnFocusVertical, {
|
||||||
|
capture: true,
|
||||||
|
passive: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getPosition: getPosition,
|
||||||
|
centerFocus: centerFocus,
|
||||||
|
toCenter: toCenter,
|
||||||
|
toStart: toStart
|
||||||
|
};
|
||||||
|
|
|
@ -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;
|
|
||||||
});
|
|
|
@ -1,214 +1,216 @@
|
||||||
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() {
|
||||||
|
inputManager.notify();
|
||||||
|
}
|
||||||
|
|
||||||
function notifyApp() {
|
function displayMessage(cmd) {
|
||||||
inputManager.notify();
|
const args = cmd.Arguments;
|
||||||
}
|
if (args.TimeoutMs) {
|
||||||
|
import('toast').then(({default: toast}) => {
|
||||||
function displayMessage(cmd) {
|
toast({ title: args.Header, text: args.Text });
|
||||||
var args = cmd.Arguments;
|
});
|
||||||
if (args.TimeoutMs) {
|
} else {
|
||||||
require(['toast'], function (toast) {
|
import('alert').then(({default: alert}) => {
|
||||||
toast({ title: args.Header, text: args.Text });
|
alert({ title: args.Header, text: args.Text });
|
||||||
});
|
|
||||||
} else {
|
|
||||||
require(['alert'], function (alert) {
|
|
||||||
alert.default({ title: args.Header, text: args.Text });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayContent(cmd, apiClient) {
|
|
||||||
if (!playbackManager.isPlayingLocally(['Video', 'Book'])) {
|
|
||||||
appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function playTrailers(apiClient, itemId) {
|
|
||||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
|
||||||
playbackManager.playTrailers(item);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function processGeneralCommand(cmd, apiClient) {
|
function displayContent(cmd, apiClient) {
|
||||||
console.debug('Received command: ' + cmd.Name);
|
if (!playbackManager.isPlayingLocally(['Video', 'Book'])) {
|
||||||
switch (cmd.Name) {
|
appRouter.showItem(cmd.Arguments.ItemId, apiClient.serverId());
|
||||||
case 'Select':
|
|
||||||
inputManager.handleCommand('select');
|
|
||||||
return;
|
|
||||||
case 'Back':
|
|
||||||
inputManager.handleCommand('back');
|
|
||||||
return;
|
|
||||||
case 'MoveUp':
|
|
||||||
inputManager.handleCommand('up');
|
|
||||||
return;
|
|
||||||
case 'MoveDown':
|
|
||||||
inputManager.handleCommand('down');
|
|
||||||
return;
|
|
||||||
case 'MoveLeft':
|
|
||||||
inputManager.handleCommand('left');
|
|
||||||
return;
|
|
||||||
case 'MoveRight':
|
|
||||||
inputManager.handleCommand('right');
|
|
||||||
return;
|
|
||||||
case 'PageUp':
|
|
||||||
inputManager.handleCommand('pageup');
|
|
||||||
return;
|
|
||||||
case 'PageDown':
|
|
||||||
inputManager.handleCommand('pagedown');
|
|
||||||
return;
|
|
||||||
case 'PlayTrailers':
|
|
||||||
playTrailers(apiClient, cmd.Arguments.ItemId);
|
|
||||||
break;
|
|
||||||
case 'SetRepeatMode':
|
|
||||||
playbackManager.setRepeatMode(cmd.Arguments.RepeatMode);
|
|
||||||
break;
|
|
||||||
case 'SetShuffleQueue':
|
|
||||||
playbackManager.setQueueShuffleMode(cmd.Arguments.ShuffleMode);
|
|
||||||
break;
|
|
||||||
case 'VolumeUp':
|
|
||||||
inputManager.handleCommand('volumeup');
|
|
||||||
return;
|
|
||||||
case 'VolumeDown':
|
|
||||||
inputManager.handleCommand('volumedown');
|
|
||||||
return;
|
|
||||||
case 'ChannelUp':
|
|
||||||
inputManager.handleCommand('channelup');
|
|
||||||
return;
|
|
||||||
case 'ChannelDown':
|
|
||||||
inputManager.handleCommand('channeldown');
|
|
||||||
return;
|
|
||||||
case 'Mute':
|
|
||||||
inputManager.handleCommand('mute');
|
|
||||||
return;
|
|
||||||
case 'Unmute':
|
|
||||||
inputManager.handleCommand('unmute');
|
|
||||||
return;
|
|
||||||
case 'ToggleMute':
|
|
||||||
inputManager.handleCommand('togglemute');
|
|
||||||
return;
|
|
||||||
case 'SetVolume':
|
|
||||||
notifyApp();
|
|
||||||
playbackManager.setVolume(cmd.Arguments.Volume);
|
|
||||||
break;
|
|
||||||
case 'SetAudioStreamIndex':
|
|
||||||
notifyApp();
|
|
||||||
playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index));
|
|
||||||
break;
|
|
||||||
case 'SetSubtitleStreamIndex':
|
|
||||||
notifyApp();
|
|
||||||
playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index));
|
|
||||||
break;
|
|
||||||
case 'ToggleFullscreen':
|
|
||||||
inputManager.handleCommand('togglefullscreen');
|
|
||||||
return;
|
|
||||||
case 'GoHome':
|
|
||||||
inputManager.handleCommand('home');
|
|
||||||
return;
|
|
||||||
case 'GoToSettings':
|
|
||||||
inputManager.handleCommand('settings');
|
|
||||||
return;
|
|
||||||
case 'DisplayContent':
|
|
||||||
displayContent(cmd, apiClient);
|
|
||||||
break;
|
|
||||||
case 'GoToSearch':
|
|
||||||
inputManager.handleCommand('search');
|
|
||||||
return;
|
|
||||||
case 'DisplayMessage':
|
|
||||||
displayMessage(cmd);
|
|
||||||
break;
|
|
||||||
case 'ToggleOsd':
|
|
||||||
// todo
|
|
||||||
break;
|
|
||||||
case 'ToggleContextMenu':
|
|
||||||
// todo
|
|
||||||
break;
|
|
||||||
case 'TakeScreenShot':
|
|
||||||
// todo
|
|
||||||
break;
|
|
||||||
case 'SendKey':
|
|
||||||
// todo
|
|
||||||
break;
|
|
||||||
case 'SendString':
|
|
||||||
// todo
|
|
||||||
focusManager.sendText(cmd.Arguments.String);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.debug('processGeneralCommand does not recognize: ' + cmd.Name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyApp();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onMessageReceived(e, msg) {
|
function playTrailers(apiClient, itemId) {
|
||||||
var apiClient = this;
|
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||||
if (msg.MessageType === 'Play') {
|
playbackManager.playTrailers(item);
|
||||||
notifyApp();
|
|
||||||
var serverId = apiClient.serverInfo().Id;
|
|
||||||
if (msg.Data.PlayCommand === 'PlayNext') {
|
|
||||||
playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId });
|
|
||||||
} else if (msg.Data.PlayCommand === 'PlayLast') {
|
|
||||||
playbackManager.queue({ ids: msg.Data.ItemIds, serverId: serverId });
|
|
||||||
} else {
|
|
||||||
playbackManager.play({
|
|
||||||
ids: msg.Data.ItemIds,
|
|
||||||
startPositionTicks: msg.Data.StartPositionTicks,
|
|
||||||
mediaSourceId: msg.Data.MediaSourceId,
|
|
||||||
audioStreamIndex: msg.Data.AudioStreamIndex,
|
|
||||||
subtitleStreamIndex: msg.Data.SubtitleStreamIndex,
|
|
||||||
startIndex: msg.Data.StartIndex,
|
|
||||||
serverId: serverId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (msg.MessageType === 'Playstate') {
|
|
||||||
if (msg.Data.Command === 'Stop') {
|
|
||||||
inputManager.handleCommand('stop');
|
|
||||||
} else if (msg.Data.Command === 'Pause') {
|
|
||||||
inputManager.handleCommand('pause');
|
|
||||||
} else if (msg.Data.Command === 'Unpause') {
|
|
||||||
inputManager.handleCommand('play');
|
|
||||||
} else if (msg.Data.Command === 'PlayPause') {
|
|
||||||
inputManager.handleCommand('playpause');
|
|
||||||
} else if (msg.Data.Command === 'Seek') {
|
|
||||||
playbackManager.seek(msg.Data.SeekPositionTicks);
|
|
||||||
} else if (msg.Data.Command === 'NextTrack') {
|
|
||||||
inputManager.handleCommand('next');
|
|
||||||
} else if (msg.Data.Command === 'PreviousTrack') {
|
|
||||||
inputManager.handleCommand('previous');
|
|
||||||
} else {
|
|
||||||
notifyApp();
|
|
||||||
}
|
|
||||||
} else if (msg.MessageType === 'GeneralCommand') {
|
|
||||||
var cmd = msg.Data;
|
|
||||||
processGeneralCommand(cmd, apiClient);
|
|
||||||
} else if (msg.MessageType === 'UserDataChanged') {
|
|
||||||
if (msg.Data.UserId === apiClient.getCurrentUserId()) {
|
|
||||||
for (var i = 0, length = msg.Data.UserDataList.length; i < length; i++) {
|
|
||||||
events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (msg.MessageType === 'SyncPlayCommand') {
|
|
||||||
syncPlayManager.processCommand(msg.Data, apiClient);
|
|
||||||
} else if (msg.MessageType === 'SyncPlayGroupUpdate') {
|
|
||||||
syncPlayManager.processGroupUpdate(msg.Data, apiClient);
|
|
||||||
} else {
|
|
||||||
events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function bindEvents(apiClient) {
|
|
||||||
events.off(apiClient, 'message', onMessageReceived);
|
|
||||||
events.on(apiClient, 'message', onMessageReceived);
|
|
||||||
}
|
|
||||||
|
|
||||||
connectionManager.getApiClients().forEach(bindEvents);
|
|
||||||
events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {
|
|
||||||
bindEvents(newApiClient);
|
|
||||||
});
|
});
|
||||||
return serverNotifications;
|
}
|
||||||
|
|
||||||
|
function processGeneralCommand(cmd, apiClient) {
|
||||||
|
console.debug('Received command: ' + cmd.Name);
|
||||||
|
switch (cmd.Name) {
|
||||||
|
case 'Select':
|
||||||
|
inputManager.handleCommand('select');
|
||||||
|
return;
|
||||||
|
case 'Back':
|
||||||
|
inputManager.handleCommand('back');
|
||||||
|
return;
|
||||||
|
case 'MoveUp':
|
||||||
|
inputManager.handleCommand('up');
|
||||||
|
return;
|
||||||
|
case 'MoveDown':
|
||||||
|
inputManager.handleCommand('down');
|
||||||
|
return;
|
||||||
|
case 'MoveLeft':
|
||||||
|
inputManager.handleCommand('left');
|
||||||
|
return;
|
||||||
|
case 'MoveRight':
|
||||||
|
inputManager.handleCommand('right');
|
||||||
|
return;
|
||||||
|
case 'PageUp':
|
||||||
|
inputManager.handleCommand('pageup');
|
||||||
|
return;
|
||||||
|
case 'PageDown':
|
||||||
|
inputManager.handleCommand('pagedown');
|
||||||
|
return;
|
||||||
|
case 'PlayTrailers':
|
||||||
|
playTrailers(apiClient, cmd.Arguments.ItemId);
|
||||||
|
break;
|
||||||
|
case 'SetRepeatMode':
|
||||||
|
playbackManager.setRepeatMode(cmd.Arguments.RepeatMode);
|
||||||
|
break;
|
||||||
|
case 'SetShuffleQueue':
|
||||||
|
playbackManager.setQueueShuffleMode(cmd.Arguments.ShuffleMode);
|
||||||
|
break;
|
||||||
|
case 'VolumeUp':
|
||||||
|
inputManager.handleCommand('volumeup');
|
||||||
|
return;
|
||||||
|
case 'VolumeDown':
|
||||||
|
inputManager.handleCommand('volumedown');
|
||||||
|
return;
|
||||||
|
case 'ChannelUp':
|
||||||
|
inputManager.handleCommand('channelup');
|
||||||
|
return;
|
||||||
|
case 'ChannelDown':
|
||||||
|
inputManager.handleCommand('channeldown');
|
||||||
|
return;
|
||||||
|
case 'Mute':
|
||||||
|
inputManager.handleCommand('mute');
|
||||||
|
return;
|
||||||
|
case 'Unmute':
|
||||||
|
inputManager.handleCommand('unmute');
|
||||||
|
return;
|
||||||
|
case 'ToggleMute':
|
||||||
|
inputManager.handleCommand('togglemute');
|
||||||
|
return;
|
||||||
|
case 'SetVolume':
|
||||||
|
notifyApp();
|
||||||
|
playbackManager.setVolume(cmd.Arguments.Volume);
|
||||||
|
break;
|
||||||
|
case 'SetAudioStreamIndex':
|
||||||
|
notifyApp();
|
||||||
|
playbackManager.setAudioStreamIndex(parseInt(cmd.Arguments.Index));
|
||||||
|
break;
|
||||||
|
case 'SetSubtitleStreamIndex':
|
||||||
|
notifyApp();
|
||||||
|
playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index));
|
||||||
|
break;
|
||||||
|
case 'ToggleFullscreen':
|
||||||
|
inputManager.handleCommand('togglefullscreen');
|
||||||
|
return;
|
||||||
|
case 'GoHome':
|
||||||
|
inputManager.handleCommand('home');
|
||||||
|
return;
|
||||||
|
case 'GoToSettings':
|
||||||
|
inputManager.handleCommand('settings');
|
||||||
|
return;
|
||||||
|
case 'DisplayContent':
|
||||||
|
displayContent(cmd, apiClient);
|
||||||
|
break;
|
||||||
|
case 'GoToSearch':
|
||||||
|
inputManager.handleCommand('search');
|
||||||
|
return;
|
||||||
|
case 'DisplayMessage':
|
||||||
|
displayMessage(cmd);
|
||||||
|
break;
|
||||||
|
case 'ToggleOsd':
|
||||||
|
// todo
|
||||||
|
break;
|
||||||
|
case 'ToggleContextMenu':
|
||||||
|
// todo
|
||||||
|
break;
|
||||||
|
case 'TakeScreenShot':
|
||||||
|
// todo
|
||||||
|
break;
|
||||||
|
case 'SendKey':
|
||||||
|
// todo
|
||||||
|
break;
|
||||||
|
case 'SendString':
|
||||||
|
// todo
|
||||||
|
focusManager.sendText(cmd.Arguments.String);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.debug('processGeneralCommand does not recognize: ' + cmd.Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMessageReceived(e, msg) {
|
||||||
|
const apiClient = this;
|
||||||
|
if (msg.MessageType === 'Play') {
|
||||||
|
notifyApp();
|
||||||
|
const serverId = apiClient.serverInfo().Id;
|
||||||
|
if (msg.Data.PlayCommand === 'PlayNext') {
|
||||||
|
playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId });
|
||||||
|
} else if (msg.Data.PlayCommand === 'PlayLast') {
|
||||||
|
playbackManager.queue({ ids: msg.Data.ItemIds, serverId: serverId });
|
||||||
|
} else {
|
||||||
|
playbackManager.play({
|
||||||
|
ids: msg.Data.ItemIds,
|
||||||
|
startPositionTicks: msg.Data.StartPositionTicks,
|
||||||
|
mediaSourceId: msg.Data.MediaSourceId,
|
||||||
|
audioStreamIndex: msg.Data.AudioStreamIndex,
|
||||||
|
subtitleStreamIndex: msg.Data.SubtitleStreamIndex,
|
||||||
|
startIndex: msg.Data.StartIndex,
|
||||||
|
serverId: serverId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (msg.MessageType === 'Playstate') {
|
||||||
|
if (msg.Data.Command === 'Stop') {
|
||||||
|
inputManager.handleCommand('stop');
|
||||||
|
} else if (msg.Data.Command === 'Pause') {
|
||||||
|
inputManager.handleCommand('pause');
|
||||||
|
} else if (msg.Data.Command === 'Unpause') {
|
||||||
|
inputManager.handleCommand('play');
|
||||||
|
} else if (msg.Data.Command === 'PlayPause') {
|
||||||
|
inputManager.handleCommand('playpause');
|
||||||
|
} else if (msg.Data.Command === 'Seek') {
|
||||||
|
playbackManager.seek(msg.Data.SeekPositionTicks);
|
||||||
|
} else if (msg.Data.Command === 'NextTrack') {
|
||||||
|
inputManager.handleCommand('next');
|
||||||
|
} else if (msg.Data.Command === 'PreviousTrack') {
|
||||||
|
inputManager.handleCommand('previous');
|
||||||
|
} else {
|
||||||
|
notifyApp();
|
||||||
|
}
|
||||||
|
} else if (msg.MessageType === 'GeneralCommand') {
|
||||||
|
const cmd = msg.Data;
|
||||||
|
processGeneralCommand(cmd, apiClient);
|
||||||
|
} else if (msg.MessageType === 'UserDataChanged') {
|
||||||
|
if (msg.Data.UserId === apiClient.getCurrentUserId()) {
|
||||||
|
for (let i = 0, length = msg.Data.UserDataList.length; i < length; i++) {
|
||||||
|
events.trigger(serverNotifications, 'UserDataChanged', [apiClient, msg.Data.UserDataList[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (msg.MessageType === 'SyncPlayCommand') {
|
||||||
|
syncPlayManager.processCommand(msg.Data, apiClient);
|
||||||
|
} else if (msg.MessageType === 'SyncPlayGroupUpdate') {
|
||||||
|
syncPlayManager.processGroupUpdate(msg.Data, apiClient);
|
||||||
|
} else {
|
||||||
|
events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function bindEvents(apiClient) {
|
||||||
|
events.off(apiClient, 'message', onMessageReceived);
|
||||||
|
events.on(apiClient, 'message', onMessageReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionManager.getApiClients().forEach(bindEvents);
|
||||||
|
events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {
|
||||||
|
bindEvents(newApiClient);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default serverNotifications;
|
||||||
|
|
|
@ -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) || '{}'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
define([], function () {
|
// TODO: This seems like a good candidate for deprecation
|
||||||
'use strict';
|
export default {
|
||||||
|
openUrl: function (url, target) {
|
||||||
return {
|
if (window.NativeShell) {
|
||||||
openUrl: function (url, target) {
|
window.NativeShell.openUrl(url, target);
|
||||||
if (window.NativeShell) {
|
} else {
|
||||||
window.NativeShell.openUrl(url, target);
|
window.open(url, target || '_blank');
|
||||||
} else {
|
|
||||||
window.open(url, target || '_blank');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
enableFullscreen: function () {
|
|
||||||
if (window.NativeShell) {
|
|
||||||
window.NativeShell.enableFullscreen();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
disableFullscreen: function () {
|
|
||||||
if (window.NativeShell) {
|
|
||||||
window.NativeShell.disableFullscreen();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
});
|
enableFullscreen: function () {
|
||||||
|
if (window.NativeShell) {
|
||||||
|
window.NativeShell.enableFullscreen();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disableFullscreen: function () {
|
||||||
|
if (window.NativeShell) {
|
||||||
|
window.NativeShell.disableFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1542,5 +1542,8 @@
|
||||||
"ButtonPlayer": "Проигрыватель",
|
"ButtonPlayer": "Проигрыватель",
|
||||||
"PreviousTrack": "Перейти к предыдущему",
|
"PreviousTrack": "Перейти к предыдущему",
|
||||||
"NextTrack": "Перейти к следующему",
|
"NextTrack": "Перейти к следующему",
|
||||||
"LabelUnstable": "Нестабильная"
|
"LabelUnstable": "Нестабильная",
|
||||||
|
"LabelSubtitleVerticalPosition": "Вертикальная позиция:",
|
||||||
|
"SubtitleVerticalPositionHelp": "Номер строки, где появляется текст. Положительные числа означают сверху вниз. Отрицательные числа означают снизу вверх.",
|
||||||
|
"Preview": "Предварительный просмотр"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue