diff --git a/dashboard-ui/bower_components/emby-apiclient/apiclient.js b/dashboard-ui/bower_components/emby-apiclient/apiclient.js index 9a56f8e1d9..ab55290e68 100644 --- a/dashboard-ui/bower_components/emby-apiclient/apiclient.js +++ b/dashboard-ui/bower_components/emby-apiclient/apiclient.js @@ -1739,7 +1739,7 @@ * Adds a virtual folder * @param {String} name */ - self.addVirtualFolder = function (name, type, refreshLibrary, initialPaths, libraryOptions) { + self.addVirtualFolder = function (name, type, refreshLibrary, libraryOptions) { if (!name) { throw new Error("null name"); @@ -1762,7 +1762,6 @@ type: "POST", url: url, data: JSON.stringify({ - Paths: initialPaths, LibraryOptions: libraryOptions }), contentType: 'application/json' @@ -1817,7 +1816,7 @@ * Adds an additional mediaPath to an existing virtual folder * @param {String} name */ - self.addMediaPath = function (virtualFolderName, mediaPath, refreshLibrary) { + self.addMediaPath = function (virtualFolderName, mediaPath, networkSharePath, refreshLibrary) { if (!virtualFolderName) { throw new Error("null virtualFolderName"); @@ -1829,15 +1828,50 @@ var url = "Library/VirtualFolders/Paths"; + var pathInfo = { + Path: mediaPath + }; + if (networkSharePath) { + pathInfo.NetworkPath = networkSharePath; + } + url = self.getUrl(url, { - refreshLibrary: refreshLibrary ? true : false, - path: mediaPath, - name: virtualFolderName + refreshLibrary: refreshLibrary ? true : false }); return self.ajax({ type: "POST", - url: url + url: url, + data: JSON.stringify({ + Name: virtualFolderName, + PathInfo: pathInfo + }), + contentType: 'application/json' + }); + }; + + self.updateMediaPath = function (virtualFolderName, pathInfo) { + + if (!virtualFolderName) { + throw new Error("null virtualFolderName"); + } + + if (!pathInfo) { + throw new Error("null pathInfo"); + } + + var url = "Library/VirtualFolders/Paths/Update"; + + url = self.getUrl(url); + + return self.ajax({ + type: "POST", + url: url, + data: JSON.stringify({ + Name: virtualFolderName, + PathInfo: pathInfo + }), + contentType: 'application/json' }); }; diff --git a/dashboard-ui/bower_components/emby-webcomponents/itemhovermenu/itemhovermenu.js b/dashboard-ui/bower_components/emby-webcomponents/itemhovermenu/itemhovermenu.js index a24fe6488d..e02e083a62 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/itemhovermenu/itemhovermenu.js +++ b/dashboard-ui/bower_components/emby-webcomponents/itemhovermenu/itemhovermenu.js @@ -243,7 +243,7 @@ showOverlayTimeout = setTimeout(function () { onShowTimerExpired(card); - }, 1000); + }, 1200); } function preventTouchHover() { diff --git a/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingfields.template.html b/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingfields.template.html index 0b5610bfd7..c45dcc38a7 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingfields.template.html +++ b/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingfields.template.html @@ -17,6 +17,10 @@ color: #cc3333; } + .manageButtonText { + text-transform: none; + } + @media all and (max-width: 440px) { .manageButtonText { diff --git a/dashboard-ui/components/directorybrowser/directorybrowser.css b/dashboard-ui/components/directorybrowser/directorybrowser.css index 7822a3bf94..2fe861ee16 100644 --- a/dashboard-ui/components/directorybrowser/directorybrowser.css +++ b/dashboard-ui/components/directorybrowser/directorybrowser.css @@ -12,5 +12,4 @@ background: #fff3a5; padding: 1em; border-radius: 5px; - margin-top: 2em; } \ No newline at end of file diff --git a/dashboard-ui/components/directorybrowser/directorybrowser.js b/dashboard-ui/components/directorybrowser/directorybrowser.js index 5d70e2fa9a..5d73df62e6 100644 --- a/dashboard-ui/components/directorybrowser/directorybrowser.js +++ b/dashboard-ui/components/directorybrowser/directorybrowser.js @@ -1,4 +1,4 @@ -define(['dialogHelper', 'jQuery', 'listViewStyle', 'emby-input', 'emby-button', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle'], function (dialogHelper, $) { +define(['dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-button', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle'], function (dialogHelper, dom) { var systemInfo; function getSystemInfo() { @@ -29,12 +29,6 @@ } Dashboard.showLoadingMsg(); - if (path) { - $('.networkHeadline').hide(); - } else { - $('.networkHeadline').show(); - } - var promises = []; if (path === "Network") { @@ -53,7 +47,7 @@ var folders = responses[0]; var parentPath = responses[1] || ''; - $('#txtDirectoryPickerPath', page).val(path || ""); + page.querySelector('#txtDirectoryPickerPath').value = path || ""; var html = ''; @@ -75,14 +69,14 @@ html += getItem("lnkPath lnkDirectory", "", "Network", Globalize.translate('ButtonNetwork')); } - $('.results', page).html(html); + page.querySelector('.results').innerHTML = html; Dashboard.hideLoadingMsg(); }, function () { - $('#txtDirectoryPickerPath', page).val(""); - $('.results', page).html(''); + page.querySelector('#txtDirectoryPickerPath').value = ""; + page.querySelector('.results').innerHTML = ''; Dashboard.hideLoadingMsg(); }); @@ -108,44 +102,63 @@ var html = ''; html += '
'; - html += '
'; + html += '
'; - var instruction = options.instruction ? options.instruction + '

' : ''; + if (!options.pathReadOnly) { + var instruction = options.instruction ? options.instruction + '

' : ''; - html += '

'; - html += instruction; - html += Globalize.translate('MessageDirectoryPickerInstruction') - .replace('{0}', '\\\\server') - .replace('{1}', '\\\\192.168.1.101'); + html += '

'; + html += instruction; + html += Globalize.translate('MessageDirectoryPickerInstruction') + .replace('{0}', '\\\\server') + .replace('{1}', '\\\\192.168.1.101'); - if (systemInfo.OperatingSystem.toLowerCase() == 'bsd') { + if (systemInfo.OperatingSystem.toLowerCase() == 'bsd') { - html += '
'; - html += '
'; - html += Globalize.translate('MessageDirectoryPickerBSDInstruction'); - html += '
'; - html += '' + Globalize.translate('ButtonMoreInformation') + ''; + html += '
'; + html += '
'; + html += Globalize.translate('MessageDirectoryPickerBSDInstruction'); + html += '
'; + html += '' + Globalize.translate('ButtonMoreInformation') + ''; + } + else if (systemInfo.OperatingSystem.toLowerCase() == 'linux') { + + html += '
'; + html += '
'; + html += Globalize.translate('MessageDirectoryPickerLinuxInstruction'); + html += '
'; + } + + html += '
'; } - else if (systemInfo.OperatingSystem.toLowerCase() == 'linux') { - - html += '
'; - html += '
'; - html += Globalize.translate('MessageDirectoryPickerLinuxInstruction'); - html += '
'; - } - - html += '

'; html += '
'; html += '
'; html += '
'; - html += ''; - html += '
'; - html += ''; + var labelKey = options.includeFiles !== true ? 'LabelFolder' : 'LabelPath'; + var readOnlyAttribute = options.pathReadOnly ? ' readonly' : ''; + html += ''; html += '
'; - html += '
'; + if (!readOnlyAttribute) { + html += ''; + } + + html += '
'; + + if (!readOnlyAttribute) { + html += '
'; + } + + if (options.enableNetworkSharePath) { + html += '
'; + html += ''; + html += '
'; + html += Globalize.translate('LabelOptionalNetworkPathHelp'); + html += '
'; + html += '
'; + } html += '
'; html += ''; @@ -162,32 +175,49 @@ function initEditor(content, options, fileOptions) { - $(content).on("click", ".lnkPath", function () { + content.addEventListener("click", function (e) { - var path = this.getAttribute('data-path'); + var lnkPath = dom.parentWithClass(e.target, 'lnkPath'); + if (lnkPath) { + var path = lnkPath.getAttribute('data-path'); - if ($(this).hasClass('lnkFile')) { - $('#txtDirectoryPickerPath', content).val(path); - } else { - refreshDirectoryBrowser(content, path, fileOptions); + if (lnkPath.classList.contains('lnkFile')) { + content.querySelector('#txtDirectoryPickerPath').value = path; + } else { + refreshDirectoryBrowser(content, path, fileOptions); + } } - }).on("click", ".btnRefreshDirectories", function () { - - var path = $('#txtDirectoryPickerPath', content).val(); - - refreshDirectoryBrowser(content, path, fileOptions); - - }).on("change", "#txtDirectoryPickerPath", function () { - - refreshDirectoryBrowser(content, this.value, fileOptions); }); - $('form', content).on('submit', function () { + content.addEventListener("click", function (e) { + + var btnRefreshDirectories = dom.parentWithClass(e.target, 'btnRefreshDirectories'); + if (btnRefreshDirectories) { + var path = content.querySelector('#txtDirectoryPickerPath').value; + + refreshDirectoryBrowser(content, path, fileOptions); + } + }); + + content.addEventListener("change", function (e) { + + var txtDirectoryPickerPath = dom.parentWithTag(e.target, 'INPUT'); + if (txtDirectoryPickerPath && txtDirectoryPickerPath.id == 'txtDirectoryPickerPath') { + refreshDirectoryBrowser(content, txtDirectoryPickerPath.value, fileOptions); + } + }); + + content.querySelector('form').addEventListener('submit', function (e) { if (options.callback) { - options.callback(this.querySelector('#txtDirectoryPickerPath').value); + + var networkSharePath = this.querySelector('#txtNetworkPath'); + networkSharePath = networkSharePath ? networkSharePath.value : null; + options.callback(this.querySelector('#txtDirectoryPickerPath').value, networkSharePath); } + e.preventDefault(); + e.stopPropagation(); return false; }); } @@ -259,15 +289,11 @@ initEditor(dlg, options, fileOptions); - // Has to be assigned a z-index after the call to .open() - $(dlg).on('iron-overlay-opened', function () { - this.querySelector('#txtDirectoryPickerPath input').focus(); - }); - $(dlg).on('close', onDialogClosed); + dlg.addEventListener('close', onDialogClosed); dialogHelper.open(dlg); - $('.btnCloseDialog', dlg).on('click', function () { + dlg.querySelector('.btnCloseDialog').addEventListener('click', function () { dialogHelper.close(dlg); }); @@ -276,7 +302,15 @@ var txtCurrentPath = dlg.querySelector('#txtDirectoryPickerPath'); txtCurrentPath.value = initialPath; - refreshDirectoryBrowser(dlg, txtCurrentPath.value); + + var txtNetworkPath = dlg.querySelector('#txtNetworkPath'); + if (txtNetworkPath) { + txtNetworkPath.value = options.networkSharePath || ''; + } + + if (!options.pathReadOnly) { + refreshDirectoryBrowser(dlg, txtCurrentPath.value); + } }); }; diff --git a/dashboard-ui/components/imageuploader/imageuploader.template.html b/dashboard-ui/components/imageuploader/imageuploader.template.html index 06793f9699..a36f163a26 100644 --- a/dashboard-ui/components/imageuploader/imageuploader.template.html +++ b/dashboard-ui/components/imageuploader/imageuploader.template.html @@ -13,7 +13,7 @@
- diff --git a/dashboard-ui/components/medialibrarycreator/medialibrarycreator.js b/dashboard-ui/components/medialibrarycreator/medialibrarycreator.js index 339ffeba15..71f8d1735f 100644 --- a/dashboard-ui/components/medialibrarycreator/medialibrarycreator.js +++ b/dashboard-ui/components/medialibrarycreator/medialibrarycreator.js @@ -3,11 +3,11 @@ var currentDeferred; var hasChanges; var currentOptions; - var paths = []; + var pathInfos = []; function onSubmit() { - if (paths.length == 0) { + if (pathInfos.length == 0) { require(['alert'], function (alert) { alert({ text: Globalize.translate('PleaseAddAtLeastOneFolder'), @@ -29,7 +29,9 @@ var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions')); - ApiClient.addVirtualFolder(name, type, currentOptions.refresh, paths, libraryOptions).then(function () { + libraryOptions.PathInfos = pathInfos; + + ApiClient.addVirtualFolder(name, type, currentOptions.refresh, libraryOptions).then(function () { hasChanges = true; dialogHelper.close(dlg); @@ -111,10 +113,11 @@ picker.show({ - callback: function (path) { + enableNetworkSharePath: true, + callback: function (path, networkSharePath) { if (path) { - addMediaLocation(page, path); + addMediaLocation(page, path, networkSharePath); } picker.close(); } @@ -123,7 +126,7 @@ }); } - function getFolderHtml(path, index) { + function getFolderHtml(pathInfo, index) { var html = ''; @@ -131,8 +134,14 @@ html += 'folder'; - html += '
'; - html += '
' + path + '
'; + var cssClass = pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody'; + + html += '
'; + html += '
' + pathInfo.Path + '
'; + + if (pathInfo.NetworkPath) { + html += '
' + pathInfo.NetworkPath + '
'; + } html += '
'; html += ''; @@ -143,7 +152,7 @@ } function renderPaths(page) { - var foldersHtml = paths.map(getFolderHtml).join(''); + var foldersHtml = pathInfos.map(getFolderHtml).join(''); var folderList = page.querySelector('.folderList'); folderList.innerHTML = foldersHtml; @@ -157,14 +166,21 @@ $(page.querySelectorAll('.btnRemovePath')).on('click', onRemoveClick); } - function addMediaLocation(page, path) { + function addMediaLocation(page, path, networkSharePath) { - if (paths.filter(function (p) { + if (pathInfos.filter(function (p) { - return p.toLowerCase() == path.toLowerCase(); + return p.Path.toLowerCase() == path.toLowerCase(); }).length == 0) { - paths.push(path); + + var pathInfo = { + Path: path + }; + if (networkSharePath) { + pathInfo.NetworkPath = networkSharePath; + } + pathInfos.push(pathInfo); renderPaths(page); } } @@ -174,10 +190,10 @@ var button = this; var index = parseInt(button.getAttribute('data-index')); - var location = paths[index]; - paths = paths.filter(function (p) { + var location = pathInfos[index]; + pathInfos = pathInfos.filter(function (p) { - return p.toLowerCase() != location.toLowerCase(); + return p.Path.toLowerCase() != location.toLowerCase(); }); var page = $(this).parents('.dlg-librarycreator')[0]; renderPaths(page); @@ -190,7 +206,7 @@ } function initLibraryOptions(dlg) { - libraryoptionseditor.embed(dlg.querySelector('.libraryOptions')).then(function() { + libraryoptionseditor.embed(dlg.querySelector('.libraryOptions')).then(function () { $('#selectCollectionType', dlg).trigger('change'); }); } @@ -241,7 +257,7 @@ dialogHelper.close(dlg); }); - paths = []; + pathInfos = []; renderPaths(dlg); initLibraryOptions(dlg); } diff --git a/dashboard-ui/components/medialibraryeditor/medialibraryeditor.js b/dashboard-ui/components/medialibraryeditor/medialibraryeditor.js index 7c1d9e501b..0459d164e9 100644 --- a/dashboard-ui/components/medialibraryeditor/medialibraryeditor.js +++ b/dashboard-ui/components/medialibraryeditor/medialibraryeditor.js @@ -4,13 +4,13 @@ var hasChanges; var currentOptions; - function addMediaLocation(page, path) { + function addMediaLocation(page, path, networkSharePath) { var virtualFolder = currentOptions.library; var refreshAfterChange = currentOptions.refresh; - ApiClient.addMediaPath(virtualFolder.Name, path, refreshAfterChange).then(function () { + ApiClient.addMediaPath(virtualFolder.Name, path, networkSharePath, refreshAfterChange).then(function () { hasChanges = true; refreshLibraryFromServer(page); @@ -23,9 +23,30 @@ }); } - function onRemoveClick() { + function updateMediaLocation(page, path, networkSharePath) { + var virtualFolder = currentOptions.library; - var button = this; + ApiClient.updateMediaPath(virtualFolder.Name, { + + Path: path, + NetworkPath: networkSharePath + + }).then(function () { + + hasChanges = true; + refreshLibraryFromServer(page); + + }, function () { + + require(['toast'], function (toast) { + toast(Globalize.translate('ErrorAddingMediaPathToVirtualFolder')); + }); + }); + } + + function onRemoveClick(btnRemovePath) { + + var button = btnRemovePath; var index = parseInt(button.getAttribute('data-index')); var virtualFolder = currentOptions.library; @@ -35,10 +56,10 @@ require(['confirm'], function (confirm) { confirm({ - + title: Globalize.translate('HeaderRemoveMediaLocation'), text: Globalize.translate('MessageConfirmRemoveMediaLocation'), - confirmText: Globalize.translate('sharedcomponents#ButtonDelete'), + confirmText: Globalize.translate('ButtonDelete'), primary: 'cancel' }).then(function () { @@ -60,18 +81,42 @@ }); } - function getFolderHtml(path, index) { + function onListItemClick(e) { + + var btnRemovePath = dom.parentWithClass(e.target, 'btnRemovePath'); + if (btnRemovePath) { + onRemoveClick(btnRemovePath); + return; + } + + var listItem = dom.parentWithClass(e.target, 'listItem'); + if (!listItem) { + return; + } + + var index = parseInt(listItem.getAttribute('data-index')); + var page = dom.parentWithClass(listItem, 'dlg-libraryeditor'); + showDirectoryBrowser(page, index); + } + + function getFolderHtml(pathInfo, index) { var html = ''; - html += '
'; + html += '
'; html += 'folder'; - html += '
'; + var cssClass = pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody'; + + html += '
'; + html += '

'; - html += path; + html += pathInfo.Path; html += '

'; + if (pathInfo.NetworkPath) { + html += '
' + pathInfo.NetworkPath + '
'; + } html += '
'; html += ''; @@ -99,13 +144,24 @@ } function renderLibrary(page, options) { - var foldersHtml = options.library.Locations.map(getFolderHtml).join(''); + + var pathInfos = (options.library.LibraryOptions || {}).PathInfos || []; + + if (!pathInfos.length) { + pathInfos = options.library.Locations.map(function (p) { + return { + Path: p + }; + }); + } + + var foldersHtml = pathInfos.map(getFolderHtml).join(''); page.querySelector('.folderList').innerHTML = foldersHtml; - var btnRemovePath = page.querySelectorAll('.btnRemovePath'); - for (var i = 0, length = btnRemovePath.length; i < length; i++) { - btnRemovePath[i].addEventListener('click', onRemoveClick); + var listItems = page.querySelectorAll('.listItem'); + for (var i = 0, length = listItems.length; i < length; i++) { + listItems[i].addEventListener('click', onListItemClick); } } @@ -113,16 +169,35 @@ var page = dom.parentWithClass(this, 'dlg-libraryeditor'); + showDirectoryBrowser(page); + } + + function showDirectoryBrowser(context, listIndex) { + require(['directorybrowser'], function (directoryBrowser) { var picker = new directoryBrowser(); + var pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || []; + var pathInfo = listIndex == null ? {} : (pathInfos[listIndex] || {}); + // legacy + var location = listIndex == null ? null : (currentOptions.library.Locations[listIndex]); + var originalPath = pathInfo.Path || location; + picker.show({ - callback: function (path) { + enableNetworkSharePath: true, + pathReadOnly: listIndex != null, + path: originalPath, + networkSharePath: pathInfo.NetworkPath, + callback: function (path, networkSharePath) { if (path) { - addMediaLocation(page, path); + if (originalPath) { + updateMediaLocation(context, originalPath, networkSharePath); + } else { + addMediaLocation(context, path, networkSharePath); + } } picker.close(); } @@ -145,6 +220,8 @@ var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions')); + libraryOptions = Object.assign(currentOptions.library.LibraryOptions || {}, libraryOptions); + ApiClient.updateVirtualFolderOptions(currentOptions.library.ItemId, libraryOptions); } diff --git a/dashboard-ui/css/librarymenu.css b/dashboard-ui/css/librarymenu.css index 9314405bd3..7e5bd5a8b4 100644 --- a/dashboard-ui/css/librarymenu.css +++ b/dashboard-ui/css/librarymenu.css @@ -246,7 +246,7 @@ body:not(.dashboardDocument) .btnNotifications { } i.sidebarLinkIcon { - font-size: 150%; + font-size: 120%; height: auto; width: auto; } diff --git a/dashboard-ui/dashboard.html b/dashboard-ui/dashboard.html index d083ae30c7..6dc6ca0388 100644 --- a/dashboard-ui/dashboard.html +++ b/dashboard-ui/dashboard.html @@ -35,7 +35,9 @@

- +
${PleaseUpdateManually} diff --git a/dashboard-ui/scripts/dashboardpage.js b/dashboard-ui/scripts/dashboardpage.js index 85984c5477..007efc99d9 100644 --- a/dashboard-ui/scripts/dashboardpage.js +++ b/dashboard-ui/scripts/dashboardpage.js @@ -986,7 +986,7 @@ html += '

' + Globalize.translate('NewVersionOfSomethingAvailable').replace('{0}', update.name) + '

'; - html += ''; + html += ''; } elem.html(html); diff --git a/dashboard-ui/scripts/userlibraryaccess.js b/dashboard-ui/scripts/userlibraryaccess.js index e07826168b..6d688424e4 100644 --- a/dashboard-ui/scripts/userlibraryaccess.js +++ b/dashboard-ui/scripts/userlibraryaccess.js @@ -70,7 +70,7 @@ var checkedAttribute = user.Policy.EnableAllDevices || user.Policy.EnabledDevices.indexOf(device.Id) != -1 ? ' checked="checked"' : ''; - html += ''; + html += ''; } html += '
'; diff --git a/dashboard-ui/strings/en-US.json b/dashboard-ui/strings/en-US.json index fde54094d3..5b5c16073e 100644 --- a/dashboard-ui/strings/en-US.json +++ b/dashboard-ui/strings/en-US.json @@ -2137,5 +2137,7 @@ "HeaderForKids": "For Kids", "HeaderRecordingGroups": "Recording Groups", "LabelConvertRecordingsTo": "Convert recordings to:", - "HeaderUpcomingOnTV": "Upcoming On TV" + "HeaderUpcomingOnTV": "Upcoming On TV", + "LabelOptionalNetworkPath": "(Optional) Shared network folder:", + "LabelOptionalNetworkPathHelp": "If this folder is shared on your network, supplying the network share path can allow Emby apps on other devices to access media files directly." }