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

490 lines
18 KiB
JavaScript
Raw Normal View History

2020-08-14 08:46:34 +02:00
import dialogHelper from '../dialogHelper/dialogHelper';
import loading from '../loading/loading';
import dom from '../../scripts/dom';
import layoutManager from '../layoutManager';
import focusManager from '../focusManager';
import globalize from '../../scripts/globalize';
import scrollHelper from '../../scripts/scrollHelper';
import imageLoader from '../images/imageLoader';
import browser from '../../scripts/browser';
2020-08-16 20:24:45 +02:00
import { appHost } from '../apphost';
2021-01-26 16:25:38 -05:00
import '../cardbuilder/card.scss';
import '../formdialog.scss';
2020-08-14 08:46:34 +02:00
import '../../elements/emby-button/emby-button';
import '../../elements/emby-button/paper-icon-button-light';
2021-01-26 16:25:38 -05:00
import './imageeditor.scss';
import ServerConnections from '../ServerConnections';
import alert from '../alert';
import confirm from '../confirm/confirm';
2020-11-25 00:17:24 -05:00
import template from './imageeditor.template.html';
/* eslint-disable indent */
const enableFocusTransform = !browser.slow && !browser.edge;
let currentItem;
let hasChanges = false;
2018-10-23 01:05:09 +03:00
function getBaseRemoteOptions() {
const options = {};
options.itemId = currentItem.Id;
return options;
2018-10-23 01:05:09 +03:00
}
function reload(page, item, focusContext) {
loading.show();
let apiClient;
if (item) {
apiClient = ServerConnections.getApiClient(item.ServerId);
reloadItem(page, item, apiClient, focusContext);
} else {
apiClient = ServerConnections.getApiClient(currentItem.ServerId);
apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function (item) {
reloadItem(page, item, apiClient, focusContext);
});
}
2018-10-23 01:05:09 +03:00
}
function addListeners(container, className, eventName, fn) {
container.addEventListener(eventName, function (e) {
const elem = dom.parentWithClass(e.target, className);
if (elem) {
fn.call(elem, e);
}
});
2018-10-23 01:05:09 +03:00
}
function reloadItem(page, item, apiClient, focusContext) {
currentItem = item;
apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) {
2020-10-07 21:12:14 +09:00
const btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages');
for (let i = 0, length = btnBrowseAllImages.length; i < length; i++) {
if (providers.length) {
btnBrowseAllImages[i].classList.remove('hide');
} else {
btnBrowseAllImages[i].classList.add('hide');
}
}
apiClient.getItemImageInfos(currentItem.Id).then(function (imageInfos) {
renderStandardImages(page, apiClient, item, imageInfos, providers);
renderBackdrops(page, apiClient, item, imageInfos, providers);
renderScreenshots(page, apiClient, item, imageInfos, providers);
loading.hide();
if (layoutManager.tv) {
focusManager.autoFocus((focusContext || page));
}
});
});
2018-10-23 01:05:09 +03:00
}
function getImageUrl(item, apiClient, type, index, options) {
options = options || {};
options.type = type;
options.index = index;
if (type === 'Backdrop') {
options.tag = item.BackdropImageTags[index];
} else if (type === 'Screenshot') {
options.tag = item.ScreenshotImageTags[index];
} else if (type === 'Primary') {
options.tag = item.PrimaryImageTag || item.ImageTags[type];
} else {
options.tag = item.ImageTags[type];
}
// For search hints
return apiClient.getScaledImageUrl(item.Id || item.ItemId, options);
2018-10-23 01:05:09 +03:00
}
function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
// TODO move card creation code to Card component
let html = '';
let cssClass = 'card scalableCard imageEditorCard';
const cardBoxCssClass = 'cardBox visualCardBox';
2020-05-04 12:44:12 +02:00
cssClass += ' backdropCard backdropCard-scalable';
if (tagName === 'button') {
cssClass += ' btnImageCard';
if (layoutManager.tv) {
cssClass += ' show-focus';
if (enableFocusTransform) {
cssClass += ' show-animation';
}
}
html += '<button type="button" class="' + cssClass + '"';
} else {
html += '<div class="' + cssClass + '"';
}
html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + index + '" data-numimages="' + numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + imageProviders.length + '"';
html += '>';
html += '<div class="' + cardBoxCssClass + '">';
html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">';
html += '<div class="cardPadder-backdrop"></div>';
html += '<div class="cardContent">';
const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
2020-05-27 07:17:06 +01:00
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center center;background-size:contain;"></div>';
html += '</div>';
html += '</div>';
html += '<div class="cardFooter visualCardBox-cardFooter">';
html += '<h3 class="cardText cardTextCentered" style="margin:0;">' + globalize.translate('' + image.ImageType) + '</h3>';
html += '<div class="cardText cardText-secondary cardTextCentered">';
if (image.Width && image.Height) {
html += image.Width + ' X ' + image.Height;
} else {
html += '&nbsp;';
}
html += '</div>';
if (enableFooterButtons) {
html += '<div class="cardText cardTextCentered">';
2020-05-04 12:44:12 +02:00
if (image.ImageType === 'Backdrop' || image.ImageType === 'Screenshot') {
if (index > 0) {
2020-04-26 02:37:28 +03:00
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left"></span></button>';
} else {
2022-02-24 20:15:24 +03:00
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left" aria-hidden="true"></span></button>';
}
if (index < numImages - 1) {
2022-02-24 20:15:24 +03:00
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex + 1) + '" title="' + globalize.translate('MoveRight') + '"><span class="material-icons chevron_right" aria-hidden="true"></span></button>';
} else {
2022-02-24 20:15:24 +03:00
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('MoveRight') + '"><span class="material-icons chevron_right" aria-hidden="true"></span></button>';
}
} else {
if (imageProviders.length) {
2022-02-24 20:15:24 +03:00
html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" class="btnSearchImages autoSize" title="' + globalize.translate('Search') + '"><span class="material-icons search" aria-hidden="true"></span></button>';
}
}
2022-02-24 20:15:24 +03:00
html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" data-index="' + (image.ImageIndex != null ? image.ImageIndex : 'null') + '" class="btnDeleteImage autoSize" title="' + globalize.translate('Delete') + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
html += '</div>';
}
html += '</div>';
html += '</div>';
html += '</' + tagName + '>';
return html;
2018-10-23 01:05:09 +03:00
}
function deleteImage(context, itemId, type, index, apiClient, enableConfirmation) {
const afterConfirm = function () {
apiClient.deleteItemImage(itemId, type, index).then(function () {
hasChanges = true;
reload(context);
});
2018-10-23 01:05:09 +03:00
};
if (!enableConfirmation) {
afterConfirm();
return;
}
confirm({
text: globalize.translate('ConfirmDeleteImage'),
confirmText: globalize.translate('Delete'),
primary: 'delete'
}).then(afterConfirm);
2018-10-23 01:05:09 +03:00
}
function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) {
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function () {
hasChanges = true;
reload(context, null, focusContext);
}, function () {
alert(globalize.translate('ErrorDefault'));
});
2018-10-23 01:05:09 +03:00
}
function renderImages(page, item, apiClient, images, imageProviders, elem) {
let html = '';
let imageSize = 300;
const windowSize = dom.getWindowSize();
if (windowSize.innerWidth >= 1280) {
imageSize = Math.round(windowSize.innerWidth / 4);
}
const tagName = layoutManager.tv ? 'button' : 'div';
const enableFooterButtons = !layoutManager.tv;
for (let i = 0, length = images.length; i < length; i++) {
const image = images[i];
html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons);
2018-10-23 01:05:09 +03:00
}
elem.innerHTML = html;
imageLoader.lazyChildren(elem);
2018-10-23 01:05:09 +03:00
}
function renderStandardImages(page, apiClient, item, imageInfos, imageProviders) {
const images = imageInfos.filter(function (i) {
2020-05-04 12:44:12 +02:00
return i.ImageType !== 'Screenshot' && i.ImageType !== 'Backdrop' && i.ImageType !== 'Chapter';
});
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#images'));
2018-10-23 01:05:09 +03:00
}
function renderBackdrops(page, apiClient, item, imageInfos, imageProviders) {
const images = imageInfos.filter(function (i) {
2020-05-04 12:44:12 +02:00
return i.ImageType === 'Backdrop';
}).sort(function (a, b) {
return a.ImageIndex - b.ImageIndex;
2018-10-23 01:05:09 +03:00
});
if (images.length) {
page.querySelector('#backdropsContainer', page).classList.remove('hide');
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#backdrops'));
} else {
page.querySelector('#backdropsContainer', page).classList.add('hide');
}
2018-10-23 01:05:09 +03:00
}
function renderScreenshots(page, apiClient, item, imageInfos, imageProviders) {
const images = imageInfos.filter(function (i) {
2020-05-04 12:44:12 +02:00
return i.ImageType === 'Screenshot';
}).sort(function (a, b) {
return a.ImageIndex - b.ImageIndex;
2018-10-23 01:05:09 +03:00
});
if (images.length) {
page.querySelector('#screenshotsContainer', page).classList.remove('hide');
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#screenshots'));
} else {
page.querySelector('#screenshotsContainer', page).classList.add('hide');
}
2018-10-23 01:05:09 +03:00
}
function showImageDownloader(page, imageType) {
2020-08-14 08:46:34 +02:00
import('../imageDownloader/imageDownloader').then((ImageDownloader) => {
ImageDownloader.show(
currentItem.Id,
currentItem.ServerId,
currentItem.Type,
imageType,
currentItem.Type == 'Season' ? currentItem.ParentId : null
).then(function () {
hasChanges = true;
reload(page);
});
});
2018-10-23 01:05:09 +03:00
}
function showActionSheet(context, imageCard) {
const itemId = imageCard.getAttribute('data-id');
const serverId = imageCard.getAttribute('data-serverid');
const apiClient = ServerConnections.getApiClient(serverId);
const type = imageCard.getAttribute('data-imagetype');
const index = parseInt(imageCard.getAttribute('data-index'));
const providerCount = parseInt(imageCard.getAttribute('data-providers'));
const numImages = parseInt(imageCard.getAttribute('data-numimages'));
2020-08-14 08:46:34 +02:00
import('../actionSheet/actionSheet').then(({default: actionSheet}) => {
const commands = [];
2018-10-23 01:05:09 +03:00
commands.push({
name: globalize.translate('Delete'),
id: 'delete'
});
if (type === 'Backdrop' || type === 'Screenshot') {
if (index > 0) {
commands.push({
name: globalize.translate('MoveLeft'),
id: 'moveleft'
});
}
if (index < numImages - 1) {
commands.push({
name: globalize.translate('MoveRight'),
id: 'moveright'
});
}
}
if (providerCount) {
commands.push({
name: globalize.translate('Search'),
id: 'search'
});
}
actionSheet.show({
2018-10-23 01:05:09 +03:00
items: commands,
positionTo: imageCard
}).then(function (id) {
2018-10-23 01:05:09 +03:00
switch (id) {
case 'delete':
deleteImage(context, itemId, type, index, apiClient, false);
2018-10-23 01:05:09 +03:00
break;
case 'search':
2018-10-23 01:05:09 +03:00
showImageDownloader(context, type);
break;
case 'moveleft':
moveImage(context, apiClient, itemId, type, index, index - 1, dom.parentWithClass(imageCard, 'itemsContainer'));
break;
case 'moveright':
moveImage(context, apiClient, itemId, type, index, index + 1, dom.parentWithClass(imageCard, 'itemsContainer'));
break;
default:
2018-10-23 01:05:09 +03:00
break;
}
});
});
2018-10-23 01:05:09 +03:00
}
function initEditor(context, options) {
const uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
const isFileInputSupported = appHost.supports('fileinput');
for (let i = 0, length = uploadButtons.length; i < length; i++) {
if (isFileInputSupported) {
uploadButtons[i].classList.remove('hide');
} else {
uploadButtons[i].classList.add('hide');
}
}
addListeners(context, 'btnOpenUploadMenu', 'click', function () {
const imageType = this.getAttribute('data-imagetype');
2020-08-14 08:46:34 +02:00
import('../imageUploader/imageUploader').then(({default: imageUploader}) => {
2018-10-23 01:05:09 +03:00
imageUploader.show({
2018-10-23 01:05:09 +03:00
theme: options.theme,
imageType: imageType,
itemId: currentItem.Id,
serverId: currentItem.ServerId
}).then(function (hasChanged) {
if (hasChanged) {
hasChanges = true;
reload(context);
}
});
});
});
addListeners(context, 'btnSearchImages', 'click', function () {
showImageDownloader(context, this.getAttribute('data-imagetype'));
});
addListeners(context, 'btnBrowseAllImages', 'click', function () {
showImageDownloader(context, this.getAttribute('data-imagetype') || 'Primary');
});
addListeners(context, 'btnImageCard', 'click', function () {
showActionSheet(context, this);
});
addListeners(context, 'btnDeleteImage', 'click', function () {
const type = this.getAttribute('data-imagetype');
let index = this.getAttribute('data-index');
2020-05-04 12:44:12 +02:00
index = index === 'null' ? null : parseInt(index);
const apiClient = ServerConnections.getApiClient(currentItem.ServerId);
deleteImage(context, currentItem.Id, type, index, apiClient, true);
});
addListeners(context, 'btnMoveImage', 'click', function () {
const type = this.getAttribute('data-imagetype');
const index = this.getAttribute('data-index');
const newIndex = this.getAttribute('data-newindex');
const apiClient = ServerConnections.getApiClient(currentItem.ServerId);
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, 'itemsContainer'));
});
2018-10-23 01:05:09 +03:00
}
function showEditor(options, resolve, reject) {
const itemId = options.itemId;
const serverId = options.serverId;
loading.show();
2020-11-25 00:17:24 -05:00
const apiClient = ServerConnections.getApiClient(serverId);
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
const dialogOptions = {
removeOnClose: true
};
2020-11-25 00:17:24 -05:00
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
2020-11-25 00:17:24 -05:00
const dlg = dialogHelper.createDialog(dialogOptions);
2020-11-25 00:17:24 -05:00
dlg.classList.add('formDialog');
2020-11-25 00:17:24 -05:00
dlg.innerHTML = globalize.translateHtml(template, 'core');
2020-11-25 00:17:24 -05:00
if (layoutManager.tv) {
scrollHelper.centerFocus.on(dlg, false);
}
2020-11-25 00:17:24 -05:00
initEditor(dlg, options);
2020-11-25 00:17:24 -05:00
// Has to be assigned a z-index after the call to .open()
dlg.addEventListener('close', function () {
if (layoutManager.tv) {
scrollHelper.centerFocus.off(dlg, false);
}
2020-11-25 00:17:24 -05:00
loading.hide();
2020-11-25 00:17:24 -05:00
if (hasChanges) {
resolve();
} else {
reject();
}
});
2020-11-25 00:17:24 -05:00
dialogHelper.open(dlg);
2020-11-25 00:17:24 -05:00
reload(dlg, item);
2020-11-25 00:17:24 -05:00
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
});
}
export function show (options) {
return new Promise(function (resolve, reject) {
hasChanges = false;
showEditor(options, resolve, reject);
});
}
export default {
show
};
/* eslint-enable indent */