mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
merge branch master into standalone
This commit is contained in:
commit
fa1483d3c0
195 changed files with 7490 additions and 3044 deletions
|
@ -16,6 +16,9 @@
|
|||
</div>
|
||||
|
||||
<div style="margin-top:1em;">
|
||||
<button is="emby-button" type="button" class="raised btnRefresh">
|
||||
<span>${ButtonScanAllLibraries}</span>
|
||||
</button>
|
||||
<button is="emby-button" type="button" id="btnRestartServer" class="raised" onclick="DashboardPage.restart(this);" style="margin-left:0;">
|
||||
<span>${Restart}</span>
|
||||
</button>
|
||||
|
|
|
@ -3,6 +3,7 @@ import events from 'events';
|
|||
import itemHelper from 'itemHelper';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import dom from 'dom';
|
||||
import taskButton from 'scripts/taskbutton';
|
||||
import globalize from 'globalize';
|
||||
import * as datefns from 'date-fns';
|
||||
import dfnshelper from 'dfnshelper';
|
||||
|
@ -550,13 +551,13 @@ import 'emby-itemscontainer';
|
|||
row.classList.remove('playingSession');
|
||||
}
|
||||
|
||||
if (session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1 && session.DeviceId !== window.connectionManager.deviceId()) {
|
||||
if (session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1) {
|
||||
row.querySelector('.btnSessionSendMessage').classList.remove('hide');
|
||||
} else {
|
||||
row.querySelector('.btnSessionSendMessage').classList.add('hide');
|
||||
}
|
||||
|
||||
if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons.length) {
|
||||
if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo) {
|
||||
row.querySelector('.btnSessionInfo').classList.remove('hide');
|
||||
} else {
|
||||
row.querySelector('.btnSessionInfo').classList.add('hide');
|
||||
|
@ -564,7 +565,7 @@ import 'emby-itemscontainer';
|
|||
|
||||
const btnSessionPlayPause = row.querySelector('.btnSessionPlayPause');
|
||||
|
||||
if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl && session.DeviceId !== window.connectionManager.deviceId()) {
|
||||
if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl) {
|
||||
btnSessionPlayPause.classList.remove('hide');
|
||||
row.querySelector('.btnSessionStop').classList.remove('hide');
|
||||
} else {
|
||||
|
@ -827,9 +828,17 @@ import 'emby-itemscontainer';
|
|||
refreshActiveRecordings(view, apiClient);
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
taskButton({
|
||||
mode: 'on',
|
||||
taskKey: 'RefreshLibrary',
|
||||
button: page.querySelector('.btnRefresh')
|
||||
});
|
||||
});
|
||||
view.addEventListener('viewbeforehide', function () {
|
||||
const apiClient = ApiClient;
|
||||
const page = this;
|
||||
|
||||
events.off(serverNotifications, 'RestartRequired', onRestartRequired);
|
||||
events.off(serverNotifications, 'ServerShuttingDown', onServerShuttingDown);
|
||||
events.off(serverNotifications, 'ServerRestarting', onServerRestarting);
|
||||
|
@ -841,6 +850,12 @@ import 'emby-itemscontainer';
|
|||
if (apiClient) {
|
||||
DashboardPage.stopInterval(apiClient);
|
||||
}
|
||||
|
||||
taskButton({
|
||||
mode: 'off',
|
||||
taskKey: 'RefreshLibrary',
|
||||
button: page.querySelector('.btnRefresh')
|
||||
});
|
||||
});
|
||||
view.addEventListener('viewdestroy', function () {
|
||||
const page = this;
|
||||
|
|
|
@ -31,6 +31,11 @@
|
|||
<div class="fieldDescription">${LabelVaapiDeviceHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer hide fldOpenclDevice">
|
||||
<input is="emby-input" type="text" id="txtOpenclDevice" label="${LabelOpenclDevice}" />
|
||||
<div class="fieldDescription">${LabelOpenclDeviceHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="hardwareAccelerationOptions hide">
|
||||
<div class="checkboxListContainer decodingCodecsList">
|
||||
<h3 class="checkboxListLabel">${LabelEnableHardwareDecodingFor}</h3>
|
||||
|
@ -89,6 +94,54 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tonemappingOptions hide">
|
||||
<div class="checkboxListContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkTonemapping" />
|
||||
<span>${EnableTonemapping}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${AllowTonemappingHelp}</div>
|
||||
</div>
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectTonemappingAlgorithm" label="${LabelTonemappingAlgorithm}">
|
||||
<option value="none">None</option>
|
||||
<option value="clip">Clip</option>
|
||||
<option value="linear">Linear</option>
|
||||
<option value="gamma">Gamma</option>
|
||||
<option value="reinhard">Reinhard</option>
|
||||
<option value="hable">Hable</option>
|
||||
<option value="mobius">Mobius</option>
|
||||
</select>
|
||||
<div class="fieldDescription">
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="button-link" href="http://ffmpeg.org/ffmpeg-all.html#tonemap_005fopencl" target="_blank">${TonemappingAlgorithmHelp}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectTonemappingRange" label="${LabelTonemappingRange}">
|
||||
<option value="auto">${Auto}</option>
|
||||
<option value="tv">TV</option>
|
||||
<option value="pc">PC</option>
|
||||
</select>
|
||||
<div class="fieldDescription">${TonemappingRangeHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" id="txtTonemappingDesat" pattern="[0-9]*" min="0" max="1.79769e+308" step=".00001" label="${LabelTonemappingDesat}" />
|
||||
<div class="fieldDescription">${LabelTonemappingDesatHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" id="txtTonemappingThreshold" pattern="[0-9]*" min="0" max="1.79769e+308" step=".00001" label="${LabelTonemappingThreshold}" />
|
||||
<div class="fieldDescription">${LabelTonemappingThresholdHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" id="txtTonemappingPeak" pattern="[0-9]*" min="0" max="1.79769e+308" step=".00001" label="${LabelTonemappingPeak}" />
|
||||
<div class="fieldDescription">${LabelTonemappingPeakHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" id="txtTonemappingParam" pattern="[0-9]*" min="2.22507e-308" max="1.79769e+308" step=".00001" label="${LabelTonemappingParam}" />
|
||||
<div class="fieldDescription">${LabelTonemappingParamHelp}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectThreadCount" label="${LabelTranscodingThreadCount}">
|
||||
<option value="-1">${Auto}</option>
|
||||
|
@ -129,6 +182,10 @@
|
|||
<input is="emby-input" type="number" id="txtDownMixAudioBoost" pattern="[0-9]*" required="required" min=".5" max="3" step=".1" label="${LabelDownMixAudioScale}" />
|
||||
<div class="fieldDescription">${LabelDownMixAudioScaleHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" id="txtMaxMuxingQueueSize" pattern="[0-9]*" required="required" min="128" max="2147483647" step="1" label="${LabelMaxMuxingQueueSize}" />
|
||||
<div class="fieldDescription">${LabelMaxMuxingQueueSizeHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectEncoderPreset" label="${LabelEncoderPreset}">
|
||||
|
|
|
@ -16,9 +16,18 @@ import libraryMenu from 'libraryMenu';
|
|||
$('#selectVideoDecoder', page).val(config.HardwareAccelerationType);
|
||||
$('#selectThreadCount', page).val(config.EncodingThreadCount);
|
||||
$('#txtDownMixAudioBoost', page).val(config.DownMixAudioBoost);
|
||||
page.querySelector('#txtMaxMuxingQueueSize').value = config.MaxMuxingQueueSize || '';
|
||||
page.querySelector('.txtEncoderPath').value = config.EncoderAppPathDisplay || '';
|
||||
$('#txtTranscodingTempPath', page).val(systemInfo.TranscodingTempPath || '');
|
||||
$('#txtVaapiDevice', page).val(config.VaapiDevice || '');
|
||||
page.querySelector('#chkTonemapping').checked = config.EnableTonemapping;
|
||||
page.querySelector('#txtOpenclDevice').value = config.OpenclDevice || '';
|
||||
page.querySelector('#selectTonemappingAlgorithm').value = config.TonemappingAlgorithm;
|
||||
page.querySelector('#selectTonemappingRange').value = config.TonemappingRange;
|
||||
page.querySelector('#txtTonemappingDesat').value = config.TonemappingDesat;
|
||||
page.querySelector('#txtTonemappingThreshold').value = config.TonemappingThreshold;
|
||||
page.querySelector('#txtTonemappingPeak').value = config.TonemappingPeak;
|
||||
page.querySelector('#txtTonemappingParam').value = config.TonemappingParam || '';
|
||||
page.querySelector('#selectEncoderPreset').value = config.EncoderPreset || '';
|
||||
page.querySelector('#txtH264Crf').value = config.H264Crf || '';
|
||||
page.querySelector('#selectDeinterlaceMethod').value = config.DeinterlaceMethod || '';
|
||||
|
@ -62,10 +71,19 @@ import libraryMenu from 'libraryMenu';
|
|||
loading.show();
|
||||
ApiClient.getNamedConfiguration('encoding').then(function (config) {
|
||||
config.DownMixAudioBoost = $('#txtDownMixAudioBoost', form).val();
|
||||
config.MaxMuxingQueueSize = form.querySelector('#txtMaxMuxingQueueSize').value;
|
||||
config.TranscodingTempPath = $('#txtTranscodingTempPath', form).val();
|
||||
config.EncodingThreadCount = $('#selectThreadCount', form).val();
|
||||
config.HardwareAccelerationType = $('#selectVideoDecoder', form).val();
|
||||
config.VaapiDevice = $('#txtVaapiDevice', form).val();
|
||||
config.OpenclDevice = form.querySelector('#txtOpenclDevice').value;
|
||||
config.EnableTonemapping = form.querySelector('#chkTonemapping').checked;
|
||||
config.TonemappingAlgorithm = form.querySelector('#selectTonemappingAlgorithm').value;
|
||||
config.TonemappingRange = form.querySelector('#selectTonemappingRange').value;
|
||||
config.TonemappingDesat = form.querySelector('#txtTonemappingDesat').value;
|
||||
config.TonemappingThreshold = form.querySelector('#txtTonemappingThreshold').value;
|
||||
config.TonemappingPeak = form.querySelector('#txtTonemappingPeak').value;
|
||||
config.TonemappingParam = form.querySelector('#txtTonemappingParam').value || '0';
|
||||
config.EncoderPreset = form.querySelector('#selectEncoderPreset').value;
|
||||
config.H264Crf = parseInt(form.querySelector('#txtH264Crf').value || '0');
|
||||
config.DeinterlaceMethod = form.querySelector('#selectDeinterlaceMethod').value;
|
||||
|
@ -149,6 +167,16 @@ import libraryMenu from 'libraryMenu';
|
|||
page.querySelector('#txtVaapiDevice').removeAttribute('required');
|
||||
}
|
||||
|
||||
if (this.value == 'nvenc' || this.value == 'amf') {
|
||||
page.querySelector('.fldOpenclDevice').classList.remove('hide');
|
||||
page.querySelector('#txtOpenclDevice').setAttribute('required', 'required');
|
||||
page.querySelector('.tonemappingOptions').classList.remove('hide');
|
||||
} else {
|
||||
page.querySelector('.fldOpenclDevice').classList.add('hide');
|
||||
page.querySelector('#txtOpenclDevice').removeAttribute('required');
|
||||
page.querySelector('.tonemappingOptions').classList.add('hide');
|
||||
}
|
||||
|
||||
if (this.value) {
|
||||
page.querySelector('.hardwareAccelerationOptions').classList.remove('hide');
|
||||
} else {
|
||||
|
|
|
@ -9,21 +9,21 @@ import 'flexStyles';
|
|||
export default function(view, params) {
|
||||
view.addEventListener('viewbeforeshow', function() {
|
||||
loading.show();
|
||||
var apiClient = ApiClient;
|
||||
const apiClient = ApiClient;
|
||||
apiClient.getJSON(apiClient.getUrl('System/Logs')).then(function(logs) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
html += '<div class="paperList">';
|
||||
html += logs.map(function(log) {
|
||||
var logUrl = apiClient.getUrl('System/Logs/Log', {
|
||||
let logUrl = apiClient.getUrl('System/Logs/Log', {
|
||||
name: log.Name
|
||||
});
|
||||
logUrl += '&api_key=' + apiClient.accessToken();
|
||||
var logHtml = '';
|
||||
let logHtml = '';
|
||||
logHtml += '<a is="emby-linkbutton" href="' + logUrl + '" target="_blank" class="listItem listItem-border" style="color:inherit;">';
|
||||
logHtml += '<div class="listItemBody two-line">';
|
||||
logHtml += "<h3 class='listItemBodyText'>" + log.Name + '</h3>';
|
||||
var date = datetime.parseISO8601Date(log.DateModified, true);
|
||||
var text = datetime.toLocaleDateString(date);
|
||||
const date = datetime.parseISO8601Date(log.DateModified, true);
|
||||
let text = datetime.toLocaleDateString(date);
|
||||
text += ' ' + datetime.getDisplayTime(date);
|
||||
logHtml += '<div class="listItemBodyText secondary">' + text + '</div>';
|
||||
logHtml += '</div>';
|
||||
|
|
|
@ -43,6 +43,11 @@
|
|||
<input is="emby-input" type="text" id="txtLanNetworks" label="${LabelLanNetworks}" />
|
||||
<div class="fieldDescription">${LanNetworksHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" id="txtKnownProxies" label="${LabelKnownProxies}" />
|
||||
<div class="fieldDescription">${KnownProxiesHelp}</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class='verticalSection verticalSection-extrabottompadding'>
|
||||
|
|
|
@ -30,6 +30,11 @@ import 'emby-select';
|
|||
}).filter(function (s) {
|
||||
return s.length > 0;
|
||||
});
|
||||
config.KnownProxies = form.querySelector('#txtKnownProxies').value.split(',').map(function (s) {
|
||||
return s.trim();
|
||||
}).filter(function (s) {
|
||||
return s.length > 0;
|
||||
});
|
||||
config.IsRemoteIPFilterBlacklist = form.querySelector('#selectExternalAddressFilterMode').value === 'blacklist';
|
||||
config.PublicPort = form.querySelector('#txtPublicPort').value;
|
||||
config.PublicHttpsPort = form.querySelector('#txtPublicHttpsPort').value;
|
||||
|
@ -108,6 +113,7 @@ import 'emby-select';
|
|||
page.querySelector('#txtPublicHttpsPort').value = config.PublicHttpsPort;
|
||||
page.querySelector('#txtLocalAddress').value = config.LocalNetworkAddresses[0] || '';
|
||||
page.querySelector('#txtLanNetworks').value = (config.LocalNetworkSubnets || []).join(', ');
|
||||
page.querySelector('#txtKnownProxies').value = (config.KnownProxies || []).join(', ');
|
||||
page.querySelector('#txtExternalAddressFilter').value = (config.RemoteIPFilter || []).join(', ');
|
||||
page.querySelector('#selectExternalAddressFilterMode').value = config.IsRemoteIPFilterBlacklist ? 'blacklist' : 'whitelist';
|
||||
page.querySelector('#chkRemoteAccess').checked = config.EnableRemoteAccess == null || config.EnableRemoteAccess;
|
||||
|
|
|
@ -42,10 +42,10 @@ function saveList(page) {
|
|||
}
|
||||
|
||||
function populateList(options) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<div class="paperList">';
|
||||
for (var i = 0; i < options.repositories.length; i++) {
|
||||
for (let i = 0; i < options.repositories.length; i++) {
|
||||
html += getRepositoryHtml(options.repositories[i]);
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ function populateList(options) {
|
|||
}
|
||||
|
||||
function getRepositoryHtml(repository) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<div class="listItem listItem-border">';
|
||||
html += `<a is="emby-linkbutton" style="margin:0;padding:0" class="clearLink listItemIconContainer" href="${repository.Url}">`;
|
||||
|
@ -93,9 +93,9 @@ export default function(view, params) {
|
|||
libraryMenu.setTabs('plugins', 2, getTabs);
|
||||
reloadList(this);
|
||||
|
||||
var save = this;
|
||||
const save = this;
|
||||
$('#repositories', view).on('click', '.btnDelete', function() {
|
||||
var button = this;
|
||||
const button = this;
|
||||
repositories = repositories.filter(function (r) {
|
||||
return r.Url !== button.id;
|
||||
});
|
||||
|
|
24
src/controllers/dashboard/quickConnect.html
Normal file
24
src/controllers/dashboard/quickConnect.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<div id="quickConnectPage" data-role="page" class="page type-interior advancedConfigurationPage">
|
||||
<div class="content-primary">
|
||||
<form class="quickConnectSettings">
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle">${QuickConnect}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>${LabelCurrentStatus}<span id="quickConnectStatus" style="padding:0 0.4em;"></span></div>
|
||||
|
||||
<div class="checkboxList paperList" style="padding:.5em 1em;">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkQuickConnectAvailable" />
|
||||
<span>${EnableQuickConnect}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button is="emby-button" id="btnQuickConnectSubmit" type="submit" class="raised button-submit block">
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
58
src/controllers/dashboard/quickConnect.js
Normal file
58
src/controllers/dashboard/quickConnect.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
import loading from 'loading';
|
||||
import toast from 'toast';
|
||||
import globalize from 'globalize';
|
||||
|
||||
const unavailable = 'Unavailable';
|
||||
const available = 'Available';
|
||||
const active = 'Active';
|
||||
let page;
|
||||
|
||||
export default function(view) {
|
||||
view.addEventListener('viewshow', function () {
|
||||
page = this;
|
||||
loading.show();
|
||||
page.querySelector('#btnQuickConnectSubmit').onclick = onSubmit;
|
||||
updatePage();
|
||||
});
|
||||
}
|
||||
|
||||
function loadPage(status) {
|
||||
const check = status === available || status === active;
|
||||
|
||||
page.querySelector('#quickConnectStatus').textContent = status.toLocaleLowerCase();
|
||||
page.querySelector('#chkQuickConnectAvailable').checked = check;
|
||||
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
loading.show();
|
||||
|
||||
const newStatus = page.querySelector('#chkQuickConnectAvailable').checked ? available : unavailable;
|
||||
|
||||
const url = ApiClient.getUrl('/QuickConnect/Available?Status=' + newStatus);
|
||||
|
||||
ApiClient.ajax({
|
||||
type: 'POST',
|
||||
url: url
|
||||
}, true).then(() => {
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
setTimeout(updatePage, 500);
|
||||
|
||||
return true;
|
||||
}).catch((e) => {
|
||||
console.error('Unable to set quick connect status. error:', e);
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
function updatePage() {
|
||||
ApiClient.getQuickConnect('Status').then((response) => {
|
||||
loadPage(response);
|
||||
return true;
|
||||
}).catch((e) => {
|
||||
console.error('Unable to get quick connect status. error:', e);
|
||||
});
|
||||
}
|
|
@ -140,32 +140,13 @@
|
|||
</div>
|
||||
<div class="fieldDescription">${OptionAllowRemoteSharedDevicesHelp}</div>
|
||||
</div>
|
||||
<div class="verticalSection">
|
||||
<h2 class="checkboxListLabel">${HeaderDownloadSync}</h2>
|
||||
<div class="checkboxList paperList" style="padding:.5em 1em;">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableDownloading" />
|
||||
<span>${OptionAllowContentDownloading}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableSyncTranscoding" />
|
||||
<span>${OptionAllowSyncTranscoding}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="checkboxListLabel">${Other}</h2>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableConversion" />
|
||||
<span>${AllowMediaConversion}</span>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableDownloading" />
|
||||
<span>${OptionAllowContentDownload}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${AllowMediaConversionHelp}</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableSharing" />
|
||||
<span>${OptionAllowLinkSharing}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription sharingHelp"></div>
|
||||
<div class="fieldDescription checkboxFieldDescription">${OptionAllowContentDownloadHelp}</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription" id="fldIsEnabled">
|
||||
<label>
|
||||
|
@ -190,6 +171,14 @@
|
|||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class=verticalSection>
|
||||
<div class="inputContainer" id="fldMaxActiveSessions">
|
||||
<input is="emby-input" type="number" id="txtMaxActiveSessions" min="0" step="1" label="${LabelUserMaxActiveSessions}"/>
|
||||
<div class="fieldDescription">${OptionMaxActiveSessions}</div>
|
||||
<div class="fieldDescription">${OptionMaxActiveSessionsHelp}</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block">
|
||||
<span>${Save}</span>
|
||||
|
|
|
@ -97,11 +97,9 @@ import globalize from 'globalize';
|
|||
$('#chkEnableVideoPlaybackRemuxing', page).prop('checked', user.Policy.EnablePlaybackRemuxing);
|
||||
$('#chkForceRemoteSourceTranscoding', page).prop('checked', user.Policy.ForceRemoteSourceTranscoding);
|
||||
$('#chkRemoteAccess', page).prop('checked', user.Policy.EnableRemoteAccess == null || user.Policy.EnableRemoteAccess);
|
||||
$('#chkEnableSyncTranscoding', page).prop('checked', user.Policy.EnableSyncTranscoding);
|
||||
$('#chkEnableConversion', page).prop('checked', user.Policy.EnableMediaConversion || false);
|
||||
$('#chkEnableSharing', page).prop('checked', user.Policy.EnablePublicSharing);
|
||||
$('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || '');
|
||||
$('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0');
|
||||
$('#txtMaxActiveSessions', page).val(user.Policy.MaxActiveSessions || '0');
|
||||
if (ApiClient.isMinServerVersion('10.6.0')) {
|
||||
$('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess);
|
||||
}
|
||||
|
@ -132,12 +130,10 @@ import globalize from 'globalize';
|
|||
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).is(':checked');
|
||||
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).is(':checked');
|
||||
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).is(':checked');
|
||||
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).is(':checked');
|
||||
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).is(':checked');
|
||||
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).is(':checked');
|
||||
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).is(':checked');
|
||||
user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0'));
|
||||
user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0');
|
||||
user.Policy.MaxActiveSessions = parseInt($('#txtMaxActiveSessions', page).val() || '0');
|
||||
user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value;
|
||||
user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value;
|
||||
user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).is(':checked');
|
||||
|
|
|
@ -51,7 +51,9 @@ import globalize from 'globalize';
|
|||
$('.channelAccessContainer', page).hide();
|
||||
}
|
||||
|
||||
$('#chkEnableAllChannels', page).prop('checked', user.Policy.EnableAllChannels);
|
||||
const chkEnableAllChannels = page.querySelector('#chkEnableAllChannels');
|
||||
chkEnableAllChannels.checked = user.Policy.EnableAllChannels;
|
||||
triggerChange(chkEnableAllChannels);
|
||||
}
|
||||
|
||||
function loadDevices(page, user, devices) {
|
||||
|
@ -67,7 +69,9 @@ import globalize from 'globalize';
|
|||
|
||||
html += '</div>';
|
||||
$('.deviceAccess', page).show().html(html);
|
||||
$('#chkEnableAllDevices', page).prop('checked', user.Policy.EnableAllDevices);
|
||||
const chkEnableAllDevices = page.querySelector('#chkEnableAllDevices');
|
||||
chkEnableAllDevices.checked = user.Policy.EnableAllDevices;
|
||||
triggerChange(chkEnableAllDevices);
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
page.querySelector('.deviceAccessContainer').classList.add('hide');
|
||||
|
|
|
@ -20,7 +20,7 @@ export default function (view, params) {
|
|||
});
|
||||
MetadataEditor.setCurrentItemId(null);
|
||||
view.querySelector('.libraryTree').addEventListener('itemclicked', function (event) {
|
||||
var data = event.detail;
|
||||
const data = event.detail;
|
||||
|
||||
if (data.id != MetadataEditor.getCurrentItemId()) {
|
||||
MetadataEditor.setCurrentItemId(data.id);
|
||||
|
|
|
@ -163,7 +163,7 @@ import 'emby-scroller';
|
|||
instance.setFilterStatus(hasFilters);
|
||||
|
||||
if (instance.alphaPicker) {
|
||||
query.NameStartsWithOrGreater = instance.alphaPicker.value();
|
||||
query.NameStartsWith = instance.alphaPicker.value();
|
||||
}
|
||||
|
||||
return query;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div id="moviesPage" data-role="page" data-dom-cache="true" class="page libraryPage backdropPage collectionEditorPage pageWithAbsoluteTabs withTabs" data-backdroptype="movie">
|
||||
|
||||
<div class="pageTabContent" data-index="0">
|
||||
<div class="pageTabContent" id="moviesTab" data-index="0">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
|
||||
|
@ -17,7 +17,7 @@
|
|||
<div class="paging"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="1">
|
||||
<div class="pageTabContent" id="suggestionsTab" data-index="1">
|
||||
<div id="resumableSection" class="verticalSection hide">
|
||||
<div class="sectionTitleContainer sectionTitleContainer-cards">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderContinueWatching}</h2>
|
||||
|
@ -43,7 +43,7 @@
|
|||
<p>${MessageNoMovieSuggestionsAvailable}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="2">
|
||||
<div class="pageTabContent" id="trailersTab" data-index="2">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
|
||||
|
@ -59,7 +59,7 @@
|
|||
<div class="paging"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="3">
|
||||
<div class="pageTabContent" id="favoritesTab" data-index="3">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
|
||||
|
@ -71,7 +71,7 @@
|
|||
<div class="paging"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="4">
|
||||
<div class="pageTabContent" id="collectionsTab" data-index="4">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
|
||||
|
@ -85,9 +85,7 @@
|
|||
<div class="paging"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="5">
|
||||
<div class="pageTabContent" id="genresTab" data-index="5">
|
||||
<div id="items"></div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="6">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -25,7 +25,12 @@ import 'emby-itemscontainer';
|
|||
|
||||
const updateFilterControls = () => {
|
||||
if (this.alphaPicker) {
|
||||
this.alphaPicker.value(query.NameStartsWithOrGreater);
|
||||
this.alphaPicker.value(query.NameStartsWith);
|
||||
if (query.SortBy.indexOf('SortName') === 0) {
|
||||
this.alphaPicker.visible(true);
|
||||
} else {
|
||||
this.alphaPicker.visible(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -163,12 +168,12 @@ import 'emby-itemscontainer';
|
|||
itemsContainer.fetchData = fetchData;
|
||||
itemsContainer.getItemsHtml = getItemsHtml;
|
||||
itemsContainer.afterRefresh = afterRefresh;
|
||||
let alphaPickerElement = tabContent.querySelector('.alphaPicker');
|
||||
const alphaPickerElement = tabContent.querySelector('.alphaPicker');
|
||||
|
||||
if (alphaPickerElement) {
|
||||
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
||||
let newValue = e.detail.value;
|
||||
query.NameStartsWithOrGreater = newValue;
|
||||
const newValue = e.detail.value;
|
||||
query.NameStartsWith = newValue;
|
||||
query.StartIndex = 0;
|
||||
itemsContainer.refreshItems();
|
||||
});
|
||||
|
@ -237,7 +242,7 @@ import 'emby-itemscontainer';
|
|||
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle, 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
|
||||
});
|
||||
btnSelectView.addEventListener('layoutchange', function (e) {
|
||||
let viewStyle = e.detail.viewStyle;
|
||||
const viewStyle = e.detail.viewStyle;
|
||||
userSettings.set(savedViewKey, viewStyle);
|
||||
query.StartIndex = 0;
|
||||
onViewStyleChange();
|
||||
|
@ -274,7 +279,7 @@ import 'emby-itemscontainer';
|
|||
|
||||
this.showFilterMenu = function () {
|
||||
import('components/filterdialog/filterdialog').then(({default: filterDialogFactory}) => {
|
||||
let filterDialog = new filterDialogFactory({
|
||||
const filterDialog = new filterDialogFactory({
|
||||
query: query,
|
||||
mode: 'movies',
|
||||
serverId: ApiClient.serverId()
|
||||
|
|
|
@ -58,7 +58,7 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function loadResume(page, userId, parentId) {
|
||||
let screenWidth = dom.getWindowSize().innerWidth;
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
const options = {
|
||||
SortBy: 'DatePlayed',
|
||||
SortOrder: 'Descending',
|
||||
|
@ -154,8 +154,8 @@ import 'emby-button';
|
|||
}
|
||||
|
||||
function loadSuggestions(page, userId, parentId) {
|
||||
let screenWidth = dom.getWindowSize().innerWidth;
|
||||
let url = ApiClient.getUrl('Movies/Recommendations', {
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
const url = ApiClient.getUrl('Movies/Recommendations', {
|
||||
userId: userId,
|
||||
categoryLimit: 6,
|
||||
ItemLimit: screenWidth >= 1920 ? 8 : screenWidth >= 1600 ? 8 : screenWidth >= 1200 ? 6 : 5,
|
||||
|
@ -172,7 +172,7 @@ import 'emby-button';
|
|||
|
||||
const html = recommendations.map(getRecommendationHtml).join('');
|
||||
page.querySelector('.noItemsMessage').classList.add('hide');
|
||||
let recs = page.querySelector('.recommendations');
|
||||
const recs = page.querySelector('.recommendations');
|
||||
recs.innerHTML = html;
|
||||
imageLoader.lazyChildren(recs);
|
||||
|
||||
|
@ -320,11 +320,6 @@ import 'emby-button';
|
|||
|
||||
if (index === suggestionsTabIndex) {
|
||||
controller = this;
|
||||
} else if (index === 6) {
|
||||
controller = new controllerFactory(view, tabContent, {
|
||||
collectionType: 'movies',
|
||||
parentId: params.topParentId
|
||||
});
|
||||
} else if (index == 0 || index == 3) {
|
||||
controller = new controllerFactory(view, params, tabContent, {
|
||||
mode: index ? 'favorites' : 'movies'
|
||||
|
@ -381,21 +376,21 @@ import 'emby-button';
|
|||
const suggestionsTabIndex = 1;
|
||||
|
||||
this.initTab = function () {
|
||||
let tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||
initSuggestedTab(view, tabContent);
|
||||
};
|
||||
|
||||
this.renderTab = function () {
|
||||
let tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||
loadSuggestionsTab(view, params, tabContent);
|
||||
};
|
||||
|
||||
let tabControllers = [];
|
||||
const tabControllers = [];
|
||||
let renderedTabs = [];
|
||||
view.addEventListener('viewshow', function (e) {
|
||||
initTabs();
|
||||
if (!view.getAttribute('data-title')) {
|
||||
var parentId = params.topParentId;
|
||||
const parentId = params.topParentId;
|
||||
|
||||
if (parentId) {
|
||||
ApiClient.getItem(ApiClient.getCurrentUserId(), parentId).then(function (item) {
|
||||
|
|
|
@ -185,7 +185,7 @@ import 'emby-itemscontainer';
|
|||
|
||||
const updateFilterControls = (tabContent) => {
|
||||
const query = getQuery(tabContent);
|
||||
this.alphaPicker.value(query.NameStartsWithOrGreater);
|
||||
this.alphaPicker.value(query.NameStartsWith);
|
||||
};
|
||||
|
||||
const data = {};
|
||||
|
@ -216,7 +216,7 @@ import 'emby-itemscontainer';
|
|||
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
||||
const newValue = e.detail.value;
|
||||
const query = getQuery(tabContent);
|
||||
query.NameStartsWithOrGreater = newValue;
|
||||
query.NameStartsWith = newValue;
|
||||
query.StartIndex = 0;
|
||||
reloadItems();
|
||||
});
|
||||
|
|
|
@ -8,7 +8,26 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
<div class="pageTabContent pageTabContent" id="suggestionsTab" data-index="0">
|
||||
<div class="pageTabContent pageTabContent" id="albumsTab" data-index="0">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
<button is="paper-icon-button-light" class="btnPlayAll musicglobalButton" title="${HeaderPlayAll}"><span class="material-icons play_arrow"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnShuffle musicglobalButton" title="${Shuffle}"><span class="material-icons shuffle"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
|
||||
</div>
|
||||
|
||||
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
|
||||
</div>
|
||||
|
||||
<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right">
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent pageTabContent" id="suggestionsTab" data-index="1">
|
||||
|
||||
<div class="verticalSection">
|
||||
|
||||
|
@ -34,25 +53,6 @@
|
|||
|
||||
<div class="favoriteSections verticalSection"></div>
|
||||
</div>
|
||||
<div class="pageTabContent pageTabContent" id="albumsTab" data-index="1">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
<button is="paper-icon-button-light" class="btnPlayAll musicglobalButton" title="${HeaderPlayAll}"><span class="material-icons play_arrow"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnShuffle musicglobalButton" title="${Shuffle}"><span class="material-icons shuffle"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
|
||||
</div>
|
||||
|
||||
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
|
||||
</div>
|
||||
|
||||
<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right">
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" id="albumArtistsTab" data-index="2">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
|
@ -85,7 +85,7 @@
|
|||
<div class="paging"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="4">
|
||||
<div class="pageTabContent" id="playlistsTab" data-index="4">
|
||||
|
||||
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap centered"></div>
|
||||
</div>
|
||||
|
@ -105,6 +105,4 @@
|
|||
<div class="pageTabContent" id="genresTab" data-index="6">
|
||||
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap"></div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="7">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -155,20 +155,21 @@ import 'emby-itemscontainer';
|
|||
overlayPlayButton: true
|
||||
});
|
||||
}
|
||||
|
||||
let elems = tabContent.querySelectorAll('.paging');
|
||||
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].innerHTML = pagingHtml;
|
||||
for (const elem of elems) {
|
||||
elem.innerHTML = pagingHtml;
|
||||
}
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('click', onNextPageClick);
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onNextPageClick);
|
||||
}
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('click', onPreviousPageClick);
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onPreviousPageClick);
|
||||
}
|
||||
|
||||
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||
|
@ -186,7 +187,16 @@ import 'emby-itemscontainer';
|
|||
|
||||
const updateFilterControls = (tabContent) => {
|
||||
const query = getQuery();
|
||||
this.alphaPicker.value(query.NameStartsWithOrGreater);
|
||||
|
||||
if (this.alphaPicker) {
|
||||
this.alphaPicker.value(query.NameStartsWith);
|
||||
|
||||
if (query.SortBy.indexOf('SortName') === 0) {
|
||||
this.alphaPicker.visible(true);
|
||||
} else {
|
||||
this.alphaPicker.visible(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let savedQueryKey;
|
||||
|
@ -200,10 +210,12 @@ import 'emby-itemscontainer';
|
|||
mode: 'albums',
|
||||
serverId: ApiClient.serverId()
|
||||
});
|
||||
|
||||
events.on(filterDialog, 'filterchange', function () {
|
||||
getQuery().StartIndex = 0;
|
||||
reloadItems(tabContent);
|
||||
});
|
||||
|
||||
filterDialog.show();
|
||||
});
|
||||
};
|
||||
|
@ -219,10 +231,11 @@ import 'emby-itemscontainer';
|
|||
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
||||
const newValue = e.detail.value;
|
||||
const query = getQuery();
|
||||
query.NameStartsWithOrGreater = newValue;
|
||||
query.NameStartsWith = newValue;
|
||||
query.StartIndex = 0;
|
||||
reloadItems(tabContent);
|
||||
});
|
||||
|
||||
this.alphaPicker = new AlphaPicker({
|
||||
element: alphaPickerElement,
|
||||
valueChangeEvent: 'click'
|
||||
|
@ -235,6 +248,7 @@ import 'emby-itemscontainer';
|
|||
tabContent.querySelector('.btnFilter').addEventListener('click', () => {
|
||||
this.showFilterMenu();
|
||||
});
|
||||
|
||||
tabContent.querySelector('.btnSort').addEventListener('click', (e) => {
|
||||
libraryBrowser.showSortMenu({
|
||||
items: [{
|
||||
|
@ -267,10 +281,12 @@ import 'emby-itemscontainer';
|
|||
button: e.target
|
||||
});
|
||||
});
|
||||
|
||||
const btnSelectView = tabContent.querySelector('.btnSelectView');
|
||||
btnSelectView.addEventListener('click', (e) => {
|
||||
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle(), 'List,Poster,PosterCard'.split(','));
|
||||
});
|
||||
|
||||
btnSelectView.addEventListener('layoutchange', function (e) {
|
||||
const viewStyle = e.detail.viewStyle;
|
||||
getPageData().view = viewStyle;
|
||||
|
@ -279,6 +295,7 @@ import 'emby-itemscontainer';
|
|||
onViewStyleChange();
|
||||
reloadItems(tabContent);
|
||||
});
|
||||
|
||||
tabContent.querySelector('.btnPlayAll').addEventListener('click', playAll);
|
||||
tabContent.querySelector('.btnShuffle').addEventListener('click', shuffle);
|
||||
};
|
||||
|
|
|
@ -169,7 +169,7 @@ import 'emby-itemscontainer';
|
|||
|
||||
const updateFilterControls = (tabContent) => {
|
||||
const query = getQuery(tabContent);
|
||||
this.alphaPicker.value(query.NameStartsWithOrGreater);
|
||||
this.alphaPicker.value(query.NameStartsWith);
|
||||
};
|
||||
|
||||
const data = {};
|
||||
|
@ -201,7 +201,7 @@ import 'emby-itemscontainer';
|
|||
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
||||
const newValue = e.detail.value;
|
||||
const query = getQuery(tabContent);
|
||||
query.NameStartsWithOrGreater = newValue;
|
||||
query.NameStartsWith = newValue;
|
||||
query.StartIndex = 0;
|
||||
reloadItems(tabContent);
|
||||
});
|
||||
|
|
|
@ -56,7 +56,7 @@ import 'flexStyles';
|
|||
EnableTotalRecordCount: false
|
||||
};
|
||||
ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
|
||||
var elem = page.querySelector('#recentlyAddedSongs');
|
||||
const elem = page.querySelector('#recentlyAddedSongs');
|
||||
elem.innerHTML = cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
showUnplayedIndicator: false,
|
||||
|
@ -103,7 +103,7 @@ import 'flexStyles';
|
|||
elem.classList.add('hide');
|
||||
}
|
||||
|
||||
var itemsContainer = elem.querySelector('.itemsContainer');
|
||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||
itemsContainer.innerHTML = cardBuilder.getCardsHtml({
|
||||
items: result.Items,
|
||||
showUnplayedIndicator: false,
|
||||
|
@ -145,7 +145,7 @@ import 'flexStyles';
|
|||
elem.classList.add('hide');
|
||||
}
|
||||
|
||||
var itemsContainer = elem.querySelector('.itemsContainer');
|
||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||
itemsContainer.innerHTML = cardBuilder.getCardsHtml({
|
||||
items: result.Items,
|
||||
showUnplayedIndicator: false,
|
||||
|
@ -177,9 +177,9 @@ import 'flexStyles';
|
|||
|
||||
function getTabs() {
|
||||
return [{
|
||||
name: globalize.translate('Suggestions')
|
||||
}, {
|
||||
name: globalize.translate('Albums')
|
||||
}, {
|
||||
name: globalize.translate('Suggestions')
|
||||
}, {
|
||||
name: globalize.translate('HeaderAlbumArtists')
|
||||
}, {
|
||||
|
@ -195,7 +195,7 @@ import 'flexStyles';
|
|||
|
||||
function getDefaultTabIndex(folderId) {
|
||||
switch (userSettings.get('landing-' + folderId)) {
|
||||
case 'albums':
|
||||
case 'suggestions':
|
||||
return 1;
|
||||
|
||||
case 'albumartists':
|
||||
|
@ -221,7 +221,7 @@ import 'flexStyles';
|
|||
export default function (view, params) {
|
||||
function reload() {
|
||||
loading.show();
|
||||
const tabContent = view.querySelector(".pageTabContent[data-index='0']");
|
||||
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||
loadSuggestionsTab(view, tabContent, params.topParentId);
|
||||
}
|
||||
|
||||
|
@ -268,11 +268,11 @@ import 'flexStyles';
|
|||
|
||||
switch (index) {
|
||||
case 0:
|
||||
depends = 'controllers/music/musicrecommended';
|
||||
depends = 'controllers/music/musicalbums';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
depends = 'controllers/music/musicalbums';
|
||||
depends = 'controllers/music/musicrecommended';
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
@ -296,7 +296,7 @@ import 'flexStyles';
|
|||
import(depends).then(({default: controllerFactory}) => {
|
||||
let tabContent;
|
||||
|
||||
if (index == 0) {
|
||||
if (index == 1) {
|
||||
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
|
||||
this.tabContent = tabContent;
|
||||
}
|
||||
|
@ -306,13 +306,8 @@ import 'flexStyles';
|
|||
if (!controller) {
|
||||
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
|
||||
|
||||
if (index === 0) {
|
||||
if (index === 1) {
|
||||
controller = this;
|
||||
} else if (index === 7) {
|
||||
controller = new controllerFactory(view, tabContent, {
|
||||
collectionType: 'music',
|
||||
parentId: params.topParentId
|
||||
});
|
||||
} else {
|
||||
controller = new controllerFactory(view, params, tabContent);
|
||||
}
|
||||
|
@ -360,9 +355,10 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId));
|
||||
const suggestionsTabIndex = 1;
|
||||
|
||||
this.initTab = function () {
|
||||
const tabContent = view.querySelector(".pageTabContent[data-index='0']");
|
||||
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||
const containers = tabContent.querySelectorAll('.itemsContainer');
|
||||
|
||||
for (let i = 0, length = containers.length; i < length; i++) {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
<div id="videoOsdPage" data-role="page" class="page libraryPage" data-backbutton="true">
|
||||
<div class="upNextContainer hide"></div>
|
||||
<div class="videoOsdBottom videoOsdBottom-maincontrols">
|
||||
<div class="osdPoster"></div>
|
||||
<div class="osdControls">
|
||||
<div class="osdTextContainer osdMainTextContainer">
|
||||
<h3 class="osdTitle"></h3>
|
||||
<div class="osdMediaInfo"></div>
|
||||
<div class="osdMediaStatus hide">
|
||||
<span class="material-icons animate autorenew"></span>
|
||||
<span>${FetchingData}</span>
|
||||
|
@ -16,7 +14,7 @@
|
|||
|
||||
<div class="flex flex-direction-row align-items-center">
|
||||
<div class="osdTextContainer startTimeText" style="margin: 0 .25em 0 0;"></div>
|
||||
<div class="sliderContainer flex-grow" style="margin: .5em .5em .25em;">
|
||||
<div class="sliderContainer flex-grow" style="margin: .5em 0 .25em;">
|
||||
<input type="range" step=".01" min="0" max="100" value="0" is="emby-slider" class="osdPositionSlider" data-slider-keep-progress="true" />
|
||||
</div>
|
||||
<div class="osdTextContainer endTimeText" style="margin: 0 0 0 .25em;"></div>
|
||||
|
@ -47,32 +45,18 @@
|
|||
<span class="xlargePaperIconButton material-icons skip_next"></span>
|
||||
</button>
|
||||
|
||||
<button is="paper-icon-button-light" class="btnAudio hide autoSize" title="${Audio}">
|
||||
<span class="xlargePaperIconButton material-icons audiotrack"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnSubtitles hide autoSize" title="${Subtitles}">
|
||||
<span class="xlargePaperIconButton material-icons closed_caption"></span>
|
||||
</button>
|
||||
|
||||
<button is="paper-icon-button-light" class="btnVideoOsdSettings hide autoSize" title="${Settings}">
|
||||
<span class="largePaperIconButton material-icons settings"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnFullscreen hide autoSize" title="${Fullscreen} (f)">
|
||||
<span class="xlargePaperIconButton material-icons fullscreen"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnPip hide autoSize" title="${PictureInPicture}">
|
||||
<span class="xlargePaperIconButton material-icons picture_in_picture_alt"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnAirPlay hide autoSize" title="${AirPlay}">
|
||||
<span class="xlargePaperIconButton material-icons airplay"></span>
|
||||
</button>
|
||||
|
||||
<div class="osdTimeText">
|
||||
<span class="osdPositionText"></span>
|
||||
<span class="osdDurationText"></span>
|
||||
<span class="endsAtText"></span>
|
||||
</div>
|
||||
|
||||
<button is="paper-icon-button-light" class="btnSubtitles hide autoSize" title="${Subtitles}">
|
||||
<span class="xlargePaperIconButton material-icons closed_caption"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnAudio hide autoSize" title="${Audio}">
|
||||
<span class="xlargePaperIconButton material-icons audiotrack"></span>
|
||||
</button>
|
||||
<div class="volumeButtons hide-mouse-idle-tv">
|
||||
<button is="paper-icon-button-light" class="buttonMute autoSize" title="${Mute} (m)">
|
||||
<span class="xlargePaperIconButton material-icons volume_up"></span>
|
||||
|
@ -81,6 +65,18 @@
|
|||
<input is="emby-slider" type="range" step="1" min="0" max="100" value="0" class="osdVolumeSlider" />
|
||||
</div>
|
||||
</div>
|
||||
<button is="paper-icon-button-light" class="btnVideoOsdSettings hide autoSize" title="${Settings}">
|
||||
<span class="largePaperIconButton material-icons settings"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnAirPlay hide autoSize" title="${AirPlay}">
|
||||
<span class="xlargePaperIconButton material-icons airplay"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnPip hide autoSize" title="${PictureInPicture}">
|
||||
<span class="xlargePaperIconButton material-icons picture_in_picture_alt"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnFullscreen hide autoSize" title="${Fullscreen} (f)">
|
||||
<span class="xlargePaperIconButton material-icons fullscreen"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,50 +20,6 @@ import 'css!assets/css/videoosd';
|
|||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function seriesImageUrl(item, options) {
|
||||
if (item.Type !== 'Episode') {
|
||||
return null;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
options.type = options.type || 'Primary';
|
||||
if (options.type === 'Primary' && item.SeriesPrimaryImageTag) {
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
}
|
||||
|
||||
if (options.type === 'Thumb') {
|
||||
if (item.SeriesThumbImageTag) {
|
||||
options.tag = item.SeriesThumbImageTag;
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
}
|
||||
|
||||
if (item.ParentThumbImageTag) {
|
||||
options.tag = item.ParentThumbImageTag;
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function imageUrl(item, options) {
|
||||
options = options || {};
|
||||
options.type = options.type || 'Primary';
|
||||
|
||||
if (item.ImageTags && item.ImageTags[options.type]) {
|
||||
options.tag = item.ImageTags[options.type];
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
|
||||
}
|
||||
|
||||
if (options.type === 'Primary' && item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getOpenedDialog() {
|
||||
return document.querySelector('.dialogContainer .dialog.opened');
|
||||
}
|
||||
|
@ -163,7 +119,6 @@ import 'css!assets/css/videoosd';
|
|||
currentItem = item;
|
||||
const displayItem = itemInfo.displayItem || item;
|
||||
updateRecordingButton(displayItem);
|
||||
setPoster(displayItem, item);
|
||||
let parentName = displayItem.SeriesName || displayItem.Album;
|
||||
|
||||
if (displayItem.EpisodeTitle || displayItem.IsSeries) {
|
||||
|
@ -171,42 +126,6 @@ import 'css!assets/css/videoosd';
|
|||
}
|
||||
|
||||
setTitle(displayItem, parentName);
|
||||
const titleElement = view.querySelector('.osdTitle');
|
||||
let displayName = itemHelper.getDisplayName(displayItem, {
|
||||
includeParentInfo: displayItem.Type !== 'Program',
|
||||
includeIndexNumber: displayItem.Type !== 'Program'
|
||||
});
|
||||
|
||||
if (!displayName) {
|
||||
displayName = displayItem.Type;
|
||||
}
|
||||
|
||||
titleElement.innerHTML = displayName;
|
||||
|
||||
if (displayName) {
|
||||
titleElement.classList.remove('hide');
|
||||
} else {
|
||||
titleElement.classList.add('hide');
|
||||
}
|
||||
|
||||
const mediaInfoHtml = mediaInfo.getPrimaryMediaInfoHtml(displayItem, {
|
||||
runtime: false,
|
||||
subtitles: false,
|
||||
tomatoes: false,
|
||||
endsAt: false,
|
||||
episodeTitle: false,
|
||||
originalAirDate: displayItem.Type !== 'Program',
|
||||
episodeTitleIndexNumber: displayItem.Type !== 'Program',
|
||||
programIndicator: false
|
||||
});
|
||||
const osdMediaInfo = view.querySelector('.osdMediaInfo');
|
||||
osdMediaInfo.innerHTML = mediaInfoHtml;
|
||||
|
||||
if (mediaInfoHtml) {
|
||||
osdMediaInfo.classList.remove('hide');
|
||||
} else {
|
||||
osdMediaInfo.classList.add('hide');
|
||||
}
|
||||
|
||||
const secondaryMediaInfo = view.querySelector('.osdSecondaryMediaInfo');
|
||||
const secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, {
|
||||
|
@ -221,12 +140,6 @@ import 'css!assets/css/videoosd';
|
|||
secondaryMediaInfo.classList.add('hide');
|
||||
}
|
||||
|
||||
if (displayName) {
|
||||
view.querySelector('.osdMainTextContainer').classList.remove('hide');
|
||||
} else {
|
||||
view.querySelector('.osdMainTextContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (enableProgressByTimeOfDay) {
|
||||
setDisplayTime(startTimeText, displayItem.StartDate);
|
||||
setDisplayTime(endTimeText, displayItem.EndDate);
|
||||
|
@ -276,7 +189,6 @@ import 'css!assets/css/videoosd';
|
|||
|
||||
currentItem = item;
|
||||
if (!item) {
|
||||
setPoster(null);
|
||||
updateRecordingButton(null);
|
||||
Emby.Page.setTitle('');
|
||||
nowPlayingVolumeSlider.disabled = true;
|
||||
|
@ -313,7 +225,20 @@ import 'css!assets/css/videoosd';
|
|||
}
|
||||
|
||||
function setTitle(item, parentName) {
|
||||
Emby.Page.setTitle(parentName || '');
|
||||
let itemName = itemHelper.getDisplayName(item, {
|
||||
includeParentInfo: item.Type !== 'Program',
|
||||
includeIndexNumber: item.Type !== 'Program'
|
||||
});
|
||||
|
||||
if (itemName && parentName) {
|
||||
itemName = `${parentName} - ${itemName}`;
|
||||
}
|
||||
|
||||
if (!itemName) {
|
||||
itemName = parentName || '';
|
||||
}
|
||||
|
||||
Emby.Page.setTitle(itemName);
|
||||
|
||||
const documentTitle = parentName || (item ? item.Name : null);
|
||||
|
||||
|
@ -322,38 +247,6 @@ import 'css!assets/css/videoosd';
|
|||
}
|
||||
}
|
||||
|
||||
function setPoster(item, secondaryItem) {
|
||||
const osdPoster = view.querySelector('.osdPoster');
|
||||
|
||||
if (item) {
|
||||
let imgUrl = seriesImageUrl(item, {
|
||||
maxWidth: osdPoster.clientWidth,
|
||||
type: 'Primary'
|
||||
}) || seriesImageUrl(item, {
|
||||
maxWidth: osdPoster.clientWidth,
|
||||
type: 'Thumb'
|
||||
}) || imageUrl(item, {
|
||||
maxWidth: osdPoster.clientWidth,
|
||||
type: 'Primary'
|
||||
});
|
||||
|
||||
if (!imgUrl && secondaryItem && (imgUrl = seriesImageUrl(secondaryItem, {
|
||||
maxWidth: osdPoster.clientWidth,
|
||||
type: 'Primary'
|
||||
}) || seriesImageUrl(secondaryItem, {
|
||||
maxWidth: osdPoster.clientWidth,
|
||||
type: 'Thumb'
|
||||
}) || imageUrl(secondaryItem, {
|
||||
maxWidth: osdPoster.clientWidth,
|
||||
type: 'Primary'
|
||||
})), imgUrl) {
|
||||
return void (osdPoster.innerHTML = '<img src="' + imgUrl + '" />');
|
||||
}
|
||||
}
|
||||
|
||||
osdPoster.innerHTML = '';
|
||||
}
|
||||
|
||||
let mouseIsDown = false;
|
||||
|
||||
function showOsd() {
|
||||
|
|
|
@ -41,6 +41,7 @@ import globalize from 'globalize';
|
|||
type: 'POST',
|
||||
url: ApiClient.getUrl('Users/ForgotPassword'),
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
EnteredUsername: view.querySelector('#txtName').value
|
||||
})
|
||||
|
|
|
@ -42,6 +42,10 @@
|
|||
<button is="emby-button" type="button" class="raised cancel block btnManual">
|
||||
<span>${ButtonManualLogin}</span>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="raised cancel block btnQuick">
|
||||
<span>${ButtonUseQuickConnect}</span>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="raised cancel block btnForgotPassword">
|
||||
<span>${ButtonForgotPassword}</span>
|
||||
|
|
|
@ -16,11 +16,10 @@ import 'emby-checkbox';
|
|||
function authenticateUserByName(page, apiClient, username, password) {
|
||||
loading.show();
|
||||
apiClient.authenticateUserByName(username, password).then(function (result) {
|
||||
var user = result.User;
|
||||
const user = result.User;
|
||||
loading.hide();
|
||||
|
||||
Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient);
|
||||
Dashboard.navigate('home.html');
|
||||
onLoginSuccessful(user.Id, result.AccessToken, apiClient);
|
||||
}, function (response) {
|
||||
page.querySelector('#txtManualName').value = '';
|
||||
page.querySelector('#txtManualPassword').value = '';
|
||||
|
@ -41,6 +40,60 @@ import 'emby-checkbox';
|
|||
});
|
||||
}
|
||||
|
||||
function authenticateQuickConnect(apiClient) {
|
||||
const url = apiClient.getUrl('/QuickConnect/Initiate');
|
||||
apiClient.getJSON(url).then(function (json) {
|
||||
if (!json.Secret || !json.Code) {
|
||||
console.error('Malformed quick connect response', json);
|
||||
return false;
|
||||
}
|
||||
|
||||
Dashboard.alert({
|
||||
message: globalize.translate('QuickConnectAuthorizeCode', json.Code),
|
||||
title: globalize.translate('QuickConnect')
|
||||
});
|
||||
|
||||
const connectUrl = apiClient.getUrl('/QuickConnect/Connect?Secret=' + json.Secret);
|
||||
|
||||
const interval = setInterval(function() {
|
||||
apiClient.getJSON(connectUrl).then(async function(data) {
|
||||
if (!data.Authenticated) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearInterval(interval);
|
||||
|
||||
const result = await apiClient.quickConnect(data.Authentication);
|
||||
onLoginSuccessful(result.User.Id, result.AccessToken, apiClient);
|
||||
}, function (e) {
|
||||
clearInterval(interval);
|
||||
|
||||
Dashboard.alert({
|
||||
message: globalize.translate('QuickConnectDeactivated'),
|
||||
title: globalize.translate('HeaderError')
|
||||
});
|
||||
|
||||
console.error('Unable to login with quick connect', e);
|
||||
});
|
||||
}, 5000, connectUrl);
|
||||
|
||||
return true;
|
||||
}, function(e) {
|
||||
Dashboard.alert({
|
||||
message: globalize.translate('QuickConnectNotActive'),
|
||||
title: globalize.translate('HeaderError')
|
||||
});
|
||||
|
||||
console.error('Quick connect error: ', e);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function onLoginSuccessful(id, accessToken, apiClient) {
|
||||
Dashboard.onServerChanged(id, accessToken, apiClient);
|
||||
Dashboard.navigate('home.html');
|
||||
}
|
||||
|
||||
function showManualForm(context, showCancel, focusPassword) {
|
||||
context.querySelector('.chkRememberLogin').checked = appSettings.enableAutoLogin();
|
||||
context.querySelector('.manualLoginForm').classList.remove('hide');
|
||||
|
@ -187,6 +240,11 @@ import 'emby-checkbox';
|
|||
Dashboard.navigate('forgotpassword.html');
|
||||
});
|
||||
view.querySelector('.btnCancel').addEventListener('click', showVisualForm);
|
||||
view.querySelector('.btnQuick').addEventListener('click', function () {
|
||||
const apiClient = getApiClient();
|
||||
authenticateQuickConnect(apiClient);
|
||||
return false;
|
||||
});
|
||||
view.querySelector('.btnManual').addEventListener('click', function () {
|
||||
view.querySelector('#txtManualName').value = '';
|
||||
showManualForm(view, true);
|
||||
|
@ -194,6 +252,7 @@ import 'emby-checkbox';
|
|||
view.querySelector('.btnSelectServer').addEventListener('click', function () {
|
||||
Dashboard.selectServer();
|
||||
});
|
||||
|
||||
view.addEventListener('viewshow', function (e) {
|
||||
loading.show();
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
import loading from 'loading';
|
||||
import groupedcards from 'components/groupedcards';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import imageLoader from 'imageLoader';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function getLatestPromise(context, params) {
|
||||
loading.show();
|
||||
const userId = ApiClient.getCurrentUserId();
|
||||
const parentId = params.topParentId;
|
||||
const options = {
|
||||
IncludeItemTypes: 'Episode',
|
||||
Limit: 30,
|
||||
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
|
||||
ParentId: parentId,
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: 'Primary,Backdrop,Thumb'
|
||||
};
|
||||
return ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options));
|
||||
}
|
||||
|
||||
function loadLatest(context, params, promise) {
|
||||
promise.then(function (items) {
|
||||
let html = '';
|
||||
html += cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
shape: 'backdrop',
|
||||
preferThumb: true,
|
||||
showTitle: true,
|
||||
showSeriesYear: true,
|
||||
showParentTitle: true,
|
||||
overlayText: false,
|
||||
cardLayout: false,
|
||||
showUnplayedIndicator: false,
|
||||
showChildCountIndicator: true,
|
||||
centerText: true,
|
||||
lazy: true,
|
||||
overlayPlayButton: true,
|
||||
lines: 2
|
||||
});
|
||||
const elem = context.querySelector('#latestEpisodes');
|
||||
elem.innerHTML = html;
|
||||
imageLoader.lazyChildren(elem);
|
||||
loading.hide();
|
||||
|
||||
import('autoFocuser').then(({default: autoFocuser}) => {
|
||||
autoFocuser.autoFocus(context);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default function (view, params, tabContent) {
|
||||
const self = this;
|
||||
let latestPromise;
|
||||
|
||||
self.preRender = function () {
|
||||
latestPromise = getLatestPromise(view, params);
|
||||
};
|
||||
|
||||
self.renderTab = function () {
|
||||
loadLatest(tabContent, params, latestPromise);
|
||||
};
|
||||
|
||||
tabContent.querySelector('#latestEpisodes').addEventListener('click', groupedcards);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
|
@ -23,8 +23,15 @@
|
|||
|
||||
<div is="emby-itemscontainer" id="resumableItems" class="itemsContainer padded-left padded-right"></div>
|
||||
</div>
|
||||
<div id="latestItemsSection" class="hide verticalSection">
|
||||
<div class="sectionTitleContainer sectionTitleContainer-cards">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderLatestEpisodes}</h2>
|
||||
</div>
|
||||
|
||||
<div class="verticalSection">
|
||||
<div is="emby-itemscontainer" id="latestEpisodesItems" class="itemsContainer padded-left padded-right"></div>
|
||||
</div>
|
||||
|
||||
<div id="nextUpItemsSection" class="hide verticalSection">
|
||||
<div class="sectionTitleContainer sectionTitleContainer-cards">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left nextUpHeader">${NextUp}</h2>
|
||||
</div>
|
||||
|
@ -33,16 +40,7 @@
|
|||
</div>
|
||||
<p class="noNextUpItems" style="display: none;">${MessageNoNextUpItems}</p>
|
||||
</div>
|
||||
<div class="pageTabContent" id="latestTab" data-index="2">
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer sectionTitleContainer-cards">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderLatestEpisodes}</h2>
|
||||
</div>
|
||||
<div is="emby-itemscontainer" id="latestEpisodes" class="itemsContainer vertical-wrap padded-left padded-right">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" id="upcomingTab" data-index="3">
|
||||
<div class="pageTabContent" id="upcomingTab" data-index="2">
|
||||
<div id="upcomingItems">
|
||||
</div>
|
||||
<div class="noItemsMessage centerMessage" style="display: none;">
|
||||
|
@ -50,13 +48,13 @@
|
|||
<p>${MessagePleaseEnsureInternetMetadata}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" id="genresTab" data-index="4">
|
||||
<div class="pageTabContent" id="genresTab" data-index="3">
|
||||
<div id="items"></div>
|
||||
</div>
|
||||
<div class="pageTabContent" id="studiosTab" data-index="5">
|
||||
<div class="pageTabContent" id="studiosTab" data-index="4">
|
||||
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap" style="text-align: center;"></div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="6">
|
||||
<div class="pageTabContent" id="episodesTab" data-index="5">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
|
||||
<div class="paging"></div>
|
||||
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
|
||||
|
@ -69,6 +67,4 @@
|
|||
<div class="paging"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageTabContent" data-index="7">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,8 +20,6 @@ import 'emby-button';
|
|||
name: globalize.translate('Shows')
|
||||
}, {
|
||||
name: globalize.translate('Suggestions')
|
||||
}, {
|
||||
name: globalize.translate('TabLatest')
|
||||
}, {
|
||||
name: globalize.translate('TabUpcoming')
|
||||
}, {
|
||||
|
@ -38,15 +36,18 @@ import 'emby-button';
|
|||
case 'suggestions':
|
||||
return 1;
|
||||
|
||||
case 'latest':
|
||||
case 'upcoming':
|
||||
return 2;
|
||||
|
||||
case 'favorites':
|
||||
return 1;
|
||||
|
||||
case 'genres':
|
||||
return 3;
|
||||
|
||||
case 'networks':
|
||||
return 4;
|
||||
|
||||
case 'episodes':
|
||||
return 5;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -70,102 +71,159 @@ import 'emby-button';
|
|||
}
|
||||
}
|
||||
|
||||
function initSuggestedTab(page, tabContent) {
|
||||
const containers = tabContent.querySelectorAll('.itemsContainer');
|
||||
|
||||
for (let i = 0, length = containers.length; i < length; i++) {
|
||||
setScrollClasses(containers[i], enableScrollX());
|
||||
}
|
||||
}
|
||||
|
||||
function loadSuggestionsTab(view, params, tabContent) {
|
||||
const parentId = params.topParentId;
|
||||
const userId = ApiClient.getCurrentUserId();
|
||||
console.debug('loadSuggestionsTab');
|
||||
loadResume(tabContent, userId, parentId);
|
||||
loadLatest(tabContent, userId, parentId);
|
||||
loadNextUp(tabContent, userId, parentId);
|
||||
}
|
||||
|
||||
function loadResume(view, userId, parentId) {
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
const options = {
|
||||
SortBy: 'DatePlayed',
|
||||
SortOrder: 'Descending',
|
||||
IncludeItemTypes: 'Episode',
|
||||
Filters: 'IsResumable',
|
||||
Limit: screenWidth >= 1920 ? 5 : screenWidth >= 1600 ? 5 : 3,
|
||||
Recursive: true,
|
||||
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
|
||||
CollapseBoxSetItems: false,
|
||||
ParentId: parentId,
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
ApiClient.getItems(userId, options).then(function (result) {
|
||||
if (result.Items.length) {
|
||||
view.querySelector('#resumableSection').classList.remove('hide');
|
||||
} else {
|
||||
view.querySelector('#resumableSection').classList.add('hide');
|
||||
}
|
||||
|
||||
const allowBottomPadding = !enableScrollX();
|
||||
const container = view.querySelector('#resumableItems');
|
||||
cardBuilder.buildCards(result.Items, {
|
||||
itemsContainer: container,
|
||||
preferThumb: true,
|
||||
shape: getThumbShape(),
|
||||
scalable: true,
|
||||
overlayPlayButton: true,
|
||||
allowBottomPadding: allowBottomPadding,
|
||||
cardLayout: false,
|
||||
showTitle: true,
|
||||
showYear: true,
|
||||
centerText: true
|
||||
});
|
||||
loading.hide();
|
||||
|
||||
import('autoFocuser').then(({default: autoFocuser}) => {
|
||||
autoFocuser.autoFocus(view);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadLatest(view, userId, parentId) {
|
||||
const options = {
|
||||
userId: userId,
|
||||
IncludeItemTypes: 'Episode',
|
||||
Limit: 30,
|
||||
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
|
||||
ParentId: parentId,
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: 'Primary,Backdrop,Thumb'
|
||||
};
|
||||
ApiClient.getLatestItems(options).then(function (items) {
|
||||
const section = view.querySelector('#latestItemsSection');
|
||||
const allowBottomPadding = !enableScrollX();
|
||||
const container = section.querySelector('#latestEpisodesItems');
|
||||
cardBuilder.buildCards(items, {
|
||||
parentContainer: section,
|
||||
itemsContainer: container,
|
||||
items: items,
|
||||
shape: 'backdrop',
|
||||
preferThumb: true,
|
||||
showTitle: true,
|
||||
showSeriesYear: true,
|
||||
showParentTitle: true,
|
||||
overlayText: false,
|
||||
cardLayout: false,
|
||||
allowBottomPadding: allowBottomPadding,
|
||||
showUnplayedIndicator: false,
|
||||
showChildCountIndicator: true,
|
||||
centerText: true,
|
||||
lazy: true,
|
||||
overlayPlayButton: true,
|
||||
lines: 2
|
||||
});
|
||||
loading.hide();
|
||||
|
||||
import('autoFocuser').then(({default: autoFocuser}) => {
|
||||
autoFocuser.autoFocus(view);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadNextUp(view, userId, parentId) {
|
||||
const query = {
|
||||
userId: userId,
|
||||
Limit: 24,
|
||||
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo',
|
||||
ParentId: parentId,
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: 'Primary,Backdrop,Thumb',
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
query.ParentId = libraryMenu.getTopParentId();
|
||||
ApiClient.getNextUpEpisodes(query).then(function (result) {
|
||||
if (result.Items.length) {
|
||||
view.querySelector('.noNextUpItems').classList.add('hide');
|
||||
} else {
|
||||
view.querySelector('.noNextUpItems').classList.remove('hide');
|
||||
}
|
||||
|
||||
const section = view.querySelector('#nextUpItemsSection');
|
||||
const container = section.querySelector('#nextUpItems');
|
||||
cardBuilder.buildCards(result.Items, {
|
||||
parentContainer: section,
|
||||
itemsContainer: container,
|
||||
preferThumb: true,
|
||||
shape: 'backdrop',
|
||||
scalable: true,
|
||||
showTitle: true,
|
||||
showParentTitle: true,
|
||||
overlayText: false,
|
||||
centerText: true,
|
||||
overlayPlayButton: true,
|
||||
cardLayout: false
|
||||
});
|
||||
loading.hide();
|
||||
|
||||
import('autoFocuser').then(({default: autoFocuser}) => {
|
||||
autoFocuser.autoFocus(view);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function enableScrollX() {
|
||||
return !layoutManager.desktop;
|
||||
}
|
||||
|
||||
function getThumbShape() {
|
||||
return enableScrollX() ? 'overflowBackdrop' : 'backdrop';
|
||||
}
|
||||
|
||||
export default function (view, params) {
|
||||
function reload() {
|
||||
loading.show();
|
||||
loadResume();
|
||||
loadNextUp();
|
||||
}
|
||||
|
||||
function loadNextUp() {
|
||||
const query = {
|
||||
Limit: 24,
|
||||
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo',
|
||||
UserId: ApiClient.getCurrentUserId(),
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: 'Primary,Backdrop,Thumb',
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
query.ParentId = libraryMenu.getTopParentId();
|
||||
ApiClient.getNextUpEpisodes(query).then(function (result) {
|
||||
if (result.Items.length) {
|
||||
view.querySelector('.noNextUpItems').classList.add('hide');
|
||||
} else {
|
||||
view.querySelector('.noNextUpItems').classList.remove('hide');
|
||||
}
|
||||
|
||||
const container = view.querySelector('#nextUpItems');
|
||||
cardBuilder.buildCards(result.Items, {
|
||||
itemsContainer: container,
|
||||
preferThumb: true,
|
||||
shape: 'backdrop',
|
||||
scalable: true,
|
||||
showTitle: true,
|
||||
showParentTitle: true,
|
||||
overlayText: false,
|
||||
centerText: true,
|
||||
overlayPlayButton: true,
|
||||
cardLayout: false
|
||||
});
|
||||
loading.hide();
|
||||
|
||||
import('autoFocuser').then(({default: autoFocuser}) => {
|
||||
autoFocuser.autoFocus(view);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function enableScrollX() {
|
||||
return !layoutManager.desktop;
|
||||
}
|
||||
|
||||
function getThumbShape() {
|
||||
return enableScrollX() ? 'overflowBackdrop' : 'backdrop';
|
||||
}
|
||||
|
||||
function loadResume() {
|
||||
const parentId = libraryMenu.getTopParentId();
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
const limit = screenWidth >= 1600 ? 5 : 6;
|
||||
const options = {
|
||||
SortBy: 'DatePlayed',
|
||||
SortOrder: 'Descending',
|
||||
IncludeItemTypes: 'Episode',
|
||||
Filters: 'IsResumable',
|
||||
Limit: limit,
|
||||
Recursive: true,
|
||||
Fields: 'PrimaryImageAspectRatio,SeriesInfo,UserData,BasicSyncInfo',
|
||||
ExcludeLocationTypes: 'Virtual',
|
||||
ParentId: parentId,
|
||||
ImageTypeLimit: 1,
|
||||
EnableImageTypes: 'Primary,Backdrop,Thumb',
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
ApiClient.getItems(ApiClient.getCurrentUserId(), options).then(function (result) {
|
||||
if (result.Items.length) {
|
||||
view.querySelector('#resumableSection').classList.remove('hide');
|
||||
} else {
|
||||
view.querySelector('#resumableSection').classList.add('hide');
|
||||
}
|
||||
|
||||
const allowBottomPadding = !enableScrollX();
|
||||
const container = view.querySelector('#resumableItems');
|
||||
cardBuilder.buildCards(result.Items, {
|
||||
itemsContainer: container,
|
||||
preferThumb: true,
|
||||
shape: getThumbShape(),
|
||||
scalable: true,
|
||||
showTitle: true,
|
||||
showParentTitle: true,
|
||||
overlayText: false,
|
||||
centerText: true,
|
||||
overlayPlayButton: true,
|
||||
allowBottomPadding: allowBottomPadding,
|
||||
cardLayout: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onBeforeTabChange(e) {
|
||||
preLoadTab(view, parseInt(e.detail.selectedTabIndex));
|
||||
}
|
||||
|
@ -196,22 +254,18 @@ import 'emby-button';
|
|||
break;
|
||||
|
||||
case 2:
|
||||
depends = 'controllers/shows/tvlatest';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
depends = 'controllers/shows/tvupcoming';
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 3:
|
||||
depends = 'controllers/shows/tvgenres';
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 4:
|
||||
depends = 'controllers/shows/tvstudios';
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 5:
|
||||
depends = 'controllers/shows/episodes';
|
||||
break;
|
||||
}
|
||||
|
@ -231,11 +285,6 @@ import 'emby-button';
|
|||
|
||||
if (index === 1) {
|
||||
controller = self;
|
||||
} else if (index === 7) {
|
||||
controller = new controllerFactory(view, tabContent, {
|
||||
collectionType: 'tvshows',
|
||||
parentId: params.topParentId
|
||||
});
|
||||
} else {
|
||||
controller = new controllerFactory(view, params, tabContent);
|
||||
}
|
||||
|
@ -294,19 +343,20 @@ import 'emby-button';
|
|||
|
||||
const self = this;
|
||||
let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId));
|
||||
const suggestionsTabIndex = 1;
|
||||
|
||||
self.initTab = function () {
|
||||
const tabContent = self.tabContent;
|
||||
setScrollClasses(tabContent.querySelector('#resumableItems'), enableScrollX());
|
||||
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||
initSuggestedTab(view, tabContent);
|
||||
};
|
||||
|
||||
self.renderTab = function () {
|
||||
reload();
|
||||
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
|
||||
loadSuggestionsTab(view, params, tabContent);
|
||||
};
|
||||
|
||||
const tabControllers = [];
|
||||
let renderedTabs = [];
|
||||
setScrollClasses(view.querySelector('#resumableItems'), enableScrollX());
|
||||
view.addEventListener('viewshow', function (e) {
|
||||
initTabs();
|
||||
if (!view.getAttribute('data-title')) {
|
||||
|
|
|
@ -54,8 +54,8 @@ import 'emby-itemscontainer';
|
|||
return context.savedQueryKey;
|
||||
}
|
||||
|
||||
function onViewStyleChange() {
|
||||
const viewStyle = self.getCurrentViewStyle();
|
||||
const onViewStyleChange = () => {
|
||||
const viewStyle = this.getCurrentViewStyle();
|
||||
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||
|
||||
if (viewStyle == 'List') {
|
||||
|
@ -67,13 +67,13 @@ import 'emby-itemscontainer';
|
|||
}
|
||||
|
||||
itemsContainer.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
function reloadItems(page) {
|
||||
const reloadItems = (page) => {
|
||||
loading.show();
|
||||
isLoading = true;
|
||||
const query = getQuery(page);
|
||||
ApiClient.getItems(ApiClient.getCurrentUserId(), query).then(function (result) {
|
||||
ApiClient.getItems(ApiClient.getCurrentUserId(), query).then((result) => {
|
||||
function onNextPageClick() {
|
||||
if (isLoading) {
|
||||
return;
|
||||
|
@ -109,7 +109,7 @@ import 'emby-itemscontainer';
|
|||
sortButton: false,
|
||||
filterButton: false
|
||||
});
|
||||
const viewStyle = self.getCurrentViewStyle();
|
||||
const viewStyle = this.getCurrentViewStyle();
|
||||
if (viewStyle == 'Thumb') {
|
||||
html = cardBuilder.getCardsHtml({
|
||||
items: result.Items,
|
||||
|
@ -169,18 +169,18 @@ import 'emby-itemscontainer';
|
|||
|
||||
let elems = tabContent.querySelectorAll('.paging');
|
||||
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].innerHTML = pagingHtml;
|
||||
for (const elem of elems) {
|
||||
elem.innerHTML = pagingHtml;
|
||||
}
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('click', onNextPageClick);
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onNextPageClick);
|
||||
}
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('click', onPreviousPageClick);
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onPreviousPageClick);
|
||||
}
|
||||
|
||||
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||
|
@ -194,18 +194,26 @@ import 'emby-itemscontainer';
|
|||
autoFocuser.autoFocus(page);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function updateFilterControls(tabContent) {
|
||||
const updateFilterControls = (tabContent) => {
|
||||
const query = getQuery(tabContent);
|
||||
self.alphaPicker.value(query.NameStartsWithOrGreater);
|
||||
}
|
||||
|
||||
const self = this;
|
||||
if (this.alphaPicker) {
|
||||
this.alphaPicker.value(query.NameStartsWith);
|
||||
|
||||
if (query.SortBy.indexOf('SortName') === 0) {
|
||||
this.alphaPicker.visible(true);
|
||||
} else {
|
||||
this.alphaPicker.visible(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const data = {};
|
||||
let isLoading = false;
|
||||
|
||||
self.showFilterMenu = function () {
|
||||
this.showFilterMenu = function () {
|
||||
import('components/filterdialog/filterdialog').then(({default: filterDialogFactory}) => {
|
||||
const filterDialog = new filterDialogFactory({
|
||||
query: getQuery(tabContent),
|
||||
|
@ -220,22 +228,22 @@ import 'emby-itemscontainer';
|
|||
});
|
||||
};
|
||||
|
||||
self.getCurrentViewStyle = function () {
|
||||
this.getCurrentViewStyle = function () {
|
||||
return getPageData(tabContent).view;
|
||||
};
|
||||
|
||||
function initPage(tabContent) {
|
||||
const initPage = (tabContent) => {
|
||||
const alphaPickerElement = tabContent.querySelector('.alphaPicker');
|
||||
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||
|
||||
alphaPickerElement.addEventListener('alphavaluechanged', function (e) {
|
||||
const newValue = e.detail.value;
|
||||
const query = getQuery(tabContent);
|
||||
query.NameStartsWithOrGreater = newValue;
|
||||
query.NameStartsWith = newValue;
|
||||
query.StartIndex = 0;
|
||||
reloadItems(tabContent);
|
||||
});
|
||||
self.alphaPicker = new AlphaPicker({
|
||||
this.alphaPicker = new AlphaPicker({
|
||||
element: alphaPickerElement,
|
||||
valueChangeEvent: 'click'
|
||||
});
|
||||
|
@ -244,8 +252,8 @@ import 'emby-itemscontainer';
|
|||
alphaPickerElement.classList.add('alphaPicker-fixed-right');
|
||||
itemsContainer.classList.add('padded-right-withalphapicker');
|
||||
|
||||
tabContent.querySelector('.btnFilter').addEventListener('click', function () {
|
||||
self.showFilterMenu();
|
||||
tabContent.querySelector('.btnFilter').addEventListener('click', () => {
|
||||
this.showFilterMenu();
|
||||
});
|
||||
tabContent.querySelector('.btnSort').addEventListener('click', function (e) {
|
||||
libraryBrowser.showSortMenu({
|
||||
|
@ -277,8 +285,8 @@ import 'emby-itemscontainer';
|
|||
});
|
||||
});
|
||||
const btnSelectView = tabContent.querySelector('.btnSelectView');
|
||||
btnSelectView.addEventListener('click', function (e) {
|
||||
libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
|
||||
btnSelectView.addEventListener('click', (e) => {
|
||||
libraryBrowser.showLayoutMenu(e.target, this.getCurrentViewStyle(), 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(','));
|
||||
});
|
||||
btnSelectView.addEventListener('layoutchange', function (e) {
|
||||
const viewStyle = e.detail.viewStyle;
|
||||
|
@ -288,17 +296,17 @@ import 'emby-itemscontainer';
|
|||
onViewStyleChange();
|
||||
reloadItems(tabContent);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
initPage(tabContent);
|
||||
onViewStyleChange();
|
||||
|
||||
self.renderTab = function () {
|
||||
this.renderTab = function () {
|
||||
reloadItems(tabContent);
|
||||
updateFilterControls(tabContent);
|
||||
};
|
||||
|
||||
self.destroy = function () {};
|
||||
this.destroy = function () {};
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -48,6 +48,16 @@
|
|||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="lnkQuickConnectPreferences listItem-border">
|
||||
<div class="listItem">
|
||||
<em class="material-icons listItemIcon listItemIcon-transparent">tap_and_play</em>
|
||||
<div class="listItemBody">
|
||||
<div class="listItemBodyText">${QuickConnect}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="clientSettings listItem-border">
|
||||
<div class="listItem">
|
||||
<span class="material-icons listItemIcon listItemIcon-transparent devices_other"></span>
|
||||
|
|
|
@ -26,6 +26,7 @@ export default function (view, params) {
|
|||
page.querySelector('.lnkHomePreferences').setAttribute('href', 'mypreferenceshome.html?userId=' + userId);
|
||||
page.querySelector('.lnkPlaybackPreferences').setAttribute('href', 'mypreferencesplayback.html?userId=' + userId);
|
||||
page.querySelector('.lnkSubtitlePreferences').setAttribute('href', 'mypreferencessubtitles.html?userId=' + userId);
|
||||
page.querySelector('.lnkQuickConnectPreferences').setAttribute('href', 'mypreferencesquickconnect.html');
|
||||
|
||||
if (window.NativeShell && window.NativeShell.AppHost.supports('clientsettings')) {
|
||||
page.querySelector('.clientSettings').classList.remove('hide');
|
||||
|
|
17
src/controllers/user/quickConnect/index.html
Normal file
17
src/controllers/user/quickConnect/index.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<div id="quickConnectPreferencesPage" data-role="page" class="page libraryPage userPreferencesPage noSecondaryNavPage" data-title="${QuickConnect}" data-backbutton="true" style="margin: 0 auto; max-width: 54em">
|
||||
<button is="emby-button" id="btnQuickConnectActivate" type="button" class="raised button-submit block">
|
||||
<span>${ButtonActivate}</span>
|
||||
</button>
|
||||
|
||||
<form class="quickConnectSettingsContainer">
|
||||
<div style="margin-bottom: 1em">
|
||||
${QuickConnectDescription}
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" min="0" max="999999" required id="txtQuickConnectCode" label="${LabelQuickConnectCode}" autocomplete="off" />
|
||||
</div>
|
||||
<button id="btnQuickConnectAuthorize" is="emby-button" type="submit" class="raised button-submit block">
|
||||
<span>${Authorize}</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
61
src/controllers/user/quickConnect/index.js
Normal file
61
src/controllers/user/quickConnect/index.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
import QuickConnectSettings from 'quickConnectSettings';
|
||||
import globalize from 'globalize';
|
||||
import toast from 'toast';
|
||||
|
||||
export default function (view) {
|
||||
let quickConnectSettingsInstance = null;
|
||||
|
||||
view.addEventListener('viewshow', function () {
|
||||
const codeElement = view.querySelector('#txtQuickConnectCode');
|
||||
|
||||
quickConnectSettingsInstance = new QuickConnectSettings();
|
||||
|
||||
view.querySelector('#btnQuickConnectActivate').addEventListener('click', () => {
|
||||
quickConnectSettingsInstance.activate(quickConnectSettingsInstance).then(() => {
|
||||
renderPage();
|
||||
});
|
||||
});
|
||||
|
||||
view.querySelector('#btnQuickConnectAuthorize').addEventListener('click', () => {
|
||||
if (!codeElement.validity.valid) {
|
||||
toast(globalize.translate('QuickConnectInvalidCode'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const code = codeElement.value;
|
||||
quickConnectSettingsInstance.authorize(code);
|
||||
});
|
||||
|
||||
view.querySelector('.quickConnectSettingsContainer').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
renderPage();
|
||||
});
|
||||
|
||||
function renderPage(forceActive = false) {
|
||||
ApiClient.getQuickConnect('Status').then((status) => {
|
||||
const btn = view.querySelector('#btnQuickConnectActivate');
|
||||
const container = view.querySelector('.quickConnectSettingsContainer');
|
||||
|
||||
// The activation button should only be visible when quick connect is unavailable (with the text replaced with an error) or when it is available (so it can be activated)
|
||||
// The authorization container is only usable when quick connect is active, so it should be hidden otherwise
|
||||
container.style.display = 'none';
|
||||
|
||||
if (status === 'Unavailable') {
|
||||
btn.textContent = globalize.translate('QuickConnectNotAvailable');
|
||||
btn.disabled = true;
|
||||
btn.classList.remove('button-submit');
|
||||
btn.classList.add('button');
|
||||
} else if (status === 'Active' || forceActive) {
|
||||
container.style.display = '';
|
||||
btn.style.display = 'none';
|
||||
}
|
||||
|
||||
return true;
|
||||
}).catch((e) => {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue