Files
jellyfin-web/src/components/slideshow/slideshow.js
T
MrTimscampi a98b961b94 Fix icons on WebOS
WebOS 4 apparently has a ligature bug that prevents icons with an underscore from working as intended.
This replaces them with either the corresponding CSS class or unicode escape code, depending on context.
Refactoring is needed in order to be able to use CSS classes everywhere, so in the interest of time, this does the best available currently.

Fixes #678
2020-02-16 01:33:34 +01:00

644 lines
20 KiB
JavaScript

define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'browser', 'apphost', 'loading', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (dialogHelper, inputManager, connectionManager, layoutManager, focusManager, browser, appHost, loading) {
'use strict';
function getImageUrl(item, options, apiClient) {
options = options || {};
options.type = options.type || "Primary";
if (typeof (item) === 'string') {
return apiClient.getScaledImageUrl(item, options);
}
if (item.ImageTags && item.ImageTags[options.type]) {
options.tag = item.ImageTags[options.type];
return apiClient.getScaledImageUrl(item.Id, options);
}
if (options.type === 'Primary') {
if (item.AlbumId && item.AlbumPrimaryImageTag) {
options.tag = item.AlbumPrimaryImageTag;
return apiClient.getScaledImageUrl(item.AlbumId, options);
}
}
return null;
}
function getBackdropImageUrl(item, options, apiClient) {
options = options || {};
options.type = options.type || "Backdrop";
// If not resizing, get the original image
if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) {
options.quality = 100;
}
if (item.BackdropImageTags && item.BackdropImageTags.length) {
options.tag = item.BackdropImageTags[0];
return apiClient.getScaledImageUrl(item.Id, options);
}
return null;
}
function getImgUrl(item, original) {
var apiClient = connectionManager.getApiClient(item.ServerId);
var imageOptions = {};
if (!original) {
imageOptions.maxWidth = screen.availWidth;
}
if (item.BackdropImageTags && item.BackdropImageTags.length) {
return getBackdropImageUrl(item, imageOptions, apiClient);
} else {
if (item.MediaType === 'Photo' && original) {
return apiClient.getItemDownloadUrl(item.Id);
}
imageOptions.type = "Primary";
return getImageUrl(item, imageOptions, apiClient);
}
}
function getIcon(icon, cssClass, canFocus, autoFocus) {
var tabIndex = canFocus ? '' : ' tabindex="-1"';
autoFocus = autoFocus ? ' autofocus' : '';
return '<button is="paper-icon-button-light" class="autoSize ' + cssClass + '"' + tabIndex + autoFocus + '><i class="material-icons slideshowButtonIcon">' + icon + '</i></button>';
}
function setUserScalable(scalable) {
try {
appHost.setUserScalable(scalable);
} catch (err) {
console.log('error in appHost.setUserScalable: ' + err);
}
}
return function (options) {
var self = this;
var swiperInstance;
var dlg;
var currentTimeout;
var currentIntervalMs;
var currentOptions;
var currentIndex;
// small hack since this is not possible anyway
if (browser.chromecast) {
options.interactive = false;
}
function createElements(options) {
dlg = dialogHelper.createDialog({
exitAnimationDuration: options.interactive ? 400 : 800,
size: 'fullscreen',
autoFocus: false,
scrollY: false,
exitAnimation: 'fadeout',
removeOnClose: true
});
dlg.classList.add('slideshowDialog');
var html = '';
if (options.interactive) {
var actionButtonsOnTop = layoutManager.mobile;
html += '<div>';
html += '<div class="slideshowSwiperContainer"><div class="swiper-wrapper"></div></div>';
html += getIcon('keyboard_arrow_left', 'btnSlideshowPrevious slideshowButton hide-mouse-idle-tv', false);
html += getIcon('keyboard_arrow_right', 'btnSlideshowNext slideshowButton hide-mouse-idle-tv', false);
html += '<div class="topActionButtons">';
if (actionButtonsOnTop) {
if (appHost.supports('filedownload')) {
html += getIcon('file_download', 'btnDownload slideshowButton', true);
}
if (appHost.supports('sharing')) {
html += getIcon('share', 'btnShare slideshowButton', true);
}
}
html += getIcon('close', 'slideshowButton btnSlideshowExit hide-mouse-idle-tv', false);
html += '</div>';
if (!actionButtonsOnTop) {
html += '<div class="slideshowBottomBar hide">';
html += getIcon('pause', 'btnSlideshowPause slideshowButton', true, true);
if (appHost.supports('filedownload')) {
html += getIcon('file_download', 'btnDownload slideshowButton', true);
}
if (appHost.supports('sharing')) {
html += getIcon('share', 'btnShare slideshowButton', true);
}
html += '</div>';
}
html += '</div>';
} else {
html += '<div class="slideshowImage"></div><h1 class="slideshowImageText"></h1>';
}
dlg.innerHTML = html;
if (options.interactive) {
dlg.querySelector('.btnSlideshowExit').addEventListener('click', function (e) {
dialogHelper.close(dlg);
});
dlg.querySelector('.btnSlideshowNext').addEventListener('click', nextImage);
dlg.querySelector('.btnSlideshowPrevious').addEventListener('click', previousImage);
var btnPause = dlg.querySelector('.btnSlideshowPause');
if (btnPause) {
btnPause.addEventListener('click', playPause);
}
var btnDownload = dlg.querySelector('.btnDownload');
if (btnDownload) {
btnDownload.addEventListener('click', download);
}
var btnShare = dlg.querySelector('.btnShare');
if (btnShare) {
btnShare.addEventListener('click', share);
}
}
setUserScalable(true);
dialogHelper.open(dlg).then(function () {
setUserScalable(false);
stopInterval();
});
inputManager.on(window, onInputCommand);
document.addEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove);
dlg.addEventListener('close', onDialogClosed);
if (options.interactive) {
loadSwiper(dlg);
}
}
function loadSwiper(dlg) {
if (currentOptions.slides) {
dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.slides.map(getSwiperSlideHtmlFromSlide).join('');
} else {
dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.items.map(getSwiperSlideHtmlFromItem).join('');
}
require(['swiper'], function (Swiper) {
swiperInstance = new Swiper(dlg.querySelector('.slideshowSwiperContainer'), {
// Optional parameters
direction: 'horizontal',
loop: options.loop !== false,
autoplay: {
delay: options.interval || 8000
},
// Disable preloading of all images
preloadImages: false,
// Enable lazy loading
lazy: true,
loadPrevNext: true,
disableOnInteraction: false,
initialSlide: options.startIndex || 0,
speed: 240
});
if (layoutManager.mobile) {
pause();
} else {
play();
}
});
}
function getSwiperSlideHtmlFromItem(item) {
return getSwiperSlideHtmlFromSlide({
imageUrl: getImgUrl(item),
originalImage: getImgUrl(item, true),
//title: item.Name,
//description: item.Overview
Id: item.Id,
ServerId: item.ServerId
});
}
function getSwiperSlideHtmlFromSlide(item) {
var html = '';
html += '<div class="swiper-slide" data-imageurl="' + item.imageUrl + '" data-original="' + item.originalImage + '" data-itemid="' + item.Id + '" data-serverid="' + item.ServerId + '">';
html += '<img data-src="' + item.imageUrl + '" class="swiper-lazy swiper-slide-img">';
if (item.title || item.subtitle) {
html += '<div class="slideText">';
html += '<div class="slideTextInner">';
if (item.title) {
html += '<h1 class="slideTitle">';
html += item.title;
html += '</h1>';
}
if (item.description) {
html += '<div class="slideSubtitle">';
html += item.description;
html += '</div>';
}
html += '</div>';
html += '</div>';
}
html += '</div>';
return html;
}
function previousImage() {
if (swiperInstance) {
swiperInstance.slidePrev();
} else {
stopInterval();
showNextImage(currentIndex - 1);
}
}
function nextImage() {
if (swiperInstance) {
if (options.loop === false) {
if (swiperInstance.activeIndex >= swiperInstance.slides.length - 1) {
dialogHelper.close(dlg);
return;
}
}
swiperInstance.slideNext();
} else {
stopInterval();
showNextImage(currentIndex + 1);
}
}
function getCurrentImageInfo() {
if (swiperInstance) {
var slide = document.querySelector('.swiper-slide-active');
if (slide) {
return {
url: slide.getAttribute('data-original'),
shareUrl: slide.getAttribute('data-imageurl'),
itemId: slide.getAttribute('data-itemid'),
serverId: slide.getAttribute('data-serverid')
};
}
return null;
} else {
return null;
}
}
function download() {
var imageInfo = getCurrentImageInfo();
require(['fileDownloader'], function (fileDownloader) {
fileDownloader.download([imageInfo]);
});
}
function share() {
var imageInfo = getCurrentImageInfo();
navigator.share({
url: imageInfo.shareUrl
});
}
function play() {
var btnSlideshowPause = dlg.querySelector('.btnSlideshowPause i');
if (btnSlideshowPause) {
btnSlideshowPause.innerHTML = "pause";
}
swiperInstance.startAutoplay();
}
function pause() {
var btnSlideshowPause = dlg.querySelector('.btnSlideshowPause i');
if (btnSlideshowPause) {
btnSlideshowPause.innerHTML = "&#xE037;";
}
swiperInstance.stopAutoplay();
}
function playPause() {
var paused = dlg.querySelector('.btnSlideshowPause i').innerHTML !== "pause";
if (paused) {
play();
} else {
pause();
}
}
function onDialogClosed() {
var swiper = swiperInstance;
if (swiper) {
swiper.destroy(true, true);
swiperInstance = null;
}
inputManager.off(window, onInputCommand);
document.removeEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove);
}
function startInterval(options) {
currentOptions = options;
stopInterval();
createElements(options);
if (!options.interactive) {
currentIntervalMs = options.interval || 11000;
showNextImage(options.startIndex || 0, true);
}
}
var _osdOpen = false;
function isOsdOpen() {
return _osdOpen;
}
function getOsdBottom() {
return dlg.querySelector('.slideshowBottomBar');
}
function showOsd() {
var bottom = getOsdBottom();
if (bottom) {
slideUpToShow(bottom);
startHideTimer();
}
}
function hideOsd() {
var bottom = getOsdBottom();
if (bottom) {
slideDownToHide(bottom);
}
}
var hideTimeout;
function startHideTimer() {
stopHideTimer();
hideTimeout = setTimeout(hideOsd, 4000);
}
function stopHideTimer() {
if (hideTimeout) {
clearTimeout(hideTimeout);
hideTimeout = null;
}
}
function slideUpToShow(elem) {
if (!elem.classList.contains('hide')) {
return;
}
_osdOpen = true;
elem.classList.remove('hide');
var onFinish = function () {
focusManager.focus(elem.querySelector('.btnSlideshowPause'));
};
if (!elem.animate) {
onFinish();
return;
}
requestAnimationFrame(function () {
var keyframes = [
{ transform: 'translate3d(0,' + elem.offsetHeight + 'px,0)', opacity: '.3', offset: 0 },
{ transform: 'translate3d(0,0,0)', opacity: '1', offset: 1 }
];
var timing = { duration: 300, iterations: 1, easing: 'ease-out' };
elem.animate(keyframes, timing).onfinish = onFinish;
});
}
function slideDownToHide(elem) {
if (elem.classList.contains('hide')) {
return;
}
var onFinish = function () {
elem.classList.add('hide');
_osdOpen = false;
};
if (!elem.animate) {
onFinish();
return;
}
requestAnimationFrame(function () {
var keyframes = [
{ transform: 'translate3d(0,0,0)', opacity: '1', offset: 0 },
{ transform: 'translate3d(0,' + elem.offsetHeight + 'px,0)', opacity: '.3', offset: 1 }
];
var timing = { duration: 300, iterations: 1, easing: 'ease-out' };
elem.animate(keyframes, timing).onfinish = onFinish;
});
}
var lastMouseMoveData;
function onPointerMove(e) {
var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
if (pointerType === 'mouse') {
var eventX = e.screenX || 0;
var eventY = e.screenY || 0;
var obj = lastMouseMoveData;
if (!obj) {
lastMouseMoveData = {
x: eventX,
y: eventY
};
return;
}
// if coord are same, it didn't move
if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) {
return;
}
obj.x = eventX;
obj.y = eventY;
showOsd();
}
}
function onInputCommand(e) {
switch (e.detail.command) {
case 'left':
if (!isOsdOpen()) {
e.preventDefault();
e.stopPropagation();
previousImage();
}
break;
case 'right':
if (!isOsdOpen()) {
e.preventDefault();
e.stopPropagation();
nextImage();
}
break;
case 'up':
case 'down':
case 'select':
case 'menu':
case 'info':
case 'play':
case 'playpause':
case 'pause':
showOsd();
break;
default:
break;
}
}
function showNextImage(index, skipPreload) {
index = Math.max(0, index);
if (index >= currentOptions.items.length) {
index = 0;
}
currentIndex = index;
var options = currentOptions;
var items = options.items;
var item = items[index];
var imgUrl = getImgUrl(item);
var onSrcLoaded = function () {
var cardImageContainer = dlg.querySelector('.slideshowImage');
var newCardImageContainer = document.createElement('div');
newCardImageContainer.className = cardImageContainer.className;
if (options.cover) {
newCardImageContainer.classList.add('slideshowImage-cover');
}
newCardImageContainer.style.backgroundImage = "url('" + imgUrl + "')";
newCardImageContainer.classList.add('hide');
cardImageContainer.parentNode.appendChild(newCardImageContainer);
if (options.showTitle) {
dlg.querySelector('.slideshowImageText').innerHTML = item.Name;
} else {
dlg.querySelector('.slideshowImageText').innerHTML = '';
}
newCardImageContainer.classList.remove('hide');
var onAnimationFinished = function () {
var parentNode = cardImageContainer.parentNode;
if (parentNode) {
parentNode.removeChild(cardImageContainer);
}
};
if (newCardImageContainer.animate) {
var keyframes = [
{ opacity: '0', offset: 0 },
{ opacity: '1', offset: 1 }
];
var timing = { duration: 1200, iterations: 1 };
newCardImageContainer.animate(keyframes, timing).onfinish = onAnimationFinished;
} else {
onAnimationFinished();
}
stopInterval();
currentTimeout = setTimeout(function () {
showNextImage(index + 1, true);
}, currentIntervalMs);
};
if (!skipPreload) {
var img = new Image();
img.onload = onSrcLoaded;
img.src = imgUrl;
} else {
onSrcLoaded();
}
}
function stopInterval() {
if (currentTimeout) {
clearTimeout(currentTimeout);
currentTimeout = null;
}
}
self.show = function () {
startInterval(options);
};
self.hide = function () {
var dialog = dlg;
if (dialog) {
dialogHelper.close(dialog);
}
};
};
});