mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'master' into migrate-to-ES6-57
This commit is contained in:
commit
d6761eb8e5
55 changed files with 3113 additions and 2934 deletions
|
@ -2,4 +2,3 @@ node_modules
|
||||||
dist
|
dist
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
src/libraries
|
|
||||||
|
|
17
package.json
17
package.json
|
@ -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",
|
||||||
|
@ -155,6 +155,8 @@
|
||||||
"src/components/playlisteditor/playlisteditor.js",
|
"src/components/playlisteditor/playlisteditor.js",
|
||||||
"src/components/playmenu.js",
|
"src/components/playmenu.js",
|
||||||
"src/components/prompt/prompt.js",
|
"src/components/prompt/prompt.js",
|
||||||
|
"src/components/recordingcreator/seriesrecordingeditor.js",
|
||||||
|
"src/components/recordingcreator/recordinghelper.js",
|
||||||
"src/components/refreshdialog/refreshdialog.js",
|
"src/components/refreshdialog/refreshdialog.js",
|
||||||
"src/components/sanatizefilename.js",
|
"src/components/sanatizefilename.js",
|
||||||
"src/components/scrollManager.js",
|
"src/components/scrollManager.js",
|
||||||
|
@ -169,6 +171,9 @@
|
||||||
"src/components/syncPlay/playbackPermissionManager.js",
|
"src/components/syncPlay/playbackPermissionManager.js",
|
||||||
"src/components/syncPlay/syncPlayManager.js",
|
"src/components/syncPlay/syncPlayManager.js",
|
||||||
"src/components/syncPlay/timeSyncManager.js",
|
"src/components/syncPlay/timeSyncManager.js",
|
||||||
|
"src/components/viewManager/viewManager.js",
|
||||||
|
"src/components/tvproviders/schedulesdirect.js",
|
||||||
|
"src/components/tvproviders/xmltv.js",
|
||||||
"src/components/toast/toast.js",
|
"src/components/toast/toast.js",
|
||||||
"src/components/upnextdialog/upnextdialog.js",
|
"src/components/upnextdialog/upnextdialog.js",
|
||||||
"src/components/viewContainer.js",
|
"src/components/viewContainer.js",
|
||||||
|
@ -216,6 +221,11 @@
|
||||||
"src/controllers/edititemmetadata.js",
|
"src/controllers/edititemmetadata.js",
|
||||||
"src/controllers/favorites.js",
|
"src/controllers/favorites.js",
|
||||||
"src/controllers/hometab.js",
|
"src/controllers/hometab.js",
|
||||||
|
"src/controllers/movies/moviecollections.js",
|
||||||
|
"src/controllers/movies/moviegenres.js",
|
||||||
|
"src/controllers/movies/movies.js",
|
||||||
|
"src/controllers/movies/moviesrecommended.js",
|
||||||
|
"src/controllers/movies/movietrailers.js",
|
||||||
"src/controllers/playback/nowplaying.js",
|
"src/controllers/playback/nowplaying.js",
|
||||||
"src/controllers/playback/videoosd.js",
|
"src/controllers/playback/videoosd.js",
|
||||||
"src/controllers/itemDetails/index.js",
|
"src/controllers/itemDetails/index.js",
|
||||||
|
@ -268,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",
|
||||||
|
@ -293,10 +305,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,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(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields'], function (globalize, connectionManager, require, loading, appHost, dom, recordingHelper, events) {
|
define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields'], function (globalize, connectionManager, require, loading, appHost, dom, recordingHelper, events) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
recordingHelper = recordingHelper.default || recordingHelper;
|
||||||
|
|
||||||
function onRecordingButtonClick(e) {
|
function onRecordingButtonClick(e) {
|
||||||
var item = this.item;
|
var item = this.item;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -12,6 +13,8 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
|
||||||
function deleteTimer(apiClient, timerId) {
|
function deleteTimer(apiClient, timerId) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
require(['recordingHelper'], function (recordingHelper) {
|
require(['recordingHelper'], function (recordingHelper) {
|
||||||
|
recordingHelper = recordingHelper.default || recordingHelper;
|
||||||
|
|
||||||
recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
|
recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
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;
|
||||||
loading = loading.default || loading;
|
loading = loading.default || loading;
|
||||||
|
|
||||||
function loadData(parent, program, apiClient) {
|
function loadData(parent, program, apiClient) {
|
||||||
|
|
|
@ -1,194 +1,195 @@
|
||||||
define(['globalize', 'loading', 'connectionManager'], function (globalize, loading, connectionManager) {
|
import globalize from 'globalize';
|
||||||
'use strict';
|
import loading from 'loading';
|
||||||
|
import connectionManager from 'connectionManager';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
/*eslint prefer-const: "error"*/
|
||||||
|
|
||||||
function changeRecordingToSeries(apiClient, timerId, programId, confirmTimerCancellation) {
|
function changeRecordingToSeries(apiClient, timerId, programId, confirmTimerCancellation) {
|
||||||
loading.show();
|
loading.show();
|
||||||
|
|
||||||
return apiClient.getItem(apiClient.getCurrentUserId(), programId).then(function (item) {
|
return apiClient.getItem(apiClient.getCurrentUserId(), programId).then(function (item) {
|
||||||
if (item.IsSeries) {
|
if (item.IsSeries) {
|
||||||
// create series
|
// create series
|
||||||
return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (timerDefaults) {
|
return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (timerDefaults) {
|
||||||
return apiClient.createLiveTvSeriesTimer(timerDefaults).then(function () {
|
return apiClient.createLiveTvSeriesTimer(timerDefaults).then(function () {
|
||||||
loading.hide();
|
loading.hide();
|
||||||
sendToast(globalize.translate('SeriesRecordingScheduled'));
|
sendToast(globalize.translate('SeriesRecordingScheduled'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// cancel
|
||||||
|
if (confirmTimerCancellation) {
|
||||||
|
return cancelTimerWithConfirmation(timerId, apiClient.serverId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return cancelTimer(apiClient.serverId(), timerId, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelTimerWithConfirmation(timerId, serverId) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
import('confirm').then(({ default: confirm }) => {
|
||||||
|
confirm.default({
|
||||||
|
|
||||||
|
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||||
|
primary: 'delete',
|
||||||
|
confirmText: globalize.translate('HeaderCancelRecording'),
|
||||||
|
cancelText: globalize.translate('HeaderKeepRecording')
|
||||||
|
|
||||||
|
}).then(function () {
|
||||||
|
loading.show();
|
||||||
|
|
||||||
|
const apiClient = connectionManager.getApiClient(serverId);
|
||||||
|
cancelTimer(apiClient, timerId, true).then(resolve, reject);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelSeriesTimerWithConfirmation(timerId, serverId) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
import('confirm').then(({ default: confirm }) => {
|
||||||
|
confirm.default({
|
||||||
|
|
||||||
|
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||||
|
primary: 'delete',
|
||||||
|
confirmText: globalize.translate('HeaderCancelSeries'),
|
||||||
|
cancelText: globalize.translate('HeaderKeepSeries')
|
||||||
|
|
||||||
|
}).then(function () {
|
||||||
|
loading.show();
|
||||||
|
|
||||||
|
const apiClient = connectionManager.getApiClient(serverId);
|
||||||
|
apiClient.cancelLiveTvSeriesTimer(timerId).then(function () {
|
||||||
|
import('toast').then(({default: toast}) => {
|
||||||
|
toast(globalize.translate('SeriesCancelled'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
loading.hide();
|
||||||
|
resolve();
|
||||||
|
}, reject);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelTimer(apiClient, timerId, hideLoading) {
|
||||||
|
loading.show();
|
||||||
|
return apiClient.cancelLiveTvTimer(timerId).then(function () {
|
||||||
|
if (hideLoading !== false) {
|
||||||
|
loading.hide();
|
||||||
|
sendToast(globalize.translate('RecordingCancelled'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRecording(apiClient, programId, isSeries) {
|
||||||
|
loading.show();
|
||||||
|
return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (item) {
|
||||||
|
const promise = isSeries ?
|
||||||
|
apiClient.createLiveTvSeriesTimer(item) :
|
||||||
|
apiClient.createLiveTvTimer(item);
|
||||||
|
|
||||||
|
return promise.then(function () {
|
||||||
|
loading.hide();
|
||||||
|
sendToast(globalize.translate('RecordingScheduled'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendToast(msg) {
|
||||||
|
import('toast').then(({ default: toast }) => {
|
||||||
|
toast(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
import('dialog').then(({ default: dialog }) => {
|
||||||
|
const items = [];
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
name: globalize.translate('HeaderKeepRecording'),
|
||||||
|
id: 'cancel',
|
||||||
|
type: 'submit'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (timerStatus === 'InProgress') {
|
||||||
|
items.push({
|
||||||
|
name: globalize.translate('HeaderStopRecording'),
|
||||||
|
id: 'canceltimer',
|
||||||
|
type: 'cancel'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// cancel
|
items.push({
|
||||||
if (confirmTimerCancellation) {
|
name: globalize.translate('HeaderCancelRecording'),
|
||||||
return cancelTimerWithConfirmation(timerId, apiClient.serverId());
|
id: 'canceltimer',
|
||||||
}
|
type: 'cancel'
|
||||||
|
});
|
||||||
return cancelTimer(apiClient.serverId(), timerId, true);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelTimerWithConfirmation(timerId, serverId) {
|
items.push({
|
||||||
return new Promise(function (resolve, reject) {
|
name: globalize.translate('HeaderCancelSeries'),
|
||||||
require(['confirm'], function (confirm) {
|
id: 'cancelseriestimer',
|
||||||
confirm.default({
|
type: 'cancel'
|
||||||
|
|
||||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
|
||||||
primary: 'delete',
|
|
||||||
confirmText: globalize.translate('HeaderCancelRecording'),
|
|
||||||
cancelText: globalize.translate('HeaderKeepRecording')
|
|
||||||
|
|
||||||
}).then(function () {
|
|
||||||
loading.show();
|
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(serverId);
|
|
||||||
cancelTimer(apiClient, timerId, true).then(resolve, reject);
|
|
||||||
}, reject);
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelSeriesTimerWithConfirmation(timerId, serverId) {
|
dialog({
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
require(['confirm'], function (confirm) {
|
|
||||||
confirm.default({
|
|
||||||
|
|
||||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
||||||
primary: 'delete',
|
buttons: items
|
||||||
confirmText: globalize.translate('HeaderCancelSeries'),
|
|
||||||
cancelText: globalize.translate('HeaderKeepSeries')
|
|
||||||
|
|
||||||
}).then(function () {
|
}).then(function (result) {
|
||||||
|
const apiClient = connectionManager.getApiClient(serverId);
|
||||||
|
|
||||||
|
if (result === 'canceltimer') {
|
||||||
loading.show();
|
loading.show();
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(serverId);
|
cancelTimer(apiClient, timerId, true).then(resolve, reject);
|
||||||
apiClient.cancelLiveTvSeriesTimer(timerId).then(function () {
|
} else if (result === 'cancelseriestimer') {
|
||||||
require(['toast'], function (toast) {
|
loading.show();
|
||||||
|
|
||||||
|
apiClient.cancelLiveTvSeriesTimer(seriesTimerId).then(function () {
|
||||||
|
import('toast').then(({ default: toast }) => {
|
||||||
toast(globalize.translate('SeriesCancelled'));
|
toast(globalize.translate('SeriesCancelled'));
|
||||||
});
|
});
|
||||||
|
|
||||||
loading.hide();
|
loading.hide();
|
||||||
resolve();
|
resolve();
|
||||||
}, reject);
|
}, reject);
|
||||||
}, reject);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelTimer(apiClient, timerId, hideLoading) {
|
|
||||||
loading.show();
|
|
||||||
return apiClient.cancelLiveTvTimer(timerId).then(function () {
|
|
||||||
if (hideLoading !== false) {
|
|
||||||
loading.hide();
|
|
||||||
sendToast(globalize.translate('RecordingCancelled'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRecording(apiClient, programId, isSeries) {
|
|
||||||
loading.show();
|
|
||||||
return apiClient.getNewLiveTvTimerDefaults({ programId: programId }).then(function (item) {
|
|
||||||
var promise = isSeries ?
|
|
||||||
apiClient.createLiveTvSeriesTimer(item) :
|
|
||||||
apiClient.createLiveTvTimer(item);
|
|
||||||
|
|
||||||
return promise.then(function () {
|
|
||||||
loading.hide();
|
|
||||||
sendToast(globalize.translate('RecordingScheduled'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendToast(msg) {
|
|
||||||
require(['toast'], function (toast) {
|
|
||||||
toast(msg);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
require(['dialog'], function (dialog) {
|
|
||||||
var items = [];
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
name: globalize.translate('HeaderKeepRecording'),
|
|
||||||
id: 'cancel',
|
|
||||||
type: 'submit'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (timerStatus === 'InProgress') {
|
|
||||||
items.push({
|
|
||||||
name: globalize.translate('HeaderStopRecording'),
|
|
||||||
id: 'canceltimer',
|
|
||||||
type: 'cancel'
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
items.push({
|
resolve();
|
||||||
name: globalize.translate('HeaderCancelRecording'),
|
|
||||||
id: 'canceltimer',
|
|
||||||
type: 'cancel'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}, reject);
|
||||||
items.push({
|
|
||||||
name: globalize.translate('HeaderCancelSeries'),
|
|
||||||
id: 'cancelseriestimer',
|
|
||||||
type: 'cancel'
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog({
|
|
||||||
|
|
||||||
text: globalize.translate('MessageConfirmRecordingCancellation'),
|
|
||||||
buttons: items
|
|
||||||
|
|
||||||
}).then(function (result) {
|
|
||||||
var apiClient = connectionManager.getApiClient(serverId);
|
|
||||||
|
|
||||||
if (result === 'canceltimer') {
|
|
||||||
loading.show();
|
|
||||||
|
|
||||||
cancelTimer(apiClient, timerId, true).then(resolve, reject);
|
|
||||||
} else if (result === 'cancelseriestimer') {
|
|
||||||
loading.show();
|
|
||||||
|
|
||||||
apiClient.cancelLiveTvSeriesTimer(seriesTimerId).then(function () {
|
|
||||||
require(['toast'], function (toast) {
|
|
||||||
toast(globalize.translate('SeriesCancelled'));
|
|
||||||
});
|
|
||||||
|
|
||||||
loading.hide();
|
|
||||||
resolve();
|
|
||||||
}, reject);
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}, reject);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId) {
|
function toggleRecording(serverId, programId, timerId, timerStatus, seriesTimerId) {
|
||||||
var apiClient = connectionManager.getApiClient(serverId);
|
const apiClient = connectionManager.getApiClient(serverId);
|
||||||
var hasTimer = timerId && timerStatus !== 'Cancelled';
|
const hasTimer = timerId && timerStatus !== 'Cancelled';
|
||||||
if (seriesTimerId && hasTimer) {
|
if (seriesTimerId && hasTimer) {
|
||||||
// cancel
|
// cancel
|
||||||
return showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId);
|
return showMultiCancellationPrompt(serverId, programId, timerId, timerStatus, seriesTimerId);
|
||||||
} else if (hasTimer && programId) {
|
} else if (hasTimer && programId) {
|
||||||
// change to series recording, if possible
|
// change to series recording, if possible
|
||||||
// otherwise cancel individual recording
|
// otherwise cancel individual recording
|
||||||
return changeRecordingToSeries(apiClient, timerId, programId, true);
|
return changeRecordingToSeries(apiClient, timerId, programId, true);
|
||||||
} else if (programId) {
|
} else if (programId) {
|
||||||
// schedule recording
|
// schedule recording
|
||||||
return createRecording(apiClient, programId);
|
return createRecording(apiClient, programId);
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
cancelTimer: cancelTimer,
|
||||||
|
createRecording: createRecording,
|
||||||
|
changeRecordingToSeries: changeRecordingToSeries,
|
||||||
|
toggleRecording: toggleRecording,
|
||||||
|
cancelTimerWithConfirmation: cancelTimerWithConfirmation,
|
||||||
|
cancelSeriesTimerWithConfirmation: cancelSeriesTimerWithConfirmation
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
cancelTimer: cancelTimer,
|
|
||||||
createRecording: createRecording,
|
|
||||||
changeRecordingToSeries: changeRecordingToSeries,
|
|
||||||
toggleRecording: toggleRecording,
|
|
||||||
cancelTimerWithConfirmation: cancelTimerWithConfirmation,
|
|
||||||
cancelSeriesTimerWithConfirmation: cancelSeriesTimerWithConfirmation
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,143 +1,200 @@
|
||||||
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'datetime', 'scrollStyles', 'emby-button', 'emby-checkbox', 'emby-input', 'emby-select', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader, datetime) {
|
import dialogHelper from 'dialogHelper';
|
||||||
'use strict';
|
import globalize from 'globalize';
|
||||||
|
import layoutManager from 'layoutManager';
|
||||||
|
import connectionManager from 'connectionManager';
|
||||||
|
import loading from 'loading';
|
||||||
|
import scrollHelper from 'scrollHelper';
|
||||||
|
import datetime from 'datetime';
|
||||||
|
import 'scrollStyles';
|
||||||
|
import 'emby-button';
|
||||||
|
import 'emby-checkbox';
|
||||||
|
import 'emby-input';
|
||||||
|
import 'emby-select';
|
||||||
|
import 'paper-icon-button-light';
|
||||||
|
import 'css!./../formdialog';
|
||||||
|
import 'css!./recordingcreator';
|
||||||
|
import 'material-icons';
|
||||||
|
import 'flexStyles';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
/*eslint prefer-const: "error"*/
|
||||||
|
|
||||||
var currentDialog;
|
let currentDialog;
|
||||||
var recordingUpdated = false;
|
let recordingUpdated = false;
|
||||||
var recordingDeleted = false;
|
let recordingDeleted = false;
|
||||||
var currentItemId;
|
let currentItemId;
|
||||||
var currentServerId;
|
let currentServerId;
|
||||||
|
|
||||||
function deleteTimer(apiClient, timerId) {
|
function deleteTimer(apiClient, timerId) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
require(['recordingHelper'], function (recordingHelper) {
|
import('recordingHelper').then(({ default: recordingHelper }) => {
|
||||||
recordingHelper.cancelSeriesTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
|
recordingHelper.cancelSeriesTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTimer(context, item) {
|
||||||
|
context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60;
|
||||||
|
context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60;
|
||||||
|
|
||||||
|
context.querySelector('.selectChannels').value = item.RecordAnyChannel ? 'all' : 'one';
|
||||||
|
context.querySelector('.selectAirTime').value = item.RecordAnyTime ? 'any' : 'original';
|
||||||
|
|
||||||
|
context.querySelector('.selectShowType').value = item.RecordNewOnly ? 'new' : 'all';
|
||||||
|
context.querySelector('.chkSkipEpisodesInLibrary').checked = item.SkipEpisodesInLibrary;
|
||||||
|
context.querySelector('.selectKeepUpTo').value = item.KeepUpTo || 0;
|
||||||
|
|
||||||
|
if (item.ChannelName || item.ChannelNumber) {
|
||||||
|
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('ChannelNameOnly', item.ChannelName || item.ChannelNumber);
|
||||||
|
} else {
|
||||||
|
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('OneChannel');
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTimer(context, item, apiClient) {
|
context.querySelector('.optionAroundTime').innerHTML = globalize.translate('AroundTime', datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate)));
|
||||||
context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60;
|
|
||||||
context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60;
|
|
||||||
|
|
||||||
context.querySelector('.selectChannels').value = item.RecordAnyChannel ? 'all' : 'one';
|
loading.hide();
|
||||||
context.querySelector('.selectAirTime').value = item.RecordAnyTime ? 'any' : 'original';
|
}
|
||||||
|
|
||||||
context.querySelector('.selectShowType').value = item.RecordNewOnly ? 'new' : 'all';
|
function closeDialog(isDeleted) {
|
||||||
context.querySelector('.chkSkipEpisodesInLibrary').checked = item.SkipEpisodesInLibrary;
|
recordingUpdated = true;
|
||||||
context.querySelector('.selectKeepUpTo').value = item.KeepUpTo || 0;
|
recordingDeleted = isDeleted;
|
||||||
|
|
||||||
if (item.ChannelName || item.ChannelNumber) {
|
dialogHelper.close(currentDialog);
|
||||||
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('ChannelNameOnly', item.ChannelName || item.ChannelNumber);
|
}
|
||||||
} else {
|
|
||||||
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('OneChannel');
|
|
||||||
}
|
|
||||||
|
|
||||||
context.querySelector('.optionAroundTime').innerHTML = globalize.translate('AroundTime', datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate)));
|
function onSubmit(e) {
|
||||||
|
const form = this;
|
||||||
|
|
||||||
|
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||||
|
|
||||||
|
apiClient.getLiveTvSeriesTimer(currentItemId).then(function (item) {
|
||||||
|
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
|
||||||
|
item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60;
|
||||||
|
item.RecordAnyChannel = form.querySelector('.selectChannels').value === 'all';
|
||||||
|
item.RecordAnyTime = form.querySelector('.selectAirTime').value === 'any';
|
||||||
|
item.RecordNewOnly = form.querySelector('.selectShowType').value === 'new';
|
||||||
|
item.SkipEpisodesInLibrary = form.querySelector('.chkSkipEpisodesInLibrary').checked;
|
||||||
|
item.KeepUpTo = form.querySelector('.selectKeepUpTo').value;
|
||||||
|
|
||||||
|
apiClient.updateLiveTvSeriesTimer(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Disable default form submission
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(context) {
|
||||||
|
fillKeepUpTo(context);
|
||||||
|
|
||||||
|
context.querySelector('.btnCancel').addEventListener('click', function () {
|
||||||
|
closeDialog(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
context.querySelector('.btnCancelRecording').addEventListener('click', function () {
|
||||||
|
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||||
|
deleteTimer(apiClient, currentItemId).then(function () {
|
||||||
|
closeDialog(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload(context, id) {
|
||||||
|
const apiClient = connectionManager.getApiClient(currentServerId);
|
||||||
|
|
||||||
|
loading.show();
|
||||||
|
if (typeof id === 'string') {
|
||||||
|
currentItemId = id;
|
||||||
|
|
||||||
|
apiClient.getLiveTvSeriesTimer(id).then(function (result) {
|
||||||
|
renderTimer(context, result);
|
||||||
|
loading.hide();
|
||||||
|
});
|
||||||
|
} else if (id) {
|
||||||
|
currentItemId = id.Id;
|
||||||
|
|
||||||
|
renderTimer(context, id);
|
||||||
loading.hide();
|
loading.hide();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function closeDialog(isDeleted) {
|
function fillKeepUpTo(context) {
|
||||||
recordingUpdated = true;
|
let html = '';
|
||||||
recordingDeleted = isDeleted;
|
|
||||||
|
|
||||||
dialogHelper.close(currentDialog);
|
for (let i = 0; i <= 50; i++) {
|
||||||
}
|
let text;
|
||||||
|
|
||||||
function onSubmit(e) {
|
if (i === 0) {
|
||||||
var form = this;
|
text = globalize.translate('AsManyAsPossible');
|
||||||
|
} else if (i === 1) {
|
||||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
text = globalize.translate('ValueOneEpisode');
|
||||||
|
} else {
|
||||||
apiClient.getLiveTvSeriesTimer(currentItemId).then(function (item) {
|
text = globalize.translate('ValueEpisodeCount', i);
|
||||||
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
|
|
||||||
item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60;
|
|
||||||
item.RecordAnyChannel = form.querySelector('.selectChannels').value === 'all';
|
|
||||||
item.RecordAnyTime = form.querySelector('.selectAirTime').value === 'any';
|
|
||||||
item.RecordNewOnly = form.querySelector('.selectShowType').value === 'new';
|
|
||||||
item.SkipEpisodesInLibrary = form.querySelector('.chkSkipEpisodesInLibrary').checked;
|
|
||||||
item.KeepUpTo = form.querySelector('.selectKeepUpTo').value;
|
|
||||||
|
|
||||||
apiClient.updateLiveTvSeriesTimer(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
// Disable default form submission
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function init(context) {
|
|
||||||
fillKeepUpTo(context);
|
|
||||||
|
|
||||||
context.querySelector('.btnCancel').addEventListener('click', function () {
|
|
||||||
closeDialog(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
context.querySelector('.btnCancelRecording').addEventListener('click', function () {
|
|
||||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
|
||||||
deleteTimer(apiClient, currentItemId).then(function () {
|
|
||||||
closeDialog(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reload(context, id) {
|
|
||||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
|
||||||
|
|
||||||
loading.show();
|
|
||||||
if (typeof id === 'string') {
|
|
||||||
currentItemId = id;
|
|
||||||
|
|
||||||
apiClient.getLiveTvSeriesTimer(id).then(function (result) {
|
|
||||||
renderTimer(context, result, apiClient);
|
|
||||||
loading.hide();
|
|
||||||
});
|
|
||||||
} else if (id) {
|
|
||||||
currentItemId = id.Id;
|
|
||||||
|
|
||||||
renderTimer(context, id, apiClient);
|
|
||||||
loading.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fillKeepUpTo(context) {
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
for (var i = 0; i <= 50; i++) {
|
|
||||||
var text;
|
|
||||||
|
|
||||||
if (i === 0) {
|
|
||||||
text = globalize.translate('AsManyAsPossible');
|
|
||||||
} else if (i === 1) {
|
|
||||||
text = globalize.translate('ValueOneEpisode');
|
|
||||||
} else {
|
|
||||||
text = globalize.translate('ValueEpisodeCount', i);
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<option value="' + i + '">' + text + '</option>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.querySelector('.selectKeepUpTo').innerHTML = html;
|
html += '<option value="' + i + '">' + text + '</option>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function onFieldChange(e) {
|
context.querySelector('.selectKeepUpTo').innerHTML = html;
|
||||||
this.querySelector('.btnSubmit').click();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function embed(itemId, serverId, options) {
|
function onFieldChange() {
|
||||||
|
this.querySelector('.btnSubmit').click();
|
||||||
|
}
|
||||||
|
|
||||||
|
function embed(itemId, serverId, options) {
|
||||||
|
recordingUpdated = false;
|
||||||
|
recordingDeleted = false;
|
||||||
|
currentServerId = serverId;
|
||||||
|
loading.show();
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
import('text!./seriesrecordingeditor.template.html').then(({ default: template }) => {
|
||||||
|
const dialogOptions = {
|
||||||
|
removeOnClose: true,
|
||||||
|
scrollY: false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (layoutManager.tv) {
|
||||||
|
dialogOptions.size = 'fullscreen';
|
||||||
|
} else {
|
||||||
|
dialogOptions.size = 'small';
|
||||||
|
}
|
||||||
|
|
||||||
|
const dlg = options.context;
|
||||||
|
|
||||||
|
dlg.classList.add('hide');
|
||||||
|
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||||
|
|
||||||
|
dlg.querySelector('.formDialogHeader').classList.add('hide');
|
||||||
|
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
||||||
|
dlg.querySelector('.formDialogContent').className = '';
|
||||||
|
dlg.querySelector('.dialogContentInner').className = '';
|
||||||
|
dlg.classList.remove('hide');
|
||||||
|
|
||||||
|
dlg.removeEventListener('change', onFieldChange);
|
||||||
|
dlg.addEventListener('change', onFieldChange);
|
||||||
|
|
||||||
|
currentDialog = dlg;
|
||||||
|
|
||||||
|
init(dlg);
|
||||||
|
|
||||||
|
reload(dlg, itemId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showEditor(itemId, serverId, options) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
recordingUpdated = false;
|
recordingUpdated = false;
|
||||||
recordingDeleted = false;
|
recordingDeleted = false;
|
||||||
currentServerId = serverId;
|
currentServerId = serverId;
|
||||||
loading.show();
|
loading.show();
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
require(['text!./seriesrecordingeditor.template.html'], function (template) {
|
import('text!./seriesrecordingeditor.template.html').then(({ default: template }) => {
|
||||||
var dialogOptions = {
|
const dialogOptions = {
|
||||||
removeOnClose: true,
|
removeOnClose: true,
|
||||||
scrollY: false
|
scrollY: false
|
||||||
};
|
};
|
||||||
|
@ -148,101 +205,58 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
|
||||||
dialogOptions.size = 'small';
|
dialogOptions.size = 'small';
|
||||||
}
|
}
|
||||||
|
|
||||||
var dlg = options.context;
|
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||||
|
|
||||||
dlg.classList.add('hide');
|
dlg.classList.add('formDialog');
|
||||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
dlg.classList.add('recordingDialog');
|
||||||
|
|
||||||
dlg.querySelector('.formDialogHeader').classList.add('hide');
|
if (!layoutManager.tv) {
|
||||||
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
dlg.style['min-width'] = '20%';
|
||||||
dlg.querySelector('.formDialogContent').className = '';
|
}
|
||||||
dlg.querySelector('.dialogContentInner').className = '';
|
|
||||||
dlg.classList.remove('hide');
|
|
||||||
|
|
||||||
dlg.removeEventListener('change', onFieldChange);
|
let html = '';
|
||||||
dlg.addEventListener('change', onFieldChange);
|
|
||||||
|
html += globalize.translateHtml(template, 'core');
|
||||||
|
|
||||||
|
dlg.innerHTML = html;
|
||||||
|
|
||||||
|
if (options.enableCancel === false) {
|
||||||
|
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
||||||
|
}
|
||||||
|
|
||||||
currentDialog = dlg;
|
currentDialog = dlg;
|
||||||
|
|
||||||
|
dlg.addEventListener('closing', function () {
|
||||||
|
if (!recordingDeleted) {
|
||||||
|
this.querySelector('.btnSubmit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dlg.addEventListener('close', function () {
|
||||||
|
if (recordingUpdated) {
|
||||||
|
resolve({
|
||||||
|
updated: true,
|
||||||
|
deleted: recordingDeleted
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (layoutManager.tv) {
|
||||||
|
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||||
|
}
|
||||||
|
|
||||||
init(dlg);
|
init(dlg);
|
||||||
|
|
||||||
reload(dlg, itemId);
|
reload(dlg, itemId);
|
||||||
|
|
||||||
|
dialogHelper.open(dlg);
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function showEditor(itemId, serverId, options) {
|
export default {
|
||||||
return new Promise(function (resolve, reject) {
|
show: showEditor,
|
||||||
recordingUpdated = false;
|
embed: embed
|
||||||
recordingDeleted = false;
|
};
|
||||||
currentServerId = serverId;
|
|
||||||
loading.show();
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
require(['text!./seriesrecordingeditor.template.html'], function (template) {
|
|
||||||
var dialogOptions = {
|
|
||||||
removeOnClose: true,
|
|
||||||
scrollY: false
|
|
||||||
};
|
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
|
||||||
dialogOptions.size = 'fullscreen';
|
|
||||||
} else {
|
|
||||||
dialogOptions.size = 'small';
|
|
||||||
}
|
|
||||||
|
|
||||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
|
||||||
|
|
||||||
dlg.classList.add('formDialog');
|
|
||||||
dlg.classList.add('recordingDialog');
|
|
||||||
|
|
||||||
if (!layoutManager.tv) {
|
|
||||||
dlg.style['min-width'] = '20%';
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
html += globalize.translateHtml(template, 'core');
|
|
||||||
|
|
||||||
dlg.innerHTML = html;
|
|
||||||
|
|
||||||
if (options.enableCancel === false) {
|
|
||||||
dlg.querySelector('.formDialogFooter').classList.add('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDialog = dlg;
|
|
||||||
|
|
||||||
dlg.addEventListener('closing', function () {
|
|
||||||
if (!recordingDeleted) {
|
|
||||||
this.querySelector('.btnSubmit').click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dlg.addEventListener('close', function () {
|
|
||||||
if (recordingUpdated) {
|
|
||||||
resolve({
|
|
||||||
updated: true,
|
|
||||||
deleted: recordingDeleted
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
|
||||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
init(dlg);
|
|
||||||
|
|
||||||
reload(dlg, itemId);
|
|
||||||
|
|
||||||
dialogHelper.open(dlg);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
show: showEditor,
|
|
||||||
embed: embed
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
|
@ -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,299 +1,304 @@
|
||||||
define(['jQuery', 'loading', 'globalize', 'emby-checkbox', 'listViewStyle', 'emby-input', 'emby-select', 'emby-button', 'flexStyles'], function ($, loading, globalize) {
|
import $ from 'jQuery';
|
||||||
'use strict';
|
import loading from 'loading';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'emby-checkbox';
|
||||||
|
import 'emby-input';
|
||||||
|
import 'listViewStyle';
|
||||||
|
import 'paper-icon-button-light';
|
||||||
|
import 'emby-select';
|
||||||
|
import 'emby-button';
|
||||||
|
import 'flexStyles';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
export default function (page, providerId, options) {
|
||||||
|
function reload() {
|
||||||
|
loading.show();
|
||||||
|
ApiClient.getNamedConfiguration('livetv').then(function (config) {
|
||||||
|
const info = config.ListingProviders.filter(function (i) {
|
||||||
|
return i.Id === providerId;
|
||||||
|
})[0] || {};
|
||||||
|
listingsId = info.ListingsId;
|
||||||
|
$('#selectListing', page).val(info.ListingsId || '');
|
||||||
|
page.querySelector('.txtUser').value = info.Username || '';
|
||||||
|
page.querySelector('.txtPass').value = '';
|
||||||
|
page.querySelector('.txtZipCode').value = info.ZipCode || '';
|
||||||
|
|
||||||
return function (page, providerId, options) {
|
if (info.Username && info.Password) {
|
||||||
function reload() {
|
page.querySelector('.listingsSection').classList.remove('hide');
|
||||||
loading.show();
|
} else {
|
||||||
ApiClient.getNamedConfiguration('livetv').then(function (config) {
|
page.querySelector('.listingsSection').classList.add('hide');
|
||||||
var info = config.ListingProviders.filter(function (i) {
|
|
||||||
return i.Id === providerId;
|
|
||||||
})[0] || {};
|
|
||||||
listingsId = info.ListingsId;
|
|
||||||
$('#selectListing', page).val(info.ListingsId || '');
|
|
||||||
page.querySelector('.txtUser').value = info.Username || '';
|
|
||||||
page.querySelector('.txtPass').value = '';
|
|
||||||
page.querySelector('.txtZipCode').value = info.ZipCode || '';
|
|
||||||
|
|
||||||
if (info.Username && info.Password) {
|
|
||||||
page.querySelector('.listingsSection').classList.remove('hide');
|
|
||||||
} else {
|
|
||||||
page.querySelector('.listingsSection').classList.add('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
page.querySelector('.chkAllTuners').checked = info.EnableAllTuners;
|
|
||||||
|
|
||||||
if (info.EnableAllTuners) {
|
|
||||||
page.querySelector('.selectTunersSection').classList.add('hide');
|
|
||||||
} else {
|
|
||||||
page.querySelector('.selectTunersSection').classList.remove('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
setCountry(info);
|
|
||||||
refreshTunerDevices(page, info, config.TunerHosts);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCountry(info) {
|
|
||||||
ApiClient.getJSON(ApiClient.getUrl('LiveTv/ListingProviders/SchedulesDirect/Countries')).then(function (result) {
|
|
||||||
var i;
|
|
||||||
var length;
|
|
||||||
var countryList = [];
|
|
||||||
|
|
||||||
for (var region in result) {
|
|
||||||
var countries = result[region];
|
|
||||||
|
|
||||||
if (countries.length && region !== 'ZZZ') {
|
|
||||||
for (i = 0, length = countries.length; i < length; i++) {
|
|
||||||
countryList.push({
|
|
||||||
name: countries[i].fullName,
|
|
||||||
value: countries[i].shortName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
countryList.sort(function (a, b) {
|
|
||||||
if (a.name > b.name) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.name < b.name) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
$('#selectCountry', page).html(countryList.map(function (c) {
|
|
||||||
return '<option value="' + c.value + '">' + c.name + '</option>';
|
|
||||||
}).join('')).val(info.Country || '');
|
|
||||||
$(page.querySelector('.txtZipCode')).trigger('change');
|
|
||||||
}, function () { // ApiClient.getJSON() error handler
|
|
||||||
Dashboard.alert({
|
|
||||||
message: globalize.translate('ErrorGettingTvLineups')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
loading.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
function sha256(str) {
|
|
||||||
if (!self.TextEncoder) {
|
|
||||||
return Promise.resolve('');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer = new TextEncoder('utf-8').encode(str);
|
page.querySelector('.chkAllTuners').checked = info.EnableAllTuners;
|
||||||
return crypto.subtle.digest('SHA-256', buffer).then(function (hash) {
|
|
||||||
return hex(hash);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function hex(buffer) {
|
if (info.EnableAllTuners) {
|
||||||
var hexCodes = [];
|
page.querySelector('.selectTunersSection').classList.add('hide');
|
||||||
var view = new DataView(buffer);
|
} else {
|
||||||
|
page.querySelector('.selectTunersSection').classList.remove('hide');
|
||||||
for (var i = 0; i < view.byteLength; i += 4) {
|
|
||||||
var value = view.getUint32(i);
|
|
||||||
var stringValue = value.toString(16);
|
|
||||||
var paddedValue = ('00000000' + stringValue).slice(-'00000000'.length);
|
|
||||||
hexCodes.push(paddedValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hexCodes.join('');
|
setCountry(info);
|
||||||
}
|
refreshTunerDevices(page, info, config.TunerHosts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function submitLoginForm() {
|
function setCountry(info) {
|
||||||
loading.show();
|
ApiClient.getJSON(ApiClient.getUrl('LiveTv/ListingProviders/SchedulesDirect/Countries')).then(function (result) {
|
||||||
sha256(page.querySelector('.txtPass').value).then(function (passwordHash) {
|
let i;
|
||||||
var info = {
|
let length;
|
||||||
Type: 'SchedulesDirect',
|
const countryList = [];
|
||||||
Username: page.querySelector('.txtUser').value,
|
|
||||||
EnableAllTuners: true,
|
|
||||||
Password: passwordHash,
|
|
||||||
Pw: page.querySelector('.txtPass').value
|
|
||||||
};
|
|
||||||
var id = providerId;
|
|
||||||
|
|
||||||
if (id) {
|
for (const region in result) {
|
||||||
info.Id = id;
|
const countries = result[region];
|
||||||
|
|
||||||
|
if (countries.length && region !== 'ZZZ') {
|
||||||
|
for (i = 0, length = countries.length; i < length; i++) {
|
||||||
|
countryList.push({
|
||||||
|
name: countries[i].fullName,
|
||||||
|
value: countries[i].shortName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
countryList.sort(function (a, b) {
|
||||||
|
if (a.name > b.name) {
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiClient.ajax({
|
if (a.name < b.name) {
|
||||||
type: 'POST',
|
return -1;
|
||||||
url: ApiClient.getUrl('LiveTv/ListingProviders', {
|
}
|
||||||
ValidateLogin: true
|
|
||||||
}),
|
return 0;
|
||||||
data: JSON.stringify(info),
|
|
||||||
contentType: 'application/json',
|
|
||||||
dataType: 'json'
|
|
||||||
}).then(function (result) {
|
|
||||||
Dashboard.processServerConfigurationUpdateResult();
|
|
||||||
providerId = result.Id;
|
|
||||||
reload();
|
|
||||||
}, function () {
|
|
||||||
Dashboard.alert({ // ApiClient.ajax() error handler
|
|
||||||
message: globalize.translate('ErrorSavingTvProvider')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
$('#selectCountry', page).html(countryList.map(function (c) {
|
||||||
|
return '<option value="' + c.value + '">' + c.name + '</option>';
|
||||||
|
}).join('')).val(info.Country || '');
|
||||||
|
$(page.querySelector('.txtZipCode')).trigger('change');
|
||||||
|
}, function () { // ApiClient.getJSON() error handler
|
||||||
|
Dashboard.alert({
|
||||||
|
message: globalize.translate('ErrorGettingTvLineups')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
loading.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sha256(str) {
|
||||||
|
if (!self.TextEncoder) {
|
||||||
|
return Promise.resolve('');
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitListingsForm() {
|
const buffer = new TextEncoder('utf-8').encode(str);
|
||||||
var selectedListingsId = $('#selectListing', page).val();
|
return crypto.subtle.digest('SHA-256', buffer).then(function (hash) {
|
||||||
|
return hex(hash);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!selectedListingsId) {
|
function hex(buffer) {
|
||||||
return void Dashboard.alert({
|
const hexCodes = [];
|
||||||
message: globalize.translate('ErrorPleaseSelectLineup')
|
const view = new DataView(buffer);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loading.show();
|
for (let i = 0; i < view.byteLength; i += 4) {
|
||||||
var id = providerId;
|
const value = view.getUint32(i);
|
||||||
ApiClient.getNamedConfiguration('livetv').then(function (config) {
|
const stringValue = value.toString(16);
|
||||||
var info = config.ListingProviders.filter(function (i) {
|
const paddedValue = ('00000000' + stringValue).slice(-'00000000'.length);
|
||||||
return i.Id === id;
|
hexCodes.push(paddedValue);
|
||||||
})[0];
|
|
||||||
info.ZipCode = page.querySelector('.txtZipCode').value;
|
|
||||||
info.Country = $('#selectCountry', page).val();
|
|
||||||
info.ListingsId = selectedListingsId;
|
|
||||||
info.EnableAllTuners = page.querySelector('.chkAllTuners').checked;
|
|
||||||
info.EnabledTuners = info.EnableAllTuners ? [] : $('.chkTuner', page).get().filter(function (i) {
|
|
||||||
return i.checked;
|
|
||||||
}).map(function (i) {
|
|
||||||
return i.getAttribute('data-id');
|
|
||||||
});
|
|
||||||
ApiClient.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: ApiClient.getUrl('LiveTv/ListingProviders', {
|
|
||||||
ValidateListings: true
|
|
||||||
}),
|
|
||||||
data: JSON.stringify(info),
|
|
||||||
contentType: 'application/json'
|
|
||||||
}).then(function (result) {
|
|
||||||
loading.hide();
|
|
||||||
|
|
||||||
if (options.showConfirmation) {
|
|
||||||
Dashboard.processServerConfigurationUpdateResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
Events.trigger(self, 'submitted');
|
|
||||||
}, function () {
|
|
||||||
loading.hide();
|
|
||||||
Dashboard.alert({
|
|
||||||
message: globalize.translate('ErrorAddingListingsToSchedulesDirect')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshListings(value) {
|
return hexCodes.join('');
|
||||||
if (!value) {
|
}
|
||||||
return void $('#selectListing', page).html('');
|
|
||||||
|
function submitLoginForm() {
|
||||||
|
loading.show();
|
||||||
|
sha256(page.querySelector('.txtPass').value).then(function (passwordHash) {
|
||||||
|
const info = {
|
||||||
|
Type: 'SchedulesDirect',
|
||||||
|
Username: page.querySelector('.txtUser').value,
|
||||||
|
EnableAllTuners: true,
|
||||||
|
Password: passwordHash,
|
||||||
|
Pw: page.querySelector('.txtPass').value
|
||||||
|
};
|
||||||
|
const id = providerId;
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
info.Id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
loading.show();
|
|
||||||
ApiClient.ajax({
|
ApiClient.ajax({
|
||||||
type: 'GET',
|
type: 'POST',
|
||||||
url: ApiClient.getUrl('LiveTv/ListingProviders/Lineups', {
|
url: ApiClient.getUrl('LiveTv/ListingProviders', {
|
||||||
Id: providerId,
|
ValidateLogin: true
|
||||||
Location: value,
|
|
||||||
Country: $('#selectCountry', page).val()
|
|
||||||
}),
|
}),
|
||||||
|
data: JSON.stringify(info),
|
||||||
|
contentType: 'application/json',
|
||||||
dataType: 'json'
|
dataType: 'json'
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
$('#selectListing', page).html(result.map(function (o) {
|
Dashboard.processServerConfigurationUpdateResult();
|
||||||
return '<option value="' + o.Id + '">' + o.Name + '</option>';
|
providerId = result.Id;
|
||||||
}));
|
reload();
|
||||||
|
}, function () {
|
||||||
if (listingsId) {
|
Dashboard.alert({ // ApiClient.ajax() error handler
|
||||||
$('#selectListing', page).val(listingsId);
|
message: globalize.translate('ErrorSavingTvProvider')
|
||||||
}
|
|
||||||
|
|
||||||
loading.hide();
|
|
||||||
}, function (result) {
|
|
||||||
Dashboard.alert({
|
|
||||||
message: globalize.translate('ErrorGettingTvLineups')
|
|
||||||
});
|
});
|
||||||
refreshListings('');
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitListingsForm() {
|
||||||
|
const selectedListingsId = $('#selectListing', page).val();
|
||||||
|
|
||||||
|
if (!selectedListingsId) {
|
||||||
|
return void Dashboard.alert({
|
||||||
|
message: globalize.translate('ErrorPleaseSelectLineup')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.show();
|
||||||
|
const id = providerId;
|
||||||
|
ApiClient.getNamedConfiguration('livetv').then(function (config) {
|
||||||
|
const info = config.ListingProviders.filter(function (i) {
|
||||||
|
return i.Id === id;
|
||||||
|
})[0];
|
||||||
|
info.ZipCode = page.querySelector('.txtZipCode').value;
|
||||||
|
info.Country = $('#selectCountry', page).val();
|
||||||
|
info.ListingsId = selectedListingsId;
|
||||||
|
info.EnableAllTuners = page.querySelector('.chkAllTuners').checked;
|
||||||
|
info.EnabledTuners = info.EnableAllTuners ? [] : $('.chkTuner', page).get().filter(function (i) {
|
||||||
|
return i.checked;
|
||||||
|
}).map(function (i) {
|
||||||
|
return i.getAttribute('data-id');
|
||||||
|
});
|
||||||
|
ApiClient.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: ApiClient.getUrl('LiveTv/ListingProviders', {
|
||||||
|
ValidateListings: true
|
||||||
|
}),
|
||||||
|
data: JSON.stringify(info),
|
||||||
|
contentType: 'application/json'
|
||||||
|
}).then(function (result) {
|
||||||
loading.hide();
|
loading.hide();
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTunerName(providerId) {
|
if (options.showConfirmation) {
|
||||||
switch (providerId = providerId.toLowerCase()) {
|
Dashboard.processServerConfigurationUpdateResult();
|
||||||
case 'm3u':
|
|
||||||
return 'M3U Playlist';
|
|
||||||
case 'hdhomerun':
|
|
||||||
return 'HDHomerun';
|
|
||||||
case 'satip':
|
|
||||||
return 'DVB';
|
|
||||||
default:
|
|
||||||
return 'Unknown';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshTunerDevices(page, providerInfo, devices) {
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
for (var i = 0, length = devices.length; i < length; i++) {
|
|
||||||
var device = devices[i];
|
|
||||||
html += '<div class="listItem">';
|
|
||||||
var enabledTuners = providerInfo.EnabledTuners || [];
|
|
||||||
var isChecked = providerInfo.EnableAllTuners || enabledTuners.indexOf(device.Id) !== -1;
|
|
||||||
var checkedAttribute = isChecked ? ' checked' : '';
|
|
||||||
html += '<label class="checkboxContainer listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" data-id="' + device.Id + '" class="chkTuner" ' + checkedAttribute + '/><span></span></label>';
|
|
||||||
html += '<div class="listItemBody two-line">';
|
|
||||||
html += '<div class="listItemBodyText">';
|
|
||||||
html += device.FriendlyName || getTunerName(device.Type);
|
|
||||||
html += '</div>';
|
|
||||||
html += '<div class="listItemBodyText secondary">';
|
|
||||||
html += device.Url;
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
page.querySelector('.tunerList').innerHTML = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
var listingsId;
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.submit = function () {
|
|
||||||
page.querySelector('.btnSubmitListingsContainer').click();
|
|
||||||
};
|
|
||||||
|
|
||||||
self.init = function () {
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
// Only hide the buttons if explicitly set to false; default to showing if undefined or null
|
|
||||||
// FIXME: rename this option to clarify logic
|
|
||||||
var hideCancelButton = options.showCancelButton === false;
|
|
||||||
page.querySelector('.btnCancel').classList.toggle('hide', hideCancelButton);
|
|
||||||
|
|
||||||
var hideSubmitButton = options.showSubmitButton === false;
|
|
||||||
page.querySelector('.btnSubmitListings').classList.toggle('hide', hideSubmitButton);
|
|
||||||
|
|
||||||
$('.formLogin', page).on('submit', function () {
|
|
||||||
submitLoginForm();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
$('.formListings', page).on('submit', function () {
|
|
||||||
submitListingsForm();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
$('.txtZipCode', page).on('change', function () {
|
|
||||||
refreshListings(this.value);
|
|
||||||
});
|
|
||||||
page.querySelector('.chkAllTuners').addEventListener('change', function (e) {
|
|
||||||
if (e.target.checked) {
|
|
||||||
page.querySelector('.selectTunersSection').classList.add('hide');
|
|
||||||
} else {
|
|
||||||
page.querySelector('.selectTunersSection').classList.remove('hide');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Events.trigger(self, 'submitted');
|
||||||
|
}, function () {
|
||||||
|
loading.hide();
|
||||||
|
Dashboard.alert({
|
||||||
|
message: globalize.translate('ErrorAddingListingsToSchedulesDirect')
|
||||||
|
});
|
||||||
});
|
});
|
||||||
$('.createAccountHelp', page).html(globalize.translate('MessageCreateAccountAt', '<a is="emby-linkbutton" class="button-link" href="http://www.schedulesdirect.org" target="_blank">http://www.schedulesdirect.org</a>'));
|
});
|
||||||
reload();
|
}
|
||||||
};
|
|
||||||
|
function refreshListings(value) {
|
||||||
|
if (!value) {
|
||||||
|
return void $('#selectListing', page).html('');
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.show();
|
||||||
|
ApiClient.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: ApiClient.getUrl('LiveTv/ListingProviders/Lineups', {
|
||||||
|
Id: providerId,
|
||||||
|
Location: value,
|
||||||
|
Country: $('#selectCountry', page).val()
|
||||||
|
}),
|
||||||
|
dataType: 'json'
|
||||||
|
}).then(function (result) {
|
||||||
|
$('#selectListing', page).html(result.map(function (o) {
|
||||||
|
return '<option value="' + o.Id + '">' + o.Name + '</option>';
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (listingsId) {
|
||||||
|
$('#selectListing', page).val(listingsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.hide();
|
||||||
|
}, function (result) {
|
||||||
|
Dashboard.alert({
|
||||||
|
message: globalize.translate('ErrorGettingTvLineups')
|
||||||
|
});
|
||||||
|
refreshListings('');
|
||||||
|
loading.hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTunerName(providerId) {
|
||||||
|
switch (providerId = providerId.toLowerCase()) {
|
||||||
|
case 'm3u':
|
||||||
|
return 'M3U Playlist';
|
||||||
|
case 'hdhomerun':
|
||||||
|
return 'HDHomerun';
|
||||||
|
case 'satip':
|
||||||
|
return 'DVB';
|
||||||
|
default:
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshTunerDevices(page, providerInfo, devices) {
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
for (let i = 0, length = devices.length; i < length; i++) {
|
||||||
|
const device = devices[i];
|
||||||
|
html += '<div class="listItem">';
|
||||||
|
const enabledTuners = providerInfo.EnabledTuners || [];
|
||||||
|
const isChecked = providerInfo.EnableAllTuners || enabledTuners.indexOf(device.Id) !== -1;
|
||||||
|
const checkedAttribute = isChecked ? ' checked' : '';
|
||||||
|
html += '<label class="checkboxContainer listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" data-id="' + device.Id + '" class="chkTuner" ' + checkedAttribute + '/><span></span></label>';
|
||||||
|
html += '<div class="listItemBody two-line">';
|
||||||
|
html += '<div class="listItemBodyText">';
|
||||||
|
html += device.FriendlyName || getTunerName(device.Type);
|
||||||
|
html += '</div>';
|
||||||
|
html += '<div class="listItemBodyText secondary">';
|
||||||
|
html += device.Url;
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
page.querySelector('.tunerList').innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
let listingsId;
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
self.submit = function () {
|
||||||
|
page.querySelector('.btnSubmitListingsContainer').click();
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
self.init = function () {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// Only hide the buttons if explicitly set to false; default to showing if undefined or null
|
||||||
|
// FIXME: rename this option to clarify logic
|
||||||
|
const hideCancelButton = options.showCancelButton === false;
|
||||||
|
page.querySelector('.btnCancel').classList.toggle('hide', hideCancelButton);
|
||||||
|
|
||||||
|
const hideSubmitButton = options.showSubmitButton === false;
|
||||||
|
page.querySelector('.btnSubmitListings').classList.toggle('hide', hideSubmitButton);
|
||||||
|
|
||||||
|
$('.formLogin', page).on('submit', function () {
|
||||||
|
submitLoginForm();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
$('.formListings', page).on('submit', function () {
|
||||||
|
submitListingsForm();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
$('.txtZipCode', page).on('change', function () {
|
||||||
|
refreshListings(this.value);
|
||||||
|
});
|
||||||
|
page.querySelector('.chkAllTuners').addEventListener('change', function (e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
page.querySelector('.selectTunersSection').classList.add('hide');
|
||||||
|
} else {
|
||||||
|
page.querySelector('.selectTunersSection').classList.remove('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('.createAccountHelp', page).html(globalize.translate('MessageCreateAccountAt', '<a is="emby-linkbutton" class="button-link" href="http://www.schedulesdirect.org" target="_blank">http://www.schedulesdirect.org</a>'));
|
||||||
|
reload();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,191 +1,193 @@
|
||||||
define(['jQuery', 'loading', 'globalize', 'emby-checkbox', 'emby-input', 'listViewStyle', 'paper-icon-button-light'], function ($, loading, globalize) {
|
import $ from 'jQuery';
|
||||||
'use strict';
|
import loading from 'loading';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'emby-checkbox';
|
||||||
|
import 'emby-input';
|
||||||
|
import 'listViewStyle';
|
||||||
|
import 'paper-icon-button-light';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
export default function (page, providerId, options) {
|
||||||
|
function getListingProvider(config, id) {
|
||||||
|
if (config && id) {
|
||||||
|
const result = config.ListingProviders.filter(function (provider) {
|
||||||
|
return provider.Id === id;
|
||||||
|
})[0];
|
||||||
|
|
||||||
return function (page, providerId, options) {
|
if (result) {
|
||||||
function getListingProvider(config, id) {
|
return Promise.resolve(result);
|
||||||
if (config && id) {
|
|
||||||
var result = config.ListingProviders.filter(function (provider) {
|
|
||||||
return provider.Id === id;
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
return Promise.resolve(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getListingProvider();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ApiClient.getJSON(ApiClient.getUrl('LiveTv/ListingProviders/Default'));
|
return getListingProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
function reload() {
|
return ApiClient.getJSON(ApiClient.getUrl('LiveTv/ListingProviders/Default'));
|
||||||
loading.show();
|
}
|
||||||
ApiClient.getNamedConfiguration('livetv').then(function (config) {
|
|
||||||
getListingProvider(config, providerId).then(function (info) {
|
|
||||||
page.querySelector('.txtPath').value = info.Path || '';
|
|
||||||
page.querySelector('.txtKids').value = (info.KidsCategories || []).join('|');
|
|
||||||
page.querySelector('.txtNews').value = (info.NewsCategories || []).join('|');
|
|
||||||
page.querySelector('.txtSports').value = (info.SportsCategories || []).join('|');
|
|
||||||
page.querySelector('.txtMovies').value = (info.MovieCategories || []).join('|');
|
|
||||||
page.querySelector('.txtMoviePrefix').value = info.MoviePrefix || '';
|
|
||||||
page.querySelector('.txtUserAgent').value = info.UserAgent || '';
|
|
||||||
page.querySelector('.chkAllTuners').checked = info.EnableAllTuners;
|
|
||||||
|
|
||||||
if (page.querySelector('.chkAllTuners').checked) {
|
function reload() {
|
||||||
page.querySelector('.selectTunersSection').classList.add('hide');
|
loading.show();
|
||||||
} else {
|
ApiClient.getNamedConfiguration('livetv').then(function (config) {
|
||||||
page.querySelector('.selectTunersSection').classList.remove('hide');
|
getListingProvider(config, providerId).then(function (info) {
|
||||||
}
|
page.querySelector('.txtPath').value = info.Path || '';
|
||||||
|
page.querySelector('.txtKids').value = (info.KidsCategories || []).join('|');
|
||||||
|
page.querySelector('.txtNews').value = (info.NewsCategories || []).join('|');
|
||||||
|
page.querySelector('.txtSports').value = (info.SportsCategories || []).join('|');
|
||||||
|
page.querySelector('.txtMovies').value = (info.MovieCategories || []).join('|');
|
||||||
|
page.querySelector('.txtMoviePrefix').value = info.MoviePrefix || '';
|
||||||
|
page.querySelector('.txtUserAgent').value = info.UserAgent || '';
|
||||||
|
page.querySelector('.chkAllTuners').checked = info.EnableAllTuners;
|
||||||
|
|
||||||
refreshTunerDevices(page, info, config.TunerHosts);
|
if (page.querySelector('.chkAllTuners').checked) {
|
||||||
loading.hide();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCategories(txtInput) {
|
|
||||||
var value = txtInput.value;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
return value.split('|');
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitListingsForm() {
|
|
||||||
loading.show();
|
|
||||||
var id = providerId;
|
|
||||||
ApiClient.getNamedConfiguration('livetv').then(function (config) {
|
|
||||||
var info = config.ListingProviders.filter(function (provider) {
|
|
||||||
return provider.Id === id;
|
|
||||||
})[0] || {};
|
|
||||||
info.Type = 'xmltv';
|
|
||||||
info.Path = page.querySelector('.txtPath').value;
|
|
||||||
info.MoviePrefix = page.querySelector('.txtMoviePrefix').value || null;
|
|
||||||
info.UserAgent = page.querySelector('.txtUserAgent').value || null;
|
|
||||||
info.MovieCategories = getCategories(page.querySelector('.txtMovies'));
|
|
||||||
info.KidsCategories = getCategories(page.querySelector('.txtKids'));
|
|
||||||
info.NewsCategories = getCategories(page.querySelector('.txtNews'));
|
|
||||||
info.SportsCategories = getCategories(page.querySelector('.txtSports'));
|
|
||||||
info.EnableAllTuners = page.querySelector('.chkAllTuners').checked;
|
|
||||||
info.EnabledTuners = info.EnableAllTuners ? [] : $('.chkTuner', page).get().filter(function (tuner) {
|
|
||||||
return tuner.checked;
|
|
||||||
}).map(function (tuner) {
|
|
||||||
return tuner.getAttribute('data-id');
|
|
||||||
});
|
|
||||||
ApiClient.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: ApiClient.getUrl('LiveTv/ListingProviders', {
|
|
||||||
ValidateListings: true
|
|
||||||
}),
|
|
||||||
data: JSON.stringify(info),
|
|
||||||
contentType: 'application/json'
|
|
||||||
}).then(function (result) {
|
|
||||||
loading.hide();
|
|
||||||
|
|
||||||
if (options.showConfirmation !== false) {
|
|
||||||
Dashboard.processServerConfigurationUpdateResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
Events.trigger(self, 'submitted');
|
|
||||||
}, function () {
|
|
||||||
loading.hide();
|
|
||||||
Dashboard.alert({
|
|
||||||
message: globalize.translate('ErrorAddingXmlTvFile')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTunerName(providerId) {
|
|
||||||
switch (providerId = providerId.toLowerCase()) {
|
|
||||||
case 'm3u':
|
|
||||||
return 'M3U Playlist';
|
|
||||||
case 'hdhomerun':
|
|
||||||
return 'HDHomerun';
|
|
||||||
case 'satip':
|
|
||||||
return 'DVB';
|
|
||||||
default:
|
|
||||||
return 'Unknown';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshTunerDevices(page, providerInfo, devices) {
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
for (var i = 0, length = devices.length; i < length; i++) {
|
|
||||||
var device = devices[i];
|
|
||||||
html += '<div class="listItem">';
|
|
||||||
var enabledTuners = providerInfo.EnabledTuners || [];
|
|
||||||
var isChecked = providerInfo.EnableAllTuners || enabledTuners.indexOf(device.Id) !== -1;
|
|
||||||
var checkedAttribute = isChecked ? ' checked' : '';
|
|
||||||
html += '<label class="listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" class="chkTuner" data-id="' + device.Id + '" ' + checkedAttribute + '><span></span></label>';
|
|
||||||
html += '<div class="listItemBody two-line">';
|
|
||||||
html += '<div class="listItemBodyText">';
|
|
||||||
html += device.FriendlyName || getTunerName(device.Type);
|
|
||||||
html += '</div>';
|
|
||||||
html += '<div class="listItemBodyText secondary">';
|
|
||||||
html += device.Url;
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
page.querySelector('.tunerList').innerHTML = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSelectPathClick(e) {
|
|
||||||
var page = $(e.target).parents('.xmltvForm')[0];
|
|
||||||
|
|
||||||
require(['directorybrowser'], function (directoryBrowser) {
|
|
||||||
var picker = new directoryBrowser.default();
|
|
||||||
picker.show({
|
|
||||||
includeFiles: true,
|
|
||||||
callback: function (path) {
|
|
||||||
if (path) {
|
|
||||||
var txtPath = page.querySelector('.txtPath');
|
|
||||||
txtPath.value = path;
|
|
||||||
txtPath.focus();
|
|
||||||
}
|
|
||||||
picker.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.submit = function () {
|
|
||||||
page.querySelector('.btnSubmitListings').click();
|
|
||||||
};
|
|
||||||
|
|
||||||
self.init = function () {
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
// Only hide the buttons if explicitly set to false; default to showing if undefined or null
|
|
||||||
// FIXME: rename this option to clarify logic
|
|
||||||
var hideCancelButton = options.showCancelButton === false;
|
|
||||||
page.querySelector('.btnCancel').classList.toggle('hide', hideCancelButton);
|
|
||||||
|
|
||||||
var hideSubmitButton = options.showSubmitButton === false;
|
|
||||||
page.querySelector('.btnSubmitListings').classList.toggle('hide', hideSubmitButton);
|
|
||||||
|
|
||||||
$('form', page).on('submit', function () {
|
|
||||||
submitListingsForm();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
page.querySelector('#btnSelectPath').addEventListener('click', onSelectPathClick);
|
|
||||||
page.querySelector('.chkAllTuners').addEventListener('change', function (evt) {
|
|
||||||
if (evt.target.checked) {
|
|
||||||
page.querySelector('.selectTunersSection').classList.add('hide');
|
page.querySelector('.selectTunersSection').classList.add('hide');
|
||||||
} else {
|
} else {
|
||||||
page.querySelector('.selectTunersSection').classList.remove('hide');
|
page.querySelector('.selectTunersSection').classList.remove('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshTunerDevices(page, info, config.TunerHosts);
|
||||||
|
loading.hide();
|
||||||
});
|
});
|
||||||
reload();
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
function getCategories(txtInput) {
|
||||||
|
const value = txtInput.value;
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
return value.split('|');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitListingsForm() {
|
||||||
|
loading.show();
|
||||||
|
const id = providerId;
|
||||||
|
ApiClient.getNamedConfiguration('livetv').then(function (config) {
|
||||||
|
const info = config.ListingProviders.filter(function (provider) {
|
||||||
|
return provider.Id === id;
|
||||||
|
})[0] || {};
|
||||||
|
info.Type = 'xmltv';
|
||||||
|
info.Path = page.querySelector('.txtPath').value;
|
||||||
|
info.MoviePrefix = page.querySelector('.txtMoviePrefix').value || null;
|
||||||
|
info.UserAgent = page.querySelector('.txtUserAgent').value || null;
|
||||||
|
info.MovieCategories = getCategories(page.querySelector('.txtMovies'));
|
||||||
|
info.KidsCategories = getCategories(page.querySelector('.txtKids'));
|
||||||
|
info.NewsCategories = getCategories(page.querySelector('.txtNews'));
|
||||||
|
info.SportsCategories = getCategories(page.querySelector('.txtSports'));
|
||||||
|
info.EnableAllTuners = page.querySelector('.chkAllTuners').checked;
|
||||||
|
info.EnabledTuners = info.EnableAllTuners ? [] : $('.chkTuner', page).get().filter(function (tuner) {
|
||||||
|
return tuner.checked;
|
||||||
|
}).map(function (tuner) {
|
||||||
|
return tuner.getAttribute('data-id');
|
||||||
|
});
|
||||||
|
ApiClient.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: ApiClient.getUrl('LiveTv/ListingProviders', {
|
||||||
|
ValidateListings: true
|
||||||
|
}),
|
||||||
|
data: JSON.stringify(info),
|
||||||
|
contentType: 'application/json'
|
||||||
|
}).then(function (result) {
|
||||||
|
loading.hide();
|
||||||
|
|
||||||
|
if (options.showConfirmation !== false) {
|
||||||
|
Dashboard.processServerConfigurationUpdateResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.trigger(self, 'submitted');
|
||||||
|
}, function () {
|
||||||
|
loading.hide();
|
||||||
|
Dashboard.alert({
|
||||||
|
message: globalize.translate('ErrorAddingXmlTvFile')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTunerName(providerId) {
|
||||||
|
switch (providerId = providerId.toLowerCase()) {
|
||||||
|
case 'm3u':
|
||||||
|
return 'M3U Playlist';
|
||||||
|
case 'hdhomerun':
|
||||||
|
return 'HDHomerun';
|
||||||
|
case 'satip':
|
||||||
|
return 'DVB';
|
||||||
|
default:
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshTunerDevices(page, providerInfo, devices) {
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
for (let i = 0, length = devices.length; i < length; i++) {
|
||||||
|
const device = devices[i];
|
||||||
|
html += '<div class="listItem">';
|
||||||
|
const enabledTuners = providerInfo.EnabledTuners || [];
|
||||||
|
const isChecked = providerInfo.EnableAllTuners || enabledTuners.indexOf(device.Id) !== -1;
|
||||||
|
const checkedAttribute = isChecked ? ' checked' : '';
|
||||||
|
html += '<label class="listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" class="chkTuner" data-id="' + device.Id + '" ' + checkedAttribute + '><span></span></label>';
|
||||||
|
html += '<div class="listItemBody two-line">';
|
||||||
|
html += '<div class="listItemBodyText">';
|
||||||
|
html += device.FriendlyName || getTunerName(device.Type);
|
||||||
|
html += '</div>';
|
||||||
|
html += '<div class="listItemBodyText secondary">';
|
||||||
|
html += device.Url;
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
page.querySelector('.tunerList').innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelectPathClick(e) {
|
||||||
|
const page = $(e.target).parents('.xmltvForm')[0];
|
||||||
|
|
||||||
|
import('directorybrowser').then(({default: directoryBrowser}) => {
|
||||||
|
const picker = new directoryBrowser();
|
||||||
|
picker.show({
|
||||||
|
includeFiles: true,
|
||||||
|
callback: function (path) {
|
||||||
|
if (path) {
|
||||||
|
const txtPath = page.querySelector('.txtPath');
|
||||||
|
txtPath.value = path;
|
||||||
|
txtPath.focus();
|
||||||
|
}
|
||||||
|
picker.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
self.submit = function () {
|
||||||
|
page.querySelector('.btnSubmitListings').click();
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
self.init = function () {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// Only hide the buttons if explicitly set to false; default to showing if undefined or null
|
||||||
|
// FIXME: rename this option to clarify logic
|
||||||
|
const hideCancelButton = options.showCancelButton === false;
|
||||||
|
page.querySelector('.btnCancel').classList.toggle('hide', hideCancelButton);
|
||||||
|
|
||||||
|
const hideSubmitButton = options.showSubmitButton === false;
|
||||||
|
page.querySelector('.btnSubmitListings').classList.toggle('hide', hideSubmitButton);
|
||||||
|
|
||||||
|
$('form', page).on('submit', function () {
|
||||||
|
submitListingsForm();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
page.querySelector('#btnSelectPath').addEventListener('click', onSelectPathClick);
|
||||||
|
page.querySelector('.chkAllTuners').addEventListener('change', function (evt) {
|
||||||
|
if (evt.target.checked) {
|
||||||
|
page.querySelector('.selectTunersSection').classList.add('hide');
|
||||||
|
} else {
|
||||||
|
page.querySelector('.selectTunersSection').classList.remove('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
reload();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder, userSettings, globalize) {
|
import loading from 'loading';
|
||||||
'use strict';
|
import libraryBrowser from 'libraryBrowser';
|
||||||
|
import imageLoader from 'imageLoader';
|
||||||
|
import listView from 'listView';
|
||||||
|
import cardBuilder from 'cardBuilder';
|
||||||
|
import * as userSettings from 'userSettings';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'emby-itemscontainer';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
/* eslint-disable indent */
|
||||||
libraryBrowser = libraryBrowser.default || libraryBrowser;
|
|
||||||
|
|
||||||
return function (view, params, tabContent) {
|
export default function (view, params, tabContent) {
|
||||||
function getPageData(context) {
|
function getPageData(context) {
|
||||||
var key = getSavedQueryKey(context);
|
const key = getSavedQueryKey(context);
|
||||||
var pageData = data[key];
|
let pageData = data[key];
|
||||||
|
|
||||||
if (!pageData) {
|
if (!pageData) {
|
||||||
pageData = data[key] = {
|
pageData = data[key] = {
|
||||||
|
@ -47,9 +52,9 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
|
||||||
return context.savedQueryKey;
|
return context.savedQueryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onViewStyleChange() {
|
const onViewStyleChange = () => {
|
||||||
var viewStyle = self.getCurrentViewStyle();
|
const viewStyle = this.getCurrentViewStyle();
|
||||||
var itemsContainer = tabContent.querySelector('.itemsContainer');
|
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||||
|
|
||||||
if (viewStyle == 'List') {
|
if (viewStyle == 'List') {
|
||||||
itemsContainer.classList.add('vertical-list');
|
itemsContainer.classList.add('vertical-list');
|
||||||
|
@ -60,13 +65,13 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
|
||||||
}
|
}
|
||||||
|
|
||||||
itemsContainer.innerHTML = '';
|
itemsContainer.innerHTML = '';
|
||||||
}
|
};
|
||||||
|
|
||||||
function reloadItems(page) {
|
const reloadItems = (page) => {
|
||||||
loading.show();
|
loading.show();
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
var query = getQuery(page);
|
const query = getQuery(page);
|
||||||
ApiClient.getItems(ApiClient.getCurrentUserId(), query).then(function (result) {
|
ApiClient.getItems(ApiClient.getCurrentUserId(), query).then((result) => {
|
||||||
function onNextPageClick() {
|
function onNextPageClick() {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return;
|
return;
|
||||||
|
@ -90,8 +95,8 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
|
||||||
}
|
}
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
var html;
|
let html;
|
||||||
var pagingHtml = libraryBrowser.getQueryPagingHtml({
|
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
||||||
startIndex: query.StartIndex,
|
startIndex: query.StartIndex,
|
||||||
limit: query.Limit,
|
limit: query.Limit,
|
||||||
totalRecordCount: result.TotalRecordCount,
|
totalRecordCount: result.TotalRecordCount,
|
||||||
|
@ -101,7 +106,7 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
|
||||||
sortButton: false,
|
sortButton: false,
|
||||||
filterButton: false
|
filterButton: false
|
||||||
});
|
});
|
||||||
var viewStyle = self.getCurrentViewStyle();
|
const viewStyle = this.getCurrentViewStyle();
|
||||||
if (viewStyle == 'Thumb') {
|
if (viewStyle == 'Thumb') {
|
||||||
html = cardBuilder.getCardsHtml({
|
html = cardBuilder.getCardsHtml({
|
||||||
items: result.Items,
|
items: result.Items,
|
||||||
|
@ -155,22 +160,21 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
|
||||||
showTitle: true
|
showTitle: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var i;
|
|
||||||
var length;
|
|
||||||
var elems = tabContent.querySelectorAll('.paging');
|
|
||||||
|
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
let elems = tabContent.querySelectorAll('.paging');
|
||||||
elems[i].innerHTML = pagingHtml;
|
|
||||||
|
for (const elem of elems) {
|
||||||
|
elem.innerHTML = pagingHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
for (const elem of elems) {
|
||||||
elems[i].addEventListener('click', onNextPageClick);
|
elem.addEventListener('click', onNextPageClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
for (const elem of elems) {
|
||||||
elems[i].addEventListener('click', onPreviousPageClick);
|
elem.addEventListener('click', onPreviousPageClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.Items.length) {
|
if (!result.Items.length) {
|
||||||
|
@ -182,28 +186,27 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemsContainer = tabContent.querySelector('.itemsContainer');
|
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||||
itemsContainer.innerHTML = html;
|
itemsContainer.innerHTML = html;
|
||||||
imageLoader.lazyChildren(itemsContainer);
|
imageLoader.lazyChildren(itemsContainer);
|
||||||
libraryBrowser.saveQueryValues(getSavedQueryKey(page), query);
|
libraryBrowser.saveQueryValues(getSavedQueryKey(page), query);
|
||||||
loading.hide();
|
loading.hide();
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
|
|
||||||
require(['autoFocuser'], function (autoFocuser) {
|
import('autoFocuser').then(({default: autoFocuser}) => {
|
||||||
autoFocuser.autoFocus(page);
|
autoFocuser.autoFocus(page);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
var self = this;
|
const data = {};
|
||||||
var data = {};
|
let isLoading = false;
|
||||||
var isLoading = false;
|
|
||||||
|
|
||||||
self.getCurrentViewStyle = function () {
|
this.getCurrentViewStyle = function () {
|
||||||
return getPageData(tabContent).view;
|
return getPageData(tabContent).view;
|
||||||
};
|
};
|
||||||
|
|
||||||
function initPage(tabContent) {
|
const initPage = (tabContent) => {
|
||||||
tabContent.querySelector('.btnSort').addEventListener('click', function (e) {
|
tabContent.querySelector('.btnSort').addEventListener('click', function (e) {
|
||||||
libraryBrowser.showSortMenu({
|
libraryBrowser.showSortMenu({
|
||||||
items: [{
|
items: [{
|
||||||
|
@ -230,36 +233,37 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
|
||||||
button: e.target
|
button: e.target
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
var btnSelectView = tabContent.querySelector('.btnSelectView');
|
const btnSelectView = tabContent.querySelector('.btnSelectView');
|
||||||
btnSelectView.addEventListener('click', function (e) {
|
btnSelectView.addEventListener('click', function (e) {
|
||||||
libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
|
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle(), 'List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
|
||||||
});
|
});
|
||||||
btnSelectView.addEventListener('layoutchange', function (e) {
|
btnSelectView.addEventListener('layoutchange', function (e) {
|
||||||
var viewStyle = e.detail.viewStyle;
|
const viewStyle = e.detail.viewStyle;
|
||||||
getPageData(tabContent).view = viewStyle;
|
getPageData(tabContent).view = viewStyle;
|
||||||
libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle);
|
libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle);
|
||||||
getQuery(tabContent).StartIndex = 0;
|
getQuery(tabContent).StartIndex = 0;
|
||||||
onViewStyleChange();
|
onViewStyleChange();
|
||||||
reloadItems(tabContent);
|
reloadItems(tabContent);
|
||||||
});
|
});
|
||||||
tabContent.querySelector('.btnNewCollection').addEventListener('click', function () {
|
tabContent.querySelector('.btnNewCollection').addEventListener('click', () => {
|
||||||
require(['collectionEditor'], function (collectionEditor) {
|
import('collectionEditor').then(({default: collectionEditor}) => {
|
||||||
var serverId = ApiClient.serverInfo().Id;
|
const serverId = ApiClient.serverInfo().Id;
|
||||||
new collectionEditor.showEditor({
|
new collectionEditor.showEditor({
|
||||||
items: [],
|
items: [],
|
||||||
serverId: serverId
|
serverId: serverId
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
initPage(tabContent);
|
initPage(tabContent);
|
||||||
onViewStyleChange();
|
onViewStyleChange();
|
||||||
|
|
||||||
self.renderTab = function () {
|
this.renderTab = function () {
|
||||||
reloadItems(tabContent);
|
reloadItems(tabContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.destroy = function () {};
|
this.destroy = function () {};
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
/* eslint-enable indent */
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader', 'apphost', 'globalize', 'appRouter', 'dom', 'emby-button'], function (layoutManager, loading, libraryBrowser, cardBuilder, lazyLoader, appHost, globalize, appRouter, dom) {
|
import layoutManager from 'layoutManager';
|
||||||
'use strict';
|
import loading from 'loading';
|
||||||
|
import libraryBrowser from 'libraryBrowser';
|
||||||
|
import cardBuilder from 'cardBuilder';
|
||||||
|
import lazyLoader from 'lazyLoader';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import appRouter from 'appRouter';
|
||||||
|
import 'emby-button';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
/* eslint-disable indent */
|
||||||
libraryBrowser = libraryBrowser.default || libraryBrowser;
|
|
||||||
|
|
||||||
return function (view, params, tabContent) {
|
export default function (view, params, tabContent) {
|
||||||
function getPageData() {
|
function getPageData() {
|
||||||
var key = getSavedQueryKey();
|
const key = getSavedQueryKey();
|
||||||
var pageData = data[key];
|
let pageData = data[key];
|
||||||
|
|
||||||
if (!pageData) {
|
if (!pageData) {
|
||||||
pageData = data[key] = {
|
pageData = data[key] = {
|
||||||
|
@ -37,7 +42,7 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
|
||||||
|
|
||||||
function getPromise() {
|
function getPromise() {
|
||||||
loading.show();
|
loading.show();
|
||||||
var query = getQuery();
|
const query = getQuery();
|
||||||
return ApiClient.getGenres(ApiClient.getCurrentUserId(), query);
|
return ApiClient.getGenres(ApiClient.getCurrentUserId(), query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,18 +58,18 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
|
||||||
return enableScrollX() ? 'overflowPortrait' : 'portrait';
|
return enableScrollX() ? 'overflowPortrait' : 'portrait';
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillItemsContainer(entry) {
|
const fillItemsContainer = (entry) => {
|
||||||
var elem = entry.target;
|
const elem = entry.target;
|
||||||
var id = elem.getAttribute('data-id');
|
const id = elem.getAttribute('data-id');
|
||||||
var viewStyle = self.getCurrentViewStyle();
|
const viewStyle = this.getCurrentViewStyle();
|
||||||
var limit = viewStyle == 'Thumb' || viewStyle == 'ThumbCard' ? 5 : 9;
|
let limit = viewStyle == 'Thumb' || viewStyle == 'ThumbCard' ? 5 : 9;
|
||||||
|
|
||||||
if (enableScrollX()) {
|
if (enableScrollX()) {
|
||||||
limit = 10;
|
limit = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
var enableImageTypes = viewStyle == 'Thumb' || viewStyle == 'ThumbCard' ? 'Primary,Backdrop,Thumb' : 'Primary';
|
const enableImageTypes = viewStyle == 'Thumb' || viewStyle == 'ThumbCard' ? 'Primary,Backdrop,Thumb' : 'Primary';
|
||||||
var query = {
|
const query = {
|
||||||
SortBy: 'SortName',
|
SortBy: 'SortName',
|
||||||
SortOrder: 'Ascending',
|
SortOrder: 'Ascending',
|
||||||
IncludeItemTypes: 'Movie',
|
IncludeItemTypes: 'Movie',
|
||||||
|
@ -126,17 +131,17 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
|
||||||
tabContent.querySelector('.btnMoreFromGenre' + id + ' .material-icons').classList.remove('hide');
|
tabContent.querySelector('.btnMoreFromGenre' + id + ' .material-icons').classList.remove('hide');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function reloadItems(context, promise) {
|
function reloadItems(context, promise) {
|
||||||
var query = getQuery();
|
const query = getQuery();
|
||||||
promise.then(function (result) {
|
promise.then(function (result) {
|
||||||
var elem = context.querySelector('#items');
|
const elem = context.querySelector('#items');
|
||||||
var html = '';
|
let html = '';
|
||||||
var items = result.Items;
|
const items = result.Items;
|
||||||
|
|
||||||
for (var i = 0, length = items.length; i < length; i++) {
|
for (let i = 0, length = items.length; i < length; i++) {
|
||||||
var item = items[i];
|
const item = items[i];
|
||||||
|
|
||||||
html += '<div class="verticalSection">';
|
html += '<div class="verticalSection">';
|
||||||
html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">';
|
html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">';
|
||||||
|
@ -151,7 +156,7 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
|
||||||
html += '</a>';
|
html += '</a>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
if (enableScrollX()) {
|
if (enableScrollX()) {
|
||||||
var scrollXClass = 'scrollX hiddenScrollX';
|
let scrollXClass = 'scrollX hiddenScrollX';
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
if (layoutManager.tv) {
|
||||||
scrollXClass += 'smoothScrollX padded-top-focusscale padded-bottom-focusscale';
|
scrollXClass += 'smoothScrollX padded-top-focusscale padded-bottom-focusscale';
|
||||||
|
@ -182,37 +187,37 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fullyReload() {
|
const fullyReload = () => {
|
||||||
self.preRender();
|
this.preRender();
|
||||||
self.renderTab();
|
this.renderTab();
|
||||||
}
|
};
|
||||||
|
|
||||||
var self = this;
|
const data = {};
|
||||||
var data = {};
|
|
||||||
|
|
||||||
self.getViewStyles = function () {
|
this.getViewStyles = function () {
|
||||||
return 'Poster,PosterCard,Thumb,ThumbCard'.split(',');
|
return 'Poster,PosterCard,Thumb,ThumbCard'.split(',');
|
||||||
};
|
};
|
||||||
|
|
||||||
self.getCurrentViewStyle = function () {
|
this.getCurrentViewStyle = function () {
|
||||||
return getPageData().view;
|
return getPageData().view;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.setCurrentViewStyle = function (viewStyle) {
|
this.setCurrentViewStyle = function (viewStyle) {
|
||||||
getPageData().view = viewStyle;
|
getPageData().view = viewStyle;
|
||||||
libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle);
|
libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle);
|
||||||
fullyReload();
|
fullyReload();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.enableViewSelection = true;
|
this.enableViewSelection = true;
|
||||||
var promise;
|
let promise;
|
||||||
|
|
||||||
self.preRender = function () {
|
this.preRender = function () {
|
||||||
promise = getPromise();
|
promise = getPromise();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.renderTab = function () {
|
this.renderTab = function () {
|
||||||
reloadItems(tabContent, promise);
|
reloadItems(tabContent, promise);
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
/* eslint-enable indent */
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser', 'alphaPicker', 'listView', 'cardBuilder', 'globalize', 'emby-itemscontainer'], function (loading, layoutManager, userSettings, events, libraryBrowser, AlphaPicker, listView, cardBuilder, globalize) {
|
import loading from 'loading';
|
||||||
'use strict';
|
import * as userSettings from 'userSettings';
|
||||||
|
import events from 'events';
|
||||||
|
import libraryBrowser from 'libraryBrowser';
|
||||||
|
import AlphaPicker from 'alphaPicker';
|
||||||
|
import listView from 'listView';
|
||||||
|
import cardBuilder from 'cardBuilder';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'emby-itemscontainer';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
/* eslint-disable indent */
|
||||||
libraryBrowser = libraryBrowser.default || libraryBrowser;
|
|
||||||
|
|
||||||
return function (view, params, tabContent, options) {
|
export default function (view, params, tabContent, options) {
|
||||||
function onViewStyleChange() {
|
const onViewStyleChange = () => {
|
||||||
if (self.getCurrentViewStyle() == 'List') {
|
if (this.getCurrentViewStyle() == 'List') {
|
||||||
itemsContainer.classList.add('vertical-list');
|
itemsContainer.classList.add('vertical-list');
|
||||||
itemsContainer.classList.remove('vertical-wrap');
|
itemsContainer.classList.remove('vertical-wrap');
|
||||||
} else {
|
} else {
|
||||||
|
@ -15,13 +21,13 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
}
|
}
|
||||||
|
|
||||||
itemsContainer.innerHTML = '';
|
itemsContainer.innerHTML = '';
|
||||||
}
|
};
|
||||||
|
|
||||||
function updateFilterControls() {
|
const updateFilterControls = () => {
|
||||||
if (self.alphaPicker) {
|
if (this.alphaPicker) {
|
||||||
self.alphaPicker.value(query.NameStartsWithOrGreater);
|
this.alphaPicker.value(query.NameStartsWithOrGreater);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function fetchData() {
|
function fetchData() {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
@ -54,7 +60,7 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
updateFilterControls();
|
updateFilterControls();
|
||||||
var pagingHtml = libraryBrowser.getQueryPagingHtml({
|
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
||||||
startIndex: query.StartIndex,
|
startIndex: query.StartIndex,
|
||||||
limit: query.Limit,
|
limit: query.Limit,
|
||||||
totalRecordCount: result.TotalRecordCount,
|
totalRecordCount: result.TotalRecordCount,
|
||||||
|
@ -64,35 +70,30 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
sortButton: false,
|
sortButton: false,
|
||||||
filterButton: false
|
filterButton: false
|
||||||
});
|
});
|
||||||
var i;
|
|
||||||
var length;
|
|
||||||
var elems = tabContent.querySelectorAll('.paging');
|
|
||||||
|
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
for (const elem of tabContent.querySelectorAll('.paging')) {
|
||||||
elems[i].innerHTML = pagingHtml;
|
elem.innerHTML = pagingHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
for (const elem of tabContent.querySelectorAll('.btnNextPage')) {
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
elem.addEventListener('click', onNextPageClick);
|
||||||
elems[i].addEventListener('click', onNextPageClick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
for (const elem of tabContent.querySelectorAll('.btnPreviousPage')) {
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
elem.addEventListener('click', onPreviousPageClick);
|
||||||
elems[i].addEventListener('click', onPreviousPageClick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
loading.hide();
|
loading.hide();
|
||||||
|
|
||||||
require(['autoFocuser'], function (autoFocuser) {
|
import('autoFocuser').then(({default: autoFocuser}) => {
|
||||||
autoFocuser.autoFocus(tabContent);
|
autoFocuser.autoFocus(tabContent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getItemsHtml(items) {
|
const getItemsHtml = (items) => {
|
||||||
var html;
|
let html;
|
||||||
var viewStyle = self.getCurrentViewStyle();
|
const viewStyle = this.getCurrentViewStyle();
|
||||||
|
|
||||||
if (viewStyle == 'Thumb') {
|
if (viewStyle == 'Thumb') {
|
||||||
html = cardBuilder.getCardsHtml({
|
html = cardBuilder.getCardsHtml({
|
||||||
|
@ -156,22 +157,22 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
}
|
}
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
}
|
};
|
||||||
|
|
||||||
function initPage(tabContent) {
|
const initPage = (tabContent) => {
|
||||||
itemsContainer.fetchData = fetchData;
|
itemsContainer.fetchData = fetchData;
|
||||||
itemsContainer.getItemsHtml = getItemsHtml;
|
itemsContainer.getItemsHtml = getItemsHtml;
|
||||||
itemsContainer.afterRefresh = afterRefresh;
|
itemsContainer.afterRefresh = afterRefresh;
|
||||||
var alphaPickerElement = tabContent.querySelector('.alphaPicker');
|
let alphaPickerElement = tabContent.querySelector('.alphaPicker');
|
||||||
|
|
||||||
if (alphaPickerElement) {
|
if (alphaPickerElement) {
|
||||||
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
||||||
var newValue = e.detail.value;
|
let newValue = e.detail.value;
|
||||||
query.NameStartsWithOrGreater = newValue;
|
query.NameStartsWithOrGreater = newValue;
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
itemsContainer.refreshItems();
|
itemsContainer.refreshItems();
|
||||||
});
|
});
|
||||||
self.alphaPicker = new AlphaPicker.default({
|
this.alphaPicker = new AlphaPicker({
|
||||||
element: alphaPickerElement,
|
element: alphaPickerElement,
|
||||||
valueChangeEvent: 'click'
|
valueChangeEvent: 'click'
|
||||||
});
|
});
|
||||||
|
@ -181,14 +182,14 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
itemsContainer.classList.add('padded-right-withalphapicker');
|
itemsContainer.classList.add('padded-right-withalphapicker');
|
||||||
}
|
}
|
||||||
|
|
||||||
var btnFilter = tabContent.querySelector('.btnFilter');
|
const btnFilter = tabContent.querySelector('.btnFilter');
|
||||||
|
|
||||||
if (btnFilter) {
|
if (btnFilter) {
|
||||||
btnFilter.addEventListener('click', function () {
|
btnFilter.addEventListener('click', () => {
|
||||||
self.showFilterMenu();
|
this.showFilterMenu();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var btnSort = tabContent.querySelector('.btnSort');
|
const btnSort = tabContent.querySelector('.btnSort');
|
||||||
|
|
||||||
if (btnSort) {
|
if (btnSort) {
|
||||||
btnSort.addEventListener('click', function (e) {
|
btnSort.addEventListener('click', function (e) {
|
||||||
|
@ -231,24 +232,23 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var btnSelectView = tabContent.querySelector('.btnSelectView');
|
const btnSelectView = tabContent.querySelector('.btnSelectView');
|
||||||
btnSelectView.addEventListener('click', function (e) {
|
btnSelectView.addEventListener('click', function (e) {
|
||||||
libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
|
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle, 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
|
||||||
});
|
});
|
||||||
btnSelectView.addEventListener('layoutchange', function (e) {
|
btnSelectView.addEventListener('layoutchange', function (e) {
|
||||||
var viewStyle = e.detail.viewStyle;
|
let viewStyle = e.detail.viewStyle;
|
||||||
userSettings.set(savedViewKey, viewStyle);
|
userSettings.set(savedViewKey, viewStyle);
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
onViewStyleChange();
|
onViewStyleChange();
|
||||||
itemsContainer.refreshItems();
|
itemsContainer.refreshItems();
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
var self = this;
|
let itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||||
var itemsContainer = tabContent.querySelector('.itemsContainer');
|
const savedQueryKey = params.topParentId + '-' + options.mode;
|
||||||
var savedQueryKey = params.topParentId + '-' + options.mode;
|
const savedViewKey = savedQueryKey + '-view';
|
||||||
var savedViewKey = savedQueryKey + '-view';
|
let query = {
|
||||||
var query = {
|
|
||||||
SortBy: 'SortName,ProductionYear',
|
SortBy: 'SortName,ProductionYear',
|
||||||
SortOrder: 'Ascending',
|
SortOrder: 'Ascending',
|
||||||
IncludeItemTypes: 'Movie',
|
IncludeItemTypes: 'Movie',
|
||||||
|
@ -264,7 +264,7 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
query['Limit'] = userSettings.libraryPageSize();
|
query['Limit'] = userSettings.libraryPageSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
var isLoading = false;
|
let isLoading = false;
|
||||||
|
|
||||||
if (options.mode === 'favorites') {
|
if (options.mode === 'favorites') {
|
||||||
query.IsFavorite = true;
|
query.IsFavorite = true;
|
||||||
|
@ -272,14 +272,14 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
|
|
||||||
query = userSettings.loadQuerySettings(savedQueryKey, query);
|
query = userSettings.loadQuerySettings(savedQueryKey, query);
|
||||||
|
|
||||||
self.showFilterMenu = function () {
|
this.showFilterMenu = function () {
|
||||||
require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
|
import('components/filterdialog/filterdialog').then(({default: filterDialogFactory}) => {
|
||||||
var filterDialog = new filterDialogFactory({
|
let filterDialog = new filterDialogFactory({
|
||||||
query: query,
|
query: query,
|
||||||
mode: 'movies',
|
mode: 'movies',
|
||||||
serverId: ApiClient.serverId()
|
serverId: ApiClient.serverId()
|
||||||
});
|
});
|
||||||
events.on(filterDialog, 'filterchange', function () {
|
events.on(filterDialog, 'filterchange', () => {
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
itemsContainer.refreshItems();
|
itemsContainer.refreshItems();
|
||||||
});
|
});
|
||||||
|
@ -287,22 +287,23 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.getCurrentViewStyle = function () {
|
this.getCurrentViewStyle = function () {
|
||||||
return userSettings.get(savedViewKey) || 'Poster';
|
return userSettings.get(savedViewKey) || 'Poster';
|
||||||
};
|
};
|
||||||
|
|
||||||
self.initTab = function () {
|
this.initTab = function () {
|
||||||
initPage(tabContent);
|
initPage(tabContent);
|
||||||
onViewStyleChange();
|
onViewStyleChange();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.renderTab = function () {
|
this.renderTab = function () {
|
||||||
itemsContainer.refreshItems();
|
itemsContainer.refreshItems();
|
||||||
updateFilterControls();
|
updateFilterControls();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.destroy = function () {
|
this.destroy = function () {
|
||||||
itemsContainer = null;
|
itemsContainer = null;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
/* eslint-enable indent */
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu', 'mainTabsManager', 'cardBuilder', 'dom', 'imageLoader', 'playbackManager', 'globalize', 'emby-scroller', 'emby-itemscontainer', 'emby-tabs', 'emby-button'], function (events, layoutManager, inputManager, userSettings, libraryMenu, mainTabsManager, cardBuilder, dom, imageLoader, playbackManager, globalize) {
|
import events from 'events';
|
||||||
'use strict';
|
import layoutManager from 'layoutManager';
|
||||||
|
import inputManager from 'inputManager';
|
||||||
|
import * as userSettings from 'userSettings';
|
||||||
|
import libraryMenu from 'libraryMenu';
|
||||||
|
import * as mainTabsManager from 'mainTabsManager';
|
||||||
|
import cardBuilder from 'cardBuilder';
|
||||||
|
import dom from 'dom';
|
||||||
|
import imageLoader from 'imageLoader';
|
||||||
|
import playbackManager from 'playbackManager';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'emby-scroller';
|
||||||
|
import 'emby-itemscontainer';
|
||||||
|
import 'emby-tabs';
|
||||||
|
import 'emby-button';
|
||||||
|
|
||||||
playbackManager = playbackManager.default || playbackManager;
|
/* eslint-disable indent */
|
||||||
|
|
||||||
function enableScrollX() {
|
function enableScrollX() {
|
||||||
return !layoutManager.desktop;
|
return !layoutManager.desktop;
|
||||||
|
@ -16,7 +29,7 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadLatest(page, userId, parentId) {
|
function loadLatest(page, userId, parentId) {
|
||||||
var options = {
|
const options = {
|
||||||
IncludeItemTypes: 'Movie',
|
IncludeItemTypes: 'Movie',
|
||||||
Limit: 18,
|
Limit: 18,
|
||||||
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
|
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
|
||||||
|
@ -26,8 +39,8 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
EnableTotalRecordCount: false
|
EnableTotalRecordCount: false
|
||||||
};
|
};
|
||||||
ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
|
ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
|
||||||
var allowBottomPadding = !enableScrollX();
|
const allowBottomPadding = !enableScrollX();
|
||||||
var container = page.querySelector('#recentlyAddedItems');
|
const container = page.querySelector('#recentlyAddedItems');
|
||||||
cardBuilder.buildCards(items, {
|
cardBuilder.buildCards(items, {
|
||||||
itemsContainer: container,
|
itemsContainer: container,
|
||||||
shape: getPortraitShape(),
|
shape: getPortraitShape(),
|
||||||
|
@ -45,8 +58,8 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadResume(page, userId, parentId) {
|
function loadResume(page, userId, parentId) {
|
||||||
var screenWidth = dom.getWindowSize().innerWidth;
|
let screenWidth = dom.getWindowSize().innerWidth;
|
||||||
var options = {
|
const options = {
|
||||||
SortBy: 'DatePlayed',
|
SortBy: 'DatePlayed',
|
||||||
SortOrder: 'Descending',
|
SortOrder: 'Descending',
|
||||||
IncludeItemTypes: 'Movie',
|
IncludeItemTypes: 'Movie',
|
||||||
|
@ -67,8 +80,8 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
page.querySelector('#resumableSection').classList.add('hide');
|
page.querySelector('#resumableSection').classList.add('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
var allowBottomPadding = !enableScrollX();
|
const allowBottomPadding = !enableScrollX();
|
||||||
var container = page.querySelector('#resumableItems');
|
const container = page.querySelector('#resumableItems');
|
||||||
cardBuilder.buildCards(result.Items, {
|
cardBuilder.buildCards(result.Items, {
|
||||||
itemsContainer: container,
|
itemsContainer: container,
|
||||||
preferThumb: true,
|
preferThumb: true,
|
||||||
|
@ -88,8 +101,8 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRecommendationHtml(recommendation) {
|
function getRecommendationHtml(recommendation) {
|
||||||
var html = '';
|
let html = '';
|
||||||
var title = '';
|
let title = '';
|
||||||
|
|
||||||
switch (recommendation.RecommendationType) {
|
switch (recommendation.RecommendationType) {
|
||||||
case 'SimilarToRecentlyPlayed':
|
case 'SimilarToRecentlyPlayed':
|
||||||
|
@ -113,7 +126,7 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
|
|
||||||
html += '<div class="verticalSection">';
|
html += '<div class="verticalSection">';
|
||||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + title + '</h2>';
|
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + title + '</h2>';
|
||||||
var allowBottomPadding = true;
|
const allowBottomPadding = true;
|
||||||
|
|
||||||
if (enableScrollX()) {
|
if (enableScrollX()) {
|
||||||
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-mousewheel="false" data-centerfocus="true">';
|
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-mousewheel="false" data-centerfocus="true">';
|
||||||
|
@ -141,8 +154,8 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSuggestions(page, userId, parentId) {
|
function loadSuggestions(page, userId, parentId) {
|
||||||
var screenWidth = dom.getWindowSize().innerWidth;
|
let screenWidth = dom.getWindowSize().innerWidth;
|
||||||
var url = ApiClient.getUrl('Movies/Recommendations', {
|
let url = ApiClient.getUrl('Movies/Recommendations', {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
categoryLimit: 6,
|
categoryLimit: 6,
|
||||||
ItemLimit: screenWidth >= 1920 ? 8 : screenWidth >= 1600 ? 8 : screenWidth >= 1200 ? 6 : 5,
|
ItemLimit: screenWidth >= 1920 ? 8 : screenWidth >= 1600 ? 8 : screenWidth >= 1200 ? 6 : 5,
|
||||||
|
@ -157,9 +170,9 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var html = recommendations.map(getRecommendationHtml).join('');
|
const html = recommendations.map(getRecommendationHtml).join('');
|
||||||
page.querySelector('.noItemsMessage').classList.add('hide');
|
page.querySelector('.noItemsMessage').classList.add('hide');
|
||||||
var recs = page.querySelector('.recommendations');
|
let recs = page.querySelector('.recommendations');
|
||||||
recs.innerHTML = html;
|
recs.innerHTML = html;
|
||||||
imageLoader.lazyChildren(recs);
|
imageLoader.lazyChildren(recs);
|
||||||
|
|
||||||
|
@ -169,7 +182,7 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
}
|
}
|
||||||
|
|
||||||
function autoFocus(page) {
|
function autoFocus(page) {
|
||||||
require(['autoFocuser'], function (autoFocuser) {
|
import('autoFocuser').then(({default: autoFocuser}) => {
|
||||||
autoFocuser.autoFocus(page);
|
autoFocuser.autoFocus(page);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -195,17 +208,16 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSuggestedTab(page, tabContent) {
|
function initSuggestedTab(page, tabContent) {
|
||||||
var containers = tabContent.querySelectorAll('.itemsContainer');
|
const containers = tabContent.querySelectorAll('.itemsContainer');
|
||||||
|
|
||||||
for (var i = 0, length = containers.length; i < length; i++) {
|
for (const container of containers) {
|
||||||
setScrollClasses(containers[i], enableScrollX());
|
setScrollClasses(container, enableScrollX());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSuggestionsTab(view, params, tabContent) {
|
function loadSuggestionsTab(view, params, tabContent) {
|
||||||
var parentId = params.topParentId;
|
const parentId = params.topParentId;
|
||||||
var userId = ApiClient.getCurrentUserId();
|
const userId = ApiClient.getCurrentUserId();
|
||||||
console.debug('loadSuggestionsTab');
|
|
||||||
loadResume(tabContent, userId, parentId);
|
loadResume(tabContent, userId, parentId);
|
||||||
loadLatest(tabContent, userId, parentId);
|
loadLatest(tabContent, userId, parentId);
|
||||||
loadSuggestions(tabContent, userId, parentId);
|
loadSuggestions(tabContent, userId, parentId);
|
||||||
|
@ -224,9 +236,6 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
name: globalize.translate('TabCollections')
|
name: globalize.translate('TabCollections')
|
||||||
}, {
|
}, {
|
||||||
name: globalize.translate('TabGenres')
|
name: globalize.translate('TabGenres')
|
||||||
}, {
|
|
||||||
name: globalize.translate('ButtonSearch'),
|
|
||||||
cssClass: 'searchTabButton'
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,13 +258,13 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return function (view, params) {
|
export default function (view, params) {
|
||||||
function onBeforeTabChange(e) {
|
function onBeforeTabChange(e) {
|
||||||
preLoadTab(view, parseInt(e.detail.selectedTabIndex));
|
preLoadTab(view, parseInt(e.detail.selectedTabIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTabChange(e) {
|
function onTabChange(e) {
|
||||||
var newIndex = parseInt(e.detail.selectedTabIndex);
|
const newIndex = parseInt(e.detail.selectedTabIndex);
|
||||||
loadTab(view, newIndex);
|
loadTab(view, newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,52 +276,50 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
mainTabsManager.setTabs(view, currentTabIndex, getTabs, getTabContainers, onBeforeTabChange, onTabChange);
|
mainTabsManager.setTabs(view, currentTabIndex, getTabs, getTabContainers, onBeforeTabChange, onTabChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTabController(page, index, callback) {
|
const getTabController = (page, index, callback) => {
|
||||||
var depends = [];
|
let depends = '';
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
depends.push('controllers/movies/movies');
|
depends = 'controllers/movies/movies';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
|
depends = 'controllers/movies/moviesrecommended.js';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
depends.push('controllers/movies/movietrailers');
|
depends = 'controllers/movies/movietrailers';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
depends.push('controllers/movies/movies');
|
depends = 'controllers/movies/movies';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
depends.push('controllers/movies/moviecollections');
|
depends = 'controllers/movies/moviecollections';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
depends.push('controllers/movies/moviegenres');
|
depends = 'controllers/movies/moviegenres';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
|
||||||
depends.push('scripts/searchtab');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
require(depends, function (controllerFactory) {
|
import(depends).then(({default: controllerFactory}) => {
|
||||||
var tabContent;
|
let tabContent;
|
||||||
|
|
||||||
if (index === suggestionsTabIndex) {
|
if (index === suggestionsTabIndex) {
|
||||||
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
|
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
|
||||||
self.tabContent = tabContent;
|
this.tabContent = tabContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
var controller = tabControllers[index];
|
let controller = tabControllers[index];
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
|
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
|
||||||
|
|
||||||
if (index === suggestionsTabIndex) {
|
if (index === suggestionsTabIndex) {
|
||||||
controller = self;
|
controller = this;
|
||||||
} else if (index === 6) {
|
} else if (index === 6) {
|
||||||
controller = new controllerFactory(view, tabContent, {
|
controller = new controllerFactory(view, tabContent, {
|
||||||
collectionType: 'movies',
|
collectionType: 'movies',
|
||||||
|
@ -335,7 +342,7 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
|
|
||||||
callback(controller);
|
callback(controller);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function preLoadTab(page, index) {
|
function preLoadTab(page, index) {
|
||||||
getTabController(page, index, function (controller) {
|
getTabController(page, index, function (controller) {
|
||||||
|
@ -347,12 +354,12 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
|
|
||||||
function loadTab(page, index) {
|
function loadTab(page, index) {
|
||||||
currentTabIndex = index;
|
currentTabIndex = index;
|
||||||
getTabController(page, index, function (controller) {
|
getTabController(page, index, ((controller) => {
|
||||||
if (renderedTabs.indexOf(index) == -1) {
|
if (renderedTabs.indexOf(index) == -1) {
|
||||||
renderedTabs.push(index);
|
renderedTabs.push(index);
|
||||||
controller.renderTab();
|
controller.renderTab();
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPlaybackStop(e, state) {
|
function onPlaybackStop(e, state) {
|
||||||
|
@ -370,22 +377,21 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId));
|
||||||
var currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId));
|
const suggestionsTabIndex = 1;
|
||||||
var suggestionsTabIndex = 1;
|
|
||||||
|
|
||||||
self.initTab = function () {
|
this.initTab = function () {
|
||||||
var tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
let tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||||
initSuggestedTab(view, tabContent);
|
initSuggestedTab(view, tabContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.renderTab = function () {
|
this.renderTab = function () {
|
||||||
var tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
let tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||||
loadSuggestionsTab(view, params, tabContent);
|
loadSuggestionsTab(view, params, tabContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
var tabControllers = [];
|
let tabControllers = [];
|
||||||
var renderedTabs = [];
|
let renderedTabs = [];
|
||||||
view.addEventListener('viewshow', function (e) {
|
view.addEventListener('viewshow', function (e) {
|
||||||
initTabs();
|
initTabs();
|
||||||
if (!view.getAttribute('data-title')) {
|
if (!view.getAttribute('data-title')) {
|
||||||
|
@ -405,15 +411,14 @@ define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu'
|
||||||
events.on(playbackManager, 'playbackstop', onPlaybackStop);
|
events.on(playbackManager, 'playbackstop', onPlaybackStop);
|
||||||
inputManager.on(window, onInputCommand);
|
inputManager.on(window, onInputCommand);
|
||||||
});
|
});
|
||||||
view.addEventListener('viewbeforehide', function (e) {
|
view.addEventListener('viewbeforehide', function () {
|
||||||
inputManager.off(window, onInputCommand);
|
inputManager.off(window, onInputCommand);
|
||||||
});
|
});
|
||||||
view.addEventListener('viewdestroy', function (e) {
|
for (const tabController of tabControllers) {
|
||||||
tabControllers.forEach(function (t) {
|
if (tabController.destroy) {
|
||||||
if (t.destroy) {
|
tabController.destroy();
|
||||||
t.destroy();
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
|
||||||
};
|
/* eslint-enable indent */
|
||||||
});
|
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, AlphaPicker, listView, cardBuilder, userSettings, globalize) {
|
import loading from 'loading';
|
||||||
'use strict';
|
import events from 'events';
|
||||||
|
import libraryBrowser from 'libraryBrowser';
|
||||||
|
import imageLoader from 'imageLoader';
|
||||||
|
import AlphaPicker from 'alphaPicker';
|
||||||
|
import listView from 'listView';
|
||||||
|
import cardBuilder from 'cardBuilder';
|
||||||
|
import * as userSettings from 'userSettings';
|
||||||
|
import globalize from 'globalize';
|
||||||
|
import 'emby-itemscontainer';
|
||||||
|
|
||||||
loading = loading.default || loading;
|
/* eslint-disable indent */
|
||||||
libraryBrowser = libraryBrowser.default || libraryBrowser;
|
|
||||||
|
|
||||||
return function (view, params, tabContent) {
|
export default function (view, params, tabContent) {
|
||||||
function getPageData(context) {
|
function getPageData(context) {
|
||||||
var key = getSavedQueryKey(context);
|
const key = getSavedQueryKey(context);
|
||||||
var pageData = data[key];
|
let pageData = data[key];
|
||||||
|
|
||||||
if (!pageData) {
|
if (!pageData) {
|
||||||
pageData = data[key] = {
|
pageData = data[key] = {
|
||||||
|
@ -46,11 +53,11 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
|
||||||
return context.savedQueryKey;
|
return context.savedQueryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadItems() {
|
const reloadItems = () => {
|
||||||
loading.show();
|
loading.show();
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
var query = getQuery(tabContent);
|
const query = getQuery(tabContent);
|
||||||
ApiClient.getItems(ApiClient.getCurrentUserId(), query).then(function (result) {
|
ApiClient.getItems(ApiClient.getCurrentUserId(), query).then((result) => {
|
||||||
function onNextPageClick() {
|
function onNextPageClick() {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return;
|
return;
|
||||||
|
@ -75,7 +82,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
updateFilterControls(tabContent);
|
updateFilterControls(tabContent);
|
||||||
var pagingHtml = libraryBrowser.getQueryPagingHtml({
|
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
||||||
startIndex: query.StartIndex,
|
startIndex: query.StartIndex,
|
||||||
limit: query.Limit,
|
limit: query.Limit,
|
||||||
totalRecordCount: result.TotalRecordCount,
|
totalRecordCount: result.TotalRecordCount,
|
||||||
|
@ -85,8 +92,8 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
|
||||||
sortButton: false,
|
sortButton: false,
|
||||||
filterButton: false
|
filterButton: false
|
||||||
});
|
});
|
||||||
var html;
|
let html;
|
||||||
var viewStyle = self.getCurrentViewStyle();
|
const viewStyle = this.getCurrentViewStyle();
|
||||||
|
|
||||||
if (viewStyle == 'Thumb') {
|
if (viewStyle == 'Thumb') {
|
||||||
html = cardBuilder.getCardsHtml({
|
html = cardBuilder.getCardsHtml({
|
||||||
|
@ -142,22 +149,20 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var i;
|
let elems = tabContent.querySelectorAll('.paging');
|
||||||
var length;
|
|
||||||
var elems = tabContent.querySelectorAll('.paging');
|
|
||||||
|
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
for (const elem of elems) {
|
||||||
elems[i].innerHTML = pagingHtml;
|
elem.innerHTML = pagingHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
for (const elem of elems) {
|
||||||
elems[i].addEventListener('click', onNextPageClick);
|
elem.addEventListener('click', onNextPageClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||||
for (i = 0, length = elems.length; i < length; i++) {
|
for (const elem of elems) {
|
||||||
elems[i].addEventListener('click', onPreviousPageClick);
|
elem.addEventListener('click', onPreviousPageClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.Items.length) {
|
if (!result.Items.length) {
|
||||||
|
@ -169,27 +174,26 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemsContainer = tabContent.querySelector('.itemsContainer');
|
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||||
itemsContainer.innerHTML = html;
|
itemsContainer.innerHTML = html;
|
||||||
imageLoader.lazyChildren(itemsContainer);
|
imageLoader.lazyChildren(itemsContainer);
|
||||||
libraryBrowser.saveQueryValues(getSavedQueryKey(tabContent), query);
|
libraryBrowser.saveQueryValues(getSavedQueryKey(tabContent), query);
|
||||||
loading.hide();
|
loading.hide();
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function updateFilterControls(tabContent) {
|
const updateFilterControls = (tabContent) => {
|
||||||
var query = getQuery(tabContent);
|
const query = getQuery(tabContent);
|
||||||
self.alphaPicker.value(query.NameStartsWithOrGreater);
|
this.alphaPicker.value(query.NameStartsWithOrGreater);
|
||||||
}
|
};
|
||||||
|
|
||||||
var self = this;
|
const data = {};
|
||||||
var data = {};
|
let isLoading = false;
|
||||||
var isLoading = false;
|
|
||||||
|
|
||||||
self.showFilterMenu = function () {
|
this.showFilterMenu = function () {
|
||||||
require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
|
import('components/filterdialog/filterdialog').then(({default: filterDialogFactory}) => {
|
||||||
var filterDialog = new filterDialogFactory({
|
const filterDialog = new filterDialogFactory({
|
||||||
query: getQuery(tabContent),
|
query: getQuery(tabContent),
|
||||||
mode: 'movies',
|
mode: 'movies',
|
||||||
serverId: ApiClient.serverId()
|
serverId: ApiClient.serverId()
|
||||||
|
@ -202,21 +206,21 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.getCurrentViewStyle = function () {
|
this.getCurrentViewStyle = function () {
|
||||||
return getPageData(tabContent).view;
|
return getPageData(tabContent).view;
|
||||||
};
|
};
|
||||||
|
|
||||||
function initPage(tabContent) {
|
const initPage = (tabContent) => {
|
||||||
var alphaPickerElement = tabContent.querySelector('.alphaPicker');
|
const alphaPickerElement = tabContent.querySelector('.alphaPicker');
|
||||||
var itemsContainer = tabContent.querySelector('.itemsContainer');
|
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||||
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
||||||
var newValue = e.detail.value;
|
const newValue = e.detail.value;
|
||||||
var query = getQuery(tabContent);
|
const query = getQuery(tabContent);
|
||||||
query.NameStartsWithOrGreater = newValue;
|
query.NameStartsWithOrGreater = newValue;
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
reloadItems();
|
reloadItems();
|
||||||
});
|
});
|
||||||
self.alphaPicker = new AlphaPicker.default({
|
this.alphaPicker = new AlphaPicker({
|
||||||
element: alphaPickerElement,
|
element: alphaPickerElement,
|
||||||
valueChangeEvent: 'click'
|
valueChangeEvent: 'click'
|
||||||
});
|
});
|
||||||
|
@ -226,7 +230,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
|
||||||
itemsContainer.classList.add('padded-right-withalphapicker');
|
itemsContainer.classList.add('padded-right-withalphapicker');
|
||||||
|
|
||||||
tabContent.querySelector('.btnFilter').addEventListener('click', function () {
|
tabContent.querySelector('.btnFilter').addEventListener('click', function () {
|
||||||
self.showFilterMenu();
|
this.showFilterMenu();
|
||||||
});
|
});
|
||||||
tabContent.querySelector('.btnSort').addEventListener('click', function (e) {
|
tabContent.querySelector('.btnSort').addEventListener('click', function (e) {
|
||||||
libraryBrowser.showSortMenu({
|
libraryBrowser.showSortMenu({
|
||||||
|
@ -260,15 +264,16 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
|
||||||
button: e.target
|
button: e.target
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
initPage(tabContent);
|
initPage(tabContent);
|
||||||
|
|
||||||
self.renderTab = function () {
|
this.renderTab = function () {
|
||||||
reloadItems();
|
reloadItems();
|
||||||
updateFilterControls(tabContent);
|
updateFilterControls(tabContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.destroy = function () {};
|
this.destroy = function () {};
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
/* eslint-enable indent */
|
||||||
|
|
|
@ -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,6 +1,7 @@
|
||||||
define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', 'viewManager', 'libraryBrowser', 'appRouter', 'apphost', 'playbackManager', 'syncPlayManager', 'groupSelectionMenu', 'browser', 'globalize', 'scripts/imagehelper', 'paper-icon-button-light', 'material-icons', 'scrollStyles', 'flexStyles'], function (dom, layoutManager, inputManager, connectionManager, events, viewManager, libraryBrowser, appRouter, appHost, playbackManager, syncPlayManager, groupSelectionMenu, browser, globalize, imageHelper) {
|
define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', 'viewManager', 'libraryBrowser', 'appRouter', 'apphost', 'playbackManager', 'syncPlayManager', 'groupSelectionMenu', 'browser', 'globalize', 'scripts/imagehelper', 'paper-icon-button-light', 'material-icons', 'scrollStyles', 'flexStyles'], function (dom, layoutManager, inputManager, connectionManager, events, viewManager, libraryBrowser, appRouter, appHost, playbackManager, syncPlayManager, groupSelectionMenu, browser, globalize, imageHelper) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
viewManager = viewManager.default || viewManager;
|
||||||
playbackManager = playbackManager.default || playbackManager;
|
playbackManager = playbackManager.default || playbackManager;
|
||||||
browser = browser.default || browser;
|
browser = browser.default || browser;
|
||||||
|
|
||||||
|
@ -806,6 +807,8 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||||
navDrawerScrollContainer.addEventListener('click', onMainDrawerClick);
|
navDrawerScrollContainer.addEventListener('click', onMainDrawerClick);
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
require(['navdrawer'], function (navdrawer) {
|
require(['navdrawer'], function (navdrawer) {
|
||||||
|
navdrawer = navdrawer.default || navdrawer;
|
||||||
|
|
||||||
navDrawerInstance = new navdrawer(getNavDrawerOptions());
|
navDrawerInstance = new navdrawer(getNavDrawerOptions());
|
||||||
|
|
||||||
if (!layoutManager.tv) {
|
if (!layoutManager.tv) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -99,9 +99,9 @@
|
||||||
"DeleteUserConfirmation": "هل انت متاكد من انك تريد حذف هذا المستخدم ؟",
|
"DeleteUserConfirmation": "هل انت متاكد من انك تريد حذف هذا المستخدم ؟",
|
||||||
"DeviceAccessHelp": "هذه الميزة تنطبق حصرياً على الأجهزة التي يمكن التعرف عليها فردياً ولن تمنع المتصفح من الدخول عليها. ترشيح الوصول لأجهزة المستخدم ستمنع المستخدمين من استعمال الأجهزة الجديدة إلى أن يتم اعتمادهم من هنا.",
|
"DeviceAccessHelp": "هذه الميزة تنطبق حصرياً على الأجهزة التي يمكن التعرف عليها فردياً ولن تمنع المتصفح من الدخول عليها. ترشيح الوصول لأجهزة المستخدم ستمنع المستخدمين من استعمال الأجهزة الجديدة إلى أن يتم اعتمادهم من هنا.",
|
||||||
"DrmChannelsNotImported": "القنوات المجهزة بإدارة الحقوق الرقمية DRM لن تورّد.",
|
"DrmChannelsNotImported": "القنوات المجهزة بإدارة الحقوق الرقمية DRM لن تورّد.",
|
||||||
"EasyPasswordHelp": "الرمز الشخصي الميسرالخاص بك يمكنك من الاتصال إلى خادم مكتبتك، عبر تطبيقات أمبي على الأجهزة أو الدخول على حسابك في الشبكة الداخلية.",
|
"EasyPasswordHelp": "الرمز pin الميسر الخاص بك يستخدم للوصول بدون اتصل عبر التطبيقات المدعومة أو الدخول على حسابك في الشبكة الداخلية.",
|
||||||
"EnablePhotos": "عرض الصور",
|
"EnablePhotos": "عرض الصور",
|
||||||
"EnablePhotosHelp": "سيتم اكتشاف الصور وعرضها مع ملفات الوسائط الأخرى",
|
"EnablePhotosHelp": "سيتم اكتشاف الصور وعرضها مع ملفات الوسائط الأخرى.",
|
||||||
"ErrorAddingListingsToSchedulesDirect": "كان هناك خطأ في إضافة الاصطفاف لخدمة \"Schedules Direct\" الخاصة بك. خدمة \"Schedules Direct\" لا تسمح إلا بعدد محدود من الاصطفافات لكل حساب. قد تحتاج إلى تسجيل الدخول إلى موقع \"Schedules Direct\" لإزالة الاصطفافات الأخرى من حسابك قبل المتابعة.",
|
"ErrorAddingListingsToSchedulesDirect": "كان هناك خطأ في إضافة الاصطفاف لخدمة \"Schedules Direct\" الخاصة بك. خدمة \"Schedules Direct\" لا تسمح إلا بعدد محدود من الاصطفافات لكل حساب. قد تحتاج إلى تسجيل الدخول إلى موقع \"Schedules Direct\" لإزالة الاصطفافات الأخرى من حسابك قبل المتابعة.",
|
||||||
"ErrorAddingMediaPathToVirtualFolder": "كان هناك خطأ في إضافة مسار الوسائط. الرجاء التأكد من صحة المسار وأن خادم أمبي لديه صلاحية الوصول إلى الموقع.",
|
"ErrorAddingMediaPathToVirtualFolder": "كان هناك خطأ في إضافة مسار الوسائط. الرجاء التأكد من صحة المسار وأن خادم أمبي لديه صلاحية الوصول إلى الموقع.",
|
||||||
"ErrorAddingTunerDevice": "كان هناك خطأ في إضافة جهاز المولف. الرجاء التأكد من صلاحية الوصول إليه ثم عاود المحاولة.",
|
"ErrorAddingTunerDevice": "كان هناك خطأ في إضافة جهاز المولف. الرجاء التأكد من صلاحية الوصول إليه ثم عاود المحاولة.",
|
||||||
|
@ -111,7 +111,7 @@
|
||||||
"ErrorPleaseSelectLineup": "الرجاء اختيار اصطفاف ثم المحاولة مرة أخرى. إن لم تتوفر أية اصطفافات، فالرجاء التأكد من اسم المستخدم وكلمة المرور الخاصة بك، وتأكد من صحة رمزك البريدي.",
|
"ErrorPleaseSelectLineup": "الرجاء اختيار اصطفاف ثم المحاولة مرة أخرى. إن لم تتوفر أية اصطفافات، فالرجاء التأكد من اسم المستخدم وكلمة المرور الخاصة بك، وتأكد من صحة رمزك البريدي.",
|
||||||
"ErrorSavingTvProvider": "كان هناك خطأ في حفظ مزود التلفزة. الرجاء التأكد من صلاحية الوصول إليه ثم عاود المحاولة.",
|
"ErrorSavingTvProvider": "كان هناك خطأ في حفظ مزود التلفزة. الرجاء التأكد من صلاحية الوصول إليه ثم عاود المحاولة.",
|
||||||
"ExitFullscreen": "الخروج من الشاشة الكاملة",
|
"ExitFullscreen": "الخروج من الشاشة الكاملة",
|
||||||
"ExtractChapterImagesHelp": "استخلاص صور الأبواب سيسمح لتطبيقات أمبي أن تظهر لك قوائم تصويرية لتبويبات الأفلام. هذه العملية قد تكون بطيئة، وتستغل قدرة المعالج بشكل ملحوظ، وقد تحتاج إلى حيازة بضعة غيغابايتات من مساحة التخزين بشكل مؤقت. هذه المهمة تعمل خلال عملية استكشاف المقاطع المرئية، كما يمكن أن تحدد لتكون مهمة ليلية مجدولة. يمكنك جدولة العملية من قسم جدولة المهام. لا ينصح بتشغيل هذه المهمة خلال ساعات الذروة من دخول المستخدمين.",
|
"ExtractChapterImagesHelp": "استخلاص صور الفصول سيسمح للتطبيقات أن تظهر لك قوائم تصويرية لتبويبات الأفلام. هذه العملية قد تكون بطيئة، وتستغل موارد الجهاز بشكل ملحوظ، وقد تحتاج إلى حيازة بضعة غيغابايتات من مساحة التخزين بشكل مؤقت. هذه المهمة تعمل خلال عملية استكشاف المقاطع المرئية، كما يمكن أن تحدد لتكون مهمة ليلية مجدولة. يمكنك جدولة العملية من قسم جدولة المهام. لا ينصح بتشغيل هذه المهمة خلال ساعات الذروة من دخول المستخدمين.",
|
||||||
"FFmpegSavePathNotFound": "لم نستطع تحديد موقع ffmpeg باستخدام المسار الذي أدخلته. سوف نحتاج تطبيق FFprobe أيضاً ويجب أن يتواجد في نفس المكان. إن هذه الأجزاء تكون بالعادة محزومة معاً في نفس ملف الإنزال. الرجاء التأكد من المسار المدخل والمحاولة مرة أخرى.",
|
"FFmpegSavePathNotFound": "لم نستطع تحديد موقع ffmpeg باستخدام المسار الذي أدخلته. سوف نحتاج تطبيق FFprobe أيضاً ويجب أن يتواجد في نفس المكان. إن هذه الأجزاء تكون بالعادة محزومة معاً في نفس ملف الإنزال. الرجاء التأكد من المسار المدخل والمحاولة مرة أخرى.",
|
||||||
"FastForward": "التقديم السريع",
|
"FastForward": "التقديم السريع",
|
||||||
"FileNotFound": "الملف غير موجود.",
|
"FileNotFound": "الملف غير موجود.",
|
||||||
|
@ -129,7 +129,7 @@
|
||||||
"GuideProviderSelectListings": "إختر المبوبات",
|
"GuideProviderSelectListings": "إختر المبوبات",
|
||||||
"H264CrfHelp": "معامل المعدل الثابت CRF هو الجودة الافتراضية لإعدادات مشفر x264. بإمكانك إعطاء قيمة تتراوح بين 0 و 51، وكلما قلت القيمة فسينتج عن ذلك جودة أفضل (على حساب حجم تخزين أعلى). القيم المعقول تتراوح بين 18 و 28. الافتراضي لـ x264 هي 23، لذا فبإمكانك استخدام هذه القيمة كنقطة بداية.",
|
"H264CrfHelp": "معامل المعدل الثابت CRF هو الجودة الافتراضية لإعدادات مشفر x264. بإمكانك إعطاء قيمة تتراوح بين 0 و 51، وكلما قلت القيمة فسينتج عن ذلك جودة أفضل (على حساب حجم تخزين أعلى). القيم المعقول تتراوح بين 18 و 28. الافتراضي لـ x264 هي 23، لذا فبإمكانك استخدام هذه القيمة كنقطة بداية.",
|
||||||
"EncoderPresetHelp": "اختر قيمة أعلى لتحسين السرة والأداء وقيمة أقل لتحسين الجودة.",
|
"EncoderPresetHelp": "اختر قيمة أعلى لتحسين السرة والأداء وقيمة أقل لتحسين الجودة.",
|
||||||
"HardwareAccelerationWarning": "تمكين التسريع بعتاد الحاسوب قد يتسبب في عدم استقرار بعض أنواع الأنظمة. تأكد من أن نظام التشغيل الخاص بك محدث إلى آخر نسخة وأن سواقات الفيديو محدثة أيضاً. إذا واجهت أية صعوبات في تسغيل الفيديو بعد تمكين هذه الخاصية، فعليك إرجاع الإعداد إلى وضعية آلي.",
|
"HardwareAccelerationWarning": "تمكين التسريع بعتاد الحاسوب قد يتسبب في عدم استقرار بعض أنواع الأنظمة. تأكد من أن نظام التشغيل الخاص بك محدث إلى آخر نسخة وأن سواقات الفيديو محدثة أيضاً. إذا واجهت أية صعوبات في تسغيل الفيديو بعد تمكين هذه الخاصية، فعليك إرجاع الإعداد إلى وضعية بلا None.",
|
||||||
"HeaderAccessSchedule": "جدول الدخولات",
|
"HeaderAccessSchedule": "جدول الدخولات",
|
||||||
"HeaderAccessScheduleHelp": "إنشئ جدول دخولات لكي تتمكن من تحديد ساعات للدخول.",
|
"HeaderAccessScheduleHelp": "إنشئ جدول دخولات لكي تتمكن من تحديد ساعات للدخول.",
|
||||||
"HeaderActiveDevices": "الأجهزة المفعّلة",
|
"HeaderActiveDevices": "الأجهزة المفعّلة",
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
"HeaderAllowMediaDeletionFrom": "السماح بحذف الوسائط من قبل",
|
"HeaderAllowMediaDeletionFrom": "السماح بحذف الوسائط من قبل",
|
||||||
"HeaderApiKey": "مفتاح API",
|
"HeaderApiKey": "مفتاح API",
|
||||||
"HeaderApiKeys": "مفاتيح API",
|
"HeaderApiKeys": "مفاتيح API",
|
||||||
"HeaderApiKeysHelp": "التطبيقات الخارجية تحتاج أن تمتلك مفتاح api لكي تتصل بخادم أمبي. هذه المفاتيح تُصدر عن طريق تسجيل الدخول بحساب أمبي، أو عن طريق منح التطبيق مفتاحاً أصدر يدوياً.",
|
"HeaderApiKeysHelp": "التطبيقات الخارجية تحتاج أن تمتلك مفتاح api لكي تتصل بالخادم. هذه المفاتيح تُصدر عن طريق تسجيل الدخول بمستخدم عادي، أو عن طريق منح التطبيق مفتاحاً أصدر يدوياً.",
|
||||||
"HeaderApp": "التطبيق",
|
"HeaderApp": "التطبيق",
|
||||||
"HeaderAudioSettings": "إعدادات الصوت",
|
"HeaderAudioSettings": "إعدادات الصوت",
|
||||||
"HeaderBooks": "الكتب",
|
"HeaderBooks": "الكتب",
|
||||||
|
@ -232,7 +232,7 @@
|
||||||
"HeaderPreferredMetadataLanguage": "اللغة المفضلة لواصفات البيانات",
|
"HeaderPreferredMetadataLanguage": "اللغة المفضلة لواصفات البيانات",
|
||||||
"HeaderProfile": "الحساب",
|
"HeaderProfile": "الحساب",
|
||||||
"HeaderProfileInformation": "معلومات العريضة",
|
"HeaderProfileInformation": "معلومات العريضة",
|
||||||
"HeaderProfileServerSettingsHelp": "هذه القيم ستتحكم في كيفية تقديم شكل خادم أمبي في الجهاز",
|
"HeaderProfileServerSettingsHelp": "هذه القيم ستتحكم في كيفية تقديم شكل الخادم في للعملاء.",
|
||||||
"HeaderRecentlyPlayed": "تم تشغيله مؤخراً",
|
"HeaderRecentlyPlayed": "تم تشغيله مؤخراً",
|
||||||
"HeaderRecordingPostProcessing": "تطبيق ما-بعد-المعالجة للتسجيل",
|
"HeaderRecordingPostProcessing": "تطبيق ما-بعد-المعالجة للتسجيل",
|
||||||
"HeaderRemoteControl": "التحكم عن بعد",
|
"HeaderRemoteControl": "التحكم عن بعد",
|
||||||
|
@ -254,7 +254,7 @@
|
||||||
"HeaderSelectServerCachePath": "إختر مسار كاشة الخادم",
|
"HeaderSelectServerCachePath": "إختر مسار كاشة الخادم",
|
||||||
"HeaderSelectServerCachePathHelp": "تصفح أو أدخل المسار الذي ترغب أن يُستخدم كاشة لملفات الخادم. يجب أن يكون هذا المجلد قابل للكتابة فيه.",
|
"HeaderSelectServerCachePathHelp": "تصفح أو أدخل المسار الذي ترغب أن يُستخدم كاشة لملفات الخادم. يجب أن يكون هذا المجلد قابل للكتابة فيه.",
|
||||||
"HeaderSelectTranscodingPath": "إختر المسار المؤقت للتشفير البيني",
|
"HeaderSelectTranscodingPath": "إختر المسار المؤقت للتشفير البيني",
|
||||||
"HeaderSelectTranscodingPathHelp": "تصفح أو أدخل المسار الذي ترغب أن يُستخدم للملفات المؤقتة للتشفير البيني. يجب أن يكون هذا المجلد قابل للكتابة فيه.",
|
"HeaderSelectTranscodingPathHelp": "تصفح أو أدخل المسار الذي ترغب أن يُستخدم لملفات التشفير البيني. يجب أن يكون هذا المجلد قابل للكتابة فيه.",
|
||||||
"HeaderSendMessage": "أرسل رسالة",
|
"HeaderSendMessage": "أرسل رسالة",
|
||||||
"HeaderSeries": "المسلسلات",
|
"HeaderSeries": "المسلسلات",
|
||||||
"HeaderServerSettings": "إعدادات الخادم",
|
"HeaderServerSettings": "إعدادات الخادم",
|
||||||
|
@ -291,17 +291,17 @@
|
||||||
"HeaderXmlSettings": "إعدادات xml",
|
"HeaderXmlSettings": "إعدادات xml",
|
||||||
"HeaderYears": "السنوات",
|
"HeaderYears": "السنوات",
|
||||||
"HeadersFolders": "مجلدات",
|
"HeadersFolders": "مجلدات",
|
||||||
"ImportFavoriteChannelsHelp": "عند التفعيل، فقط القنوات التي علّمت في المفضلة على هذا المولف ستورد إلى النظام.",
|
"ImportFavoriteChannelsHelp": "فقط القنوات التي علّمت في المفضلة على جهاز المولف ستورد.",
|
||||||
"ImportMissingEpisodesHelp": "عند التمكين، المعلومات الناقصة للحلقات ستورّد إلى قاعدة بيانات أمبي وستعرض داخل المواسم والمسلسلات. قد تتسبب هذه بأوقات أطول بكثير عند تمشيط المكنبات.",
|
"ImportMissingEpisodesHelp": "المعلومات الناقصة للحلقات ستورّد إلى قاعدة بياناتك وستعرض داخل المواسم والمسلسلات. قد تتسبب هذه بأوقات أطول بكثير عند تمشيط المكتبات.",
|
||||||
"LabelAbortedByServerShutdown": "(تم إهماله بسبب عملية إغلاق الخادم)",
|
"LabelAbortedByServerShutdown": "(تم إهماله بسبب عملية إغلاق الخادم)",
|
||||||
"LabelAccessDay": "يوم الأسبوع:",
|
"LabelAccessDay": "يوم الأسبوع:",
|
||||||
"LabelAccessEnd": "تاريخ النهاية",
|
"LabelAccessEnd": "وقت النهاية:",
|
||||||
"LabelAccessStart": "تاريخ البداية",
|
"LabelAccessStart": "وقت البداية:",
|
||||||
"LabelAirDays": "أيام البث:",
|
"LabelAirDays": "أيام البث:",
|
||||||
"LabelAirTime": "وقت البث:",
|
"LabelAirTime": "وقت البث:",
|
||||||
"LabelAlbum": "الألبوم",
|
"LabelAlbum": "الألبوم:",
|
||||||
"LabelAlbumArtHelp": "PN المستخدمة في رسومات الألبوم، داخل سمة dlna:profileID في upnp:albumArtURI. بعض الأجهزة تحتاج قيمة محددة، مهما كان حجم الصورة.",
|
"LabelAlbumArtHelp": "PN المستخدمة في رسومات الألبوم، داخل سمة dlna:profileID في upnp:albumArtURI. بعض الأجهزة تحتاج قيمة محددة، مهما كان حجم الصورة.",
|
||||||
"LabelAlbumArtMaxHeight": "الارتفاع الأقصى لرسومات الألبوم",
|
"LabelAlbumArtMaxHeight": "الارتفاع الأقصى لرسومات الألبوم:",
|
||||||
"LabelAlbumArtMaxHeightHelp": "الدقة القصوى لرسومات الألبوم المظهّرة عبر سمة upnp:albumArtURI.",
|
"LabelAlbumArtMaxHeightHelp": "الدقة القصوى لرسومات الألبوم المظهّرة عبر سمة upnp:albumArtURI.",
|
||||||
"LabelAlbumArtMaxWidth": "العرض الأقصى لرسوم الألبوم:",
|
"LabelAlbumArtMaxWidth": "العرض الأقصى لرسوم الألبوم:",
|
||||||
"LabelAlbumArtMaxWidthHelp": "الدقة القصوى لرسومات الألبوم المظهّرة عبر سمة upnp:albumArtURI.",
|
"LabelAlbumArtMaxWidthHelp": "الدقة القصوى لرسومات الألبوم المظهّرة عبر سمة upnp:albumArtURI.",
|
||||||
|
@ -310,42 +310,42 @@
|
||||||
"LabelAll": "الجميع",
|
"LabelAll": "الجميع",
|
||||||
"LabelAllowHWTranscoding": "السماح بالتشفير البيني بعتاد الحاسب",
|
"LabelAllowHWTranscoding": "السماح بالتشفير البيني بعتاد الحاسب",
|
||||||
"LabelAppName": "اسم التطبيق",
|
"LabelAppName": "اسم التطبيق",
|
||||||
"LabelAppNameExample": "مثال: Sickbeard، NzbDrone",
|
"LabelAppNameExample": "مثال: Sickbeard، Sonarr",
|
||||||
"LabelArtists": "الفنانون:",
|
"LabelArtists": "الفنانون:",
|
||||||
"LabelArtistsHelp": "فصل الاستعمالات المتعددة ;",
|
"LabelArtistsHelp": "افصل بين الفنانين ب ; فاصلة منقوطة.",
|
||||||
"LabelAudioLanguagePreference": "اللغة المفضلة للصوت:",
|
"LabelAudioLanguagePreference": "اللغة المفضلة للصوت:",
|
||||||
"LabelBindToLocalNetworkAddress": "إربطه إلى عنوان شبكة محلي:",
|
"LabelBindToLocalNetworkAddress": "إربطه إلى عنوان شبكة محلي:",
|
||||||
"LabelBindToLocalNetworkAddressHelp": "هذا خياري. امتطي عنوان الآي بي المحلي لربطه بخادم http. إذا ترك فارغاً، فإن الخادم سيربطه بجميع العناوين المتاحة. تغيير هذه القيمة يتطلب إعادة تشغيل خادم أمبي.",
|
"LabelBindToLocalNetworkAddressHelp": "تجاوز عنوان الآي بي المحلي لربطه بخادم http. إذا ترك فارغاً، فإن الخادم سيربطه بجميع العناوين المتاحة. تغيير هذه القيمة يتطلب إعادة تشغيل خادم جيلليفن.",
|
||||||
"LabelBlastMessageInterval": "فترات بث رسالة قيد التشغيل (بالثواني)",
|
"LabelBlastMessageInterval": "فترات بث رسالة قيد التشغيل",
|
||||||
"LabelBlastMessageIntervalHelp": "يحدد الفترة بالثواني بين يث رسائل قيد التشغيل",
|
"LabelBlastMessageIntervalHelp": "يحدد الفترة بالثواني بين بث رسائل قيد التشغيل.",
|
||||||
"LabelCache": "ذاكرة الكاشة",
|
"LabelCache": "مَخبأ (كاش):",
|
||||||
"LabelCachePath": "مسار ذاكرة الكاشة:",
|
"LabelCachePath": "مسار ذاكرة الكاش:",
|
||||||
"LabelCachePathHelp": "حدد موقع مخصص لملفات كاشة الخادم، مثل الصور وغيرها. أترك هذه الخانة فارغة لاستعمال القيمة التلقائية.",
|
"LabelCachePathHelp": "حدد موقع مخصص لملفات الخادم المؤقتة، مثل الصور وغيرها. أترك هذه الخانة فارغة لاستعمال القيمة الافتراضية.",
|
||||||
"LabelCancelled": "تم الإلغاء",
|
"LabelCancelled": "تم الإلغاء",
|
||||||
"LabelCollection": "المجموعة",
|
"LabelCollection": "المجموعة:",
|
||||||
"LabelCommunityRating": "تقييم المجتمع:",
|
"LabelCommunityRating": "تقييم المجتمع:",
|
||||||
"LabelContentType": "نوع المحتوى",
|
"LabelContentType": "نوع المحتوى:",
|
||||||
"LabelCountry": "البلد:",
|
"LabelCountry": "البلد:",
|
||||||
"LabelCurrentPassword": "كلمة السر الحالية:",
|
"LabelCurrentPassword": "كلمة السر الحالية:",
|
||||||
"LabelCustomCertificatePath": "مسار شهادة ssl مخصص:",
|
"LabelCustomCertificatePath": "مسار شهادة SSL المخصص:",
|
||||||
"LabelCustomCertificatePathHelp": "مسار ملف PKCS # 12 يحتوي على شهادة ومفتاح خاص لتمكين دعم TLS على مجال مخصص.",
|
"LabelCustomCertificatePathHelp": "مسار ملف PKCS # 12 يحتوي على شهادة ومفتاح خاص لتمكين دعم TLS على مجال مخصص.",
|
||||||
"LabelCustomCss": "تنيسق CSS مخصوص:",
|
"LabelCustomCss": "تنيسق CSS مخصص:",
|
||||||
"LabelCustomCssHelp": "طبق تنسيق css مخصوصة لواجهة الويب.",
|
"LabelCustomCssHelp": "طبق تنسيقك css المخصص لواجهة الويب.",
|
||||||
"LabelCustomDeviceDisplayName": "اسم العرض:",
|
"LabelCustomDeviceDisplayName": "اسم العرض:",
|
||||||
"LabelCustomDeviceDisplayNameHelp": "أذكر اسم عرض مخصوص أو أتركه فارغاً لاستخدام",
|
"LabelCustomDeviceDisplayNameHelp": "أذكر اسم عرض مخصوص أو أتركه فارغاً لاستخدام الاسم المبلغ من الجهاز.",
|
||||||
"LabelDateAddedBehavior": "كيف يتصرف المحتوى الجديد نحو \"تاريخ الإضافة\" الخاص به:",
|
"LabelDateAddedBehavior": "كيف يتصرف المحتوى الجديد نحو \"تاريخ الإضافة\" الخاص به:",
|
||||||
"LabelDateAddedBehaviorHelp": "إذا استعرضت قيمة واصفات البيانا فإنها سوف تستخدم قبل أن تستخدم أي من هذه الخيارات.",
|
"LabelDateAddedBehaviorHelp": "إذا اخذت واصفات البيانات قيمة، فإنها سوف تستخدم قبل أن تستخدم أي من هذه الخيارات.",
|
||||||
"LabelDay": "اليوم:",
|
"LabelDay": "اليوم:",
|
||||||
"LabelDeathDate": "تاريخ الوفاة:",
|
"LabelDeathDate": "تاريخ الوفاة:",
|
||||||
"LabelDefaultUser": "المستخدم الافتراضي",
|
"LabelDefaultUser": "المستخدم الافتراضي:",
|
||||||
"LabelDefaultUserHelp": "لتحديد مكتبة المستخدم التي تظهر على الأجهزة المتصلة. بإمكان الامتطاء على هذه القيمة لكل جهاز عن طريق عرائض الأجهزة.",
|
"LabelDefaultUserHelp": "لتحديد مكتبة المستخدم التي تظهر على الأجهزة المتصلة. بإمكان الامتطاء على هذه القيمة لكل جهاز عن طريق عرائض الأجهزة.",
|
||||||
"LabelDeviceDescription": "وصف الجهاز",
|
"LabelDeviceDescription": "وصف الجهاز",
|
||||||
"LabelDidlMode": "طور didl:",
|
"LabelDidlMode": "طور DIDL:",
|
||||||
"LabelDisplayMissingEpisodesWithinSeasons": "أظهر الحلقات المفقودة في مجلدات المواسم",
|
"LabelDisplayMissingEpisodesWithinSeasons": "أظهر الحلقات المفقودة في مجلدات المواسم",
|
||||||
"LabelDisplayName": "الاسم المعروض:",
|
"LabelDisplayName": "الاسم المعروض:",
|
||||||
"LabelDisplaySpecialsWithinSeasons": "أظهر الحلقات الخاصة في المواسم التي بثت فيها",
|
"LabelDisplaySpecialsWithinSeasons": "أظهر الحلقات الخاصة في المواسم التي بثت فيها",
|
||||||
"LabelDownMixAudioScale": "تعزيز الصوت عند تقليل توزيع قنوات الصوت:",
|
"LabelDownMixAudioScale": "تعزيز الصوت عند تقليل توزيع قنوات الصوت:",
|
||||||
"LabelDownMixAudioScaleHelp": "تعزيز الصوت عند تقليل توزيع قنوات الصوت. حدد القيمة بـ 1 للمحافظة على القيمة الأصلية للصوت.",
|
"LabelDownMixAudioScaleHelp": "تعزيز الصوت عند تقليل توزيع قنوات الصوت. حدد القيمة ب 1 للمحافظة على القيمة الأصلية للصوت.",
|
||||||
"LabelDownloadLanguages": "إنزال اللغة:",
|
"LabelDownloadLanguages": "إنزال اللغة:",
|
||||||
"LabelDynamicExternalId": "معرفة {0}:",
|
"LabelDynamicExternalId": "معرفة {0}:",
|
||||||
"LabelEasyPinCode": "الرمز الشخصي الميسر:",
|
"LabelEasyPinCode": "الرمز الشخصي الميسر:",
|
||||||
|
@ -354,8 +354,8 @@
|
||||||
"LabelEnableAutomaticPortMap": "فعل الخاصية الآلية في التوفيق بين المنافذ",
|
"LabelEnableAutomaticPortMap": "فعل الخاصية الآلية في التوفيق بين المنافذ",
|
||||||
"LabelEnableAutomaticPortMapHelp": "حاول التوفيق بين المنفذ العالمي والمنفذ المحلي آلياً باستخدام آلية UPnP. هذه الخاصية قد لا تعمل مع بعض أنواع الراوترات.",
|
"LabelEnableAutomaticPortMapHelp": "حاول التوفيق بين المنفذ العالمي والمنفذ المحلي آلياً باستخدام آلية UPnP. هذه الخاصية قد لا تعمل مع بعض أنواع الراوترات.",
|
||||||
"LabelEnableBlastAliveMessages": "بث رسائل قيد التشغيل",
|
"LabelEnableBlastAliveMessages": "بث رسائل قيد التشغيل",
|
||||||
"LabelEnableBlastAliveMessagesHelp": "فعل هذه الخاصية إذا كان الخادم لا يكتشف بكفاءة من قبل أجهزة UPnP الأخرى على شبكتك",
|
"LabelEnableBlastAliveMessagesHelp": "فعل هذه الخاصية إذا كان الخادم لا يكتشف بكفاءة من قبل أجهزة UPnP الأخرى على شبكتك.",
|
||||||
"LabelEnableDlnaClientDiscoveryInterval": "فترات استكشاف العملاء (بالثواني)",
|
"LabelEnableDlnaClientDiscoveryInterval": "فترات استكشاف العملاء",
|
||||||
"LabelEnableDlnaClientDiscoveryIntervalHelp": "يحدد الفترة بالثواني بين عمليات بحث SSDP التي يقوم بها أمبي.",
|
"LabelEnableDlnaClientDiscoveryIntervalHelp": "يحدد الفترة بالثواني بين عمليات بحث SSDP التي يقوم بها أمبي.",
|
||||||
"LabelEnableDlnaDebugLogging": "تفعيل خاصية كشوفات أخطاء DLNA",
|
"LabelEnableDlnaDebugLogging": "تفعيل خاصية كشوفات أخطاء DLNA",
|
||||||
"LabelEnableDlnaDebugLoggingHelp": "هذه ستنشئ سجلات كشفية ضخمة ولا ينبغي تفعيلها إلا عند الحاجة إليها بغرض استكشاف الأخطاء وحصرها.",
|
"LabelEnableDlnaDebugLoggingHelp": "هذه ستنشئ سجلات كشفية ضخمة ولا ينبغي تفعيلها إلا عند الحاجة إليها بغرض استكشاف الأخطاء وحصرها.",
|
||||||
|
@ -930,7 +930,7 @@
|
||||||
"Backdrops": "خلفيات متغيرة للصفحة",
|
"Backdrops": "خلفيات متغيرة للصفحة",
|
||||||
"Backdrop": "خلفية متغيرة للصفحة",
|
"Backdrop": "خلفية متغيرة للصفحة",
|
||||||
"Auto": "تلقائي",
|
"Auto": "تلقائي",
|
||||||
"AuthProviderHelp": "حدد مقدم المصادقات ليتم استخدامه لمصادقة كلمة مرور هذا المستخدم.",
|
"AuthProviderHelp": "اختار مقدم المصادقة ليتم استخدامه لمصادقة كلمة مرور هذا المستخدم.",
|
||||||
"AroundTime": "حول",
|
"AroundTime": "حول",
|
||||||
"AttributeNew": "جديد",
|
"AttributeNew": "جديد",
|
||||||
"AspectRatio": "نسبة العرض الى الارتفاع",
|
"AspectRatio": "نسبة العرض الى الارتفاع",
|
||||||
|
@ -1038,7 +1038,7 @@
|
||||||
"Director": "المخرج",
|
"Director": "المخرج",
|
||||||
"DirectPlaying": "بث بدون تحويل الصيغة",
|
"DirectPlaying": "بث بدون تحويل الصيغة",
|
||||||
"DirectStreaming": "البث المباشر",
|
"DirectStreaming": "البث المباشر",
|
||||||
"DirectStreamHelp2": "البث المباشر للملف يستخدم طاقة معالجة قليلة جدًا دون أي خسارة في جودة الفيديو.",
|
"DirectStreamHelp2": "البث المباشر للملف يستخدم قوة معالجة قليلة جدًا دون أي خسارة في جودة الفيديو.",
|
||||||
"DirectStreamHelp1": "الوسائط متوافقة مع الجهاز فيما يتعلق بالدقة ونوع الوسائط (H.264 ، AC3 ، إلخ) ، ولكنها في حاوية ملفات غير متوافقة (mkv ، avi ، wmv ، إلخ). سيتم إعادة حزم الفيديو في الوقت الحقيقي قبل بثه إلى الجهاز.",
|
"DirectStreamHelp1": "الوسائط متوافقة مع الجهاز فيما يتعلق بالدقة ونوع الوسائط (H.264 ، AC3 ، إلخ) ، ولكنها في حاوية ملفات غير متوافقة (mkv ، avi ، wmv ، إلخ). سيتم إعادة حزم الفيديو في الوقت الحقيقي قبل بثه إلى الجهاز.",
|
||||||
"DetectingDevices": "يتم الكشف عن الأجهزة",
|
"DetectingDevices": "يتم الكشف عن الأجهزة",
|
||||||
"Desktop": "سطح المكتب",
|
"Desktop": "سطح المكتب",
|
||||||
|
@ -1139,5 +1139,51 @@
|
||||||
"Dislike": "لم يعجبنى",
|
"Dislike": "لم يعجبنى",
|
||||||
"ButtonSyncPlay": "SyncPlay",
|
"ButtonSyncPlay": "SyncPlay",
|
||||||
"ExtraLarge": "كبير جدا",
|
"ExtraLarge": "كبير جدا",
|
||||||
"EnableNextVideoInfoOverlayHelp": "في نهاية الفيديو, عرض معلومات عن الفيديو القادم في قائمة التشغيل."
|
"EnableNextVideoInfoOverlayHelp": "في نهاية الفيديو, عرض معلومات عن الفيديو القادم في قائمة التشغيل.",
|
||||||
|
"LabelDroppedFrames": "الاطارات الساقطة:",
|
||||||
|
"LabelDropImageHere": "اسقط صورة هنا، او ضغط تصفح.",
|
||||||
|
"LabelDisplayOrder": "ترتيب المعروض:",
|
||||||
|
"LabelDisplayMode": "وضع المعروض:",
|
||||||
|
"LabelDisplayLanguageHelp": "ترجمة جيلليفين هو مشروع مستمر.",
|
||||||
|
"LabelDisplayLanguage": "لغة العرض:",
|
||||||
|
"LabelDiscNumber": "رقم القرص:",
|
||||||
|
"LabelDeinterlaceMethod": "طريقة تقليل التشابك:",
|
||||||
|
"LabelDefaultScreen": "الشاشة الافتراضية:",
|
||||||
|
"LabelDateTimeLocale": "وقت و تاريخ محلي:",
|
||||||
|
"LabelDateAdded": "تاريخ الاضافة:",
|
||||||
|
"LabelCustomRating": "تقييم مخصص:",
|
||||||
|
"LabelCriticRating": "تقييم النقاد:",
|
||||||
|
"LabelCorruptedFrames": "الإطارات التالفة:",
|
||||||
|
"LabelChannels": "القنوات:",
|
||||||
|
"LabelCertificatePasswordHelp": "اذا تطلبت شهادتك الامنية كلمة مرور، من فضلك ادخلها هنا.",
|
||||||
|
"LabelCertificatePassword": "كلمة مرور الشهادة الامنية:",
|
||||||
|
"LabelBurnSubtitles": "الترجمات المحروقة:",
|
||||||
|
"LabelBlockContentWithTags": "احجب العناصر بالعلامات:",
|
||||||
|
"LabelBitrate": "معدل البت:",
|
||||||
|
"LabelBirthYear": "عام الميلاد:",
|
||||||
|
"LabelBirthDate": "تاريخ الميلاد:",
|
||||||
|
"LabelAutomaticallyRefreshInternetMetadataEvery": "حدث وصف البيانات تلقائيا من الانترنت:",
|
||||||
|
"LabelAuthProvider": "مقدم التصديق:",
|
||||||
|
"LabelAudioSampleRate": "سرعة معينة الصوت:",
|
||||||
|
"LabelAudioCodec": "ترميز الصوت:",
|
||||||
|
"LabelAudioChannels": "قنوات الصوت:",
|
||||||
|
"LabelAudioBitrate": "معدل بث الصوت:",
|
||||||
|
"LabelAudioBitDepth": "عمق بث الصوت:",
|
||||||
|
"LabelAudio": "الصوت",
|
||||||
|
"LabelAllowedRemoteAddressesMode": "وضع مرشح عنوان المضيف IP البعيد:",
|
||||||
|
"LabelAllowedRemoteAddresses": "مرشح عنوان المضيف IP البعيد:",
|
||||||
|
"LabelAirsBeforeSeason": "عروض بث قبل الموسم:",
|
||||||
|
"LabelAirsBeforeEpisode": "عروض بث قبل الحلقة:",
|
||||||
|
"LabelAirsAfterSeason": "عروض بث بعد الموسم:",
|
||||||
|
"Label3DFormat": "صيغة ثلاثية الابعاد:",
|
||||||
|
"Kids": "اطفال",
|
||||||
|
"Items": "عناصر",
|
||||||
|
"ItemCount": "{0} عنصر",
|
||||||
|
"InstantMix": "خلط فوري",
|
||||||
|
"HeaderSyncPlayEnabled": "تزامن اللعب ممكَّن",
|
||||||
|
"HeaderSyncPlaySelectGroup": "انضم لمجموعة",
|
||||||
|
"EnableDetailsBannerHelp": "اظهر صوره اللافته اعلى عنصر تفاصيل الصفحة.",
|
||||||
|
"EnableDetailsBanner": "لافتة التفاصيل",
|
||||||
|
"EnableDecodingColorDepth10Vp9": "تمكين ترميز ال10 بت عبر العتاد الصلب من اجل VP9",
|
||||||
|
"EnableDecodingColorDepth10Hevc": "تمكين ترميز ال10 بت عبر العتاد الصلب من اجل HEVC"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -471,7 +471,7 @@
|
||||||
"TabTrailers": "טריילרים",
|
"TabTrailers": "טריילרים",
|
||||||
"TabTranscoding": "קידוד",
|
"TabTranscoding": "קידוד",
|
||||||
"TabUpcoming": "בקרוב",
|
"TabUpcoming": "בקרוב",
|
||||||
"Tags": "תגים",
|
"Tags": "מילות מפתח",
|
||||||
"TellUsAboutYourself": "ספר לנו על עצמך",
|
"TellUsAboutYourself": "ספר לנו על עצמך",
|
||||||
"ThisWizardWillGuideYou": "אשף זה יעזור לך בהתליך ההתקנה.",
|
"ThisWizardWillGuideYou": "אשף זה יעזור לך בהתליך ההתקנה.",
|
||||||
"Thursday": "חמישי",
|
"Thursday": "חמישי",
|
||||||
|
@ -588,7 +588,7 @@
|
||||||
"MessageConfirmRestart": "האם אתה בטוח שברצונך לאתחל את שרת ה-Jellyfin?",
|
"MessageConfirmRestart": "האם אתה בטוח שברצונך לאתחל את שרת ה-Jellyfin?",
|
||||||
"HeaderThisUserIsCurrentlyDisabled": "משתמש זה אינו פעיל כרגע",
|
"HeaderThisUserIsCurrentlyDisabled": "משתמש זה אינו פעיל כרגע",
|
||||||
"HeaderTaskTriggers": "טריגרים של המשימה",
|
"HeaderTaskTriggers": "טריגרים של המשימה",
|
||||||
"HeaderTags": "תגיות",
|
"HeaderTags": "מילות מפתח",
|
||||||
"HeaderStopRecording": "עצור הקלטה",
|
"HeaderStopRecording": "עצור הקלטה",
|
||||||
"HeaderSortOrder": "סדר מיון",
|
"HeaderSortOrder": "סדר מיון",
|
||||||
"HeaderSortBy": "מיין לפי",
|
"HeaderSortBy": "מיין לפי",
|
||||||
|
@ -867,5 +867,7 @@
|
||||||
"OptionEveryday": "כל יום",
|
"OptionEveryday": "כל יום",
|
||||||
"OptionEnableExternalContentInSuggestions": "הפעל תוכן חיצוני בהמלצות",
|
"OptionEnableExternalContentInSuggestions": "הפעל תוכן חיצוני בהמלצות",
|
||||||
"OptionEnableAccessToAllLibraries": "אפשר גישה לכל הספריות",
|
"OptionEnableAccessToAllLibraries": "אפשר גישה לכל הספריות",
|
||||||
"OptionEnableAccessToAllChannels": "אפשר גישה לכל הערוצים"
|
"OptionEnableAccessToAllChannels": "אפשר גישה לכל הערוצים",
|
||||||
|
"HeaderSyncPlaySelectGroup": "הצטרף לקבוצה",
|
||||||
|
"TabUsers": "משתמשים"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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