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

update slideshow

This commit is contained in:
Luke Pulverenti 2016-04-18 01:58:08 -04:00
parent 1c296d8d87
commit 658f5052da
32 changed files with 834 additions and 174 deletions

View file

@ -16,12 +16,12 @@
}, },
"devDependencies": {}, "devDependencies": {},
"ignore": [], "ignore": [],
"version": "1.2.26", "version": "1.2.31",
"_release": "1.2.26", "_release": "1.2.31",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "1.2.26", "tag": "1.2.31",
"commit": "7e13c8d9c17a4946681b3485c5fbf3e62f39cd2f" "commit": "87a2ef738364e9c40e0b97326f5861b6edfc5b3e"
}, },
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git", "_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
"_target": "^1.2.0", "_target": "^1.2.0",

View file

@ -62,7 +62,7 @@ define(['dialogHelper', 'layoutManager', 'dialogText', 'html!./../prompt/icons.h
if (raisedButtons) { if (raisedButtons) {
html += '<paper-button raised class="btnSubmit"><iron-icon icon="dialog:check"></iron-icon><span>' + dialogText.get(buttonText) + '</span></paper-button>'; html += '<paper-button raised class="btnSubmit"><iron-icon icon="dialog:check"></iron-icon><span>' + dialogText.get(buttonText) + '</span></paper-button>';
} else { } else {
html += '<div style="text-align:right;">'; html += '<div class="buttons" style="text-align:right;">';
html += '<paper-button class="btnSubmit">' + dialogText.get(buttonText) + '</paper-button>'; html += '<paper-button class="btnSubmit">' + dialogText.get(buttonText) + '</paper-button>';
html += '</div>'; html += '</div>';
} }

View file

@ -1,4 +1,4 @@
define([], function () { define(['globalize'], function (globalize) {
function parseISO8601Date(s, toLocal) { function parseISO8601Date(s, toLocal) {
@ -94,11 +94,28 @@ define([], function () {
return parts.join(':'); return parts.join(':');
} }
var toLocaleTimeStringSupportsLocales = function toLocaleTimeStringSupportsLocales() {
try {
new Date().toLocaleTimeString('i');
} catch (e) {
return e.name === 'RangeError';
}
return false;
}();
function getDisplayTime(date) { function getDisplayTime(date) {
var time = date.toLocaleTimeString().toLowerCase();
if (time.indexOf('am') != -1 || time.indexOf('pm') != -1) { var currentLocale = globalize.getCurrentLocale();
var time = currentLocale && toLocaleTimeStringSupportsLocales ?
date.toLocaleTimeString(currentLocale) :
date.toLocaleTimeString();
var timeLower = time.toLowerCase();
if (timeLower.indexOf('am') != -1 || timeLower.indexOf('pm') != -1) {
time = timeLower;
var hour = date.getHours() % 12; var hour = date.getHours() % 12;
var suffix = date.getHours() > 11 ? 'pm' : 'am'; var suffix = date.getHours() > 11 ? 'pm' : 'am';
if (!hour) { if (!hour) {

View file

@ -0,0 +1,11 @@
define(['multi-download'], function (multiDownload) {
return {
download: function (items) {
multiDownload(items.map(function (item) {
return item.url;
}));
}
};
});

View file

@ -12,7 +12,7 @@
.promptDialogContent { .promptDialogContent {
text-align: left; text-align: left;
padding: 2em; padding: 1em 2em;
margin: 0 !important; margin: 0 !important;
} }

View file

@ -34,11 +34,13 @@ See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for
<iron-iconset-svg name="slideshow" size="24"> <iron-iconset-svg name="slideshow" size="24">
<svg> <svg>
<defs> <defs>
<g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" /></g> <g id="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" /></g>
<g id="pause"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" /></g> <g id="pause"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" /></g>
<g id="skip-next"><path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z" /></g> <g id="keyboard-arrow-left"><path d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z" /></g>
<g id="skip-previous"><path d="M6 6h2v12H6zm3.5 6l8.5 6V6z" /></g> <g id="keyboard-arrow-right"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z" /></g>
<g id="play-arrow"><path d="M8 5v14l11-7z" /></g> <g id="play-arrow"><path d="M8 5v14l11-7z" /></g>
<g id="file-download"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z" /></g>
<g id="share"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z" /></g>
</defs> </defs>
</svg> </svg>
</iron-iconset-svg> </iron-iconset-svg>

View file

@ -1,16 +1,117 @@
define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'css!./style', 'html!./icons', 'iron-icon-set', 'paper-fab', 'paper-icon-button', 'paper-spinner'], function (dialogHelper, inputmanager, connectionManager, layoutManager) { define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'apphost', 'css!./style', 'html!./icons', 'iron-icon-set', 'paper-icon-button', 'paper-spinner'], function (dialogHelper, inputmanager, connectionManager, layoutManager, focusManager, appHost) {
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);
}
//else if (item.AlbumId && item.SeriesPrimaryImageTag) {
// imgUrl = ApiClient.getScaledImageUrl(item.SeriesId, {
// type: "Primary",
// width: downloadWidth,
// tag: item.SeriesPrimaryImageTag,
// minScale: minScale
// });
//}
//else if (item.ParentPrimaryImageTag) {
// imgUrl = ApiClient.getImageUrl(item.ParentPrimaryImageItemId, {
// type: "Primary",
// width: downloadWidth,
// tag: item.ParentPrimaryImageTag,
// minScale: minScale
// });
//}
}
return null;
}
function getBackdropImageUrl(item, options, apiClient) {
options = options || {};
options.type = options.type || "Backdrop";
options.width = null;
delete options.width;
options.maxWidth = null;
delete options.maxWidth;
options.maxHeight = null;
delete options.maxHeight;
options.height = null;
delete options.height;
// 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.getUrl("Items/" + item.Id + "/Download", {
api_key: apiClient.accessToken()
});
}
imageOptions.type = "Primary";
return getImageUrl(item, imageOptions, apiClient);
}
}
return function (options) { return function (options) {
var self = this; var self = this;
var swiperInstance; var swiperInstance;
var dlg; var dlg;
var currentTimeout;
var currentIntervalMs;
var currentOptions;
var currentIndex;
function createElements(options) { function createElements(options) {
dlg = dialogHelper.createDialog({ dlg = dialogHelper.createDialog({
exitAnimationDuration: options.interactive ? 400 : 800, exitAnimationDuration: options.interactive ? 400 : 800,
size: 'fullscreen' size: 'fullscreen',
autoFocus: false
}); });
dlg.classList.add('slideshowDialog'); dlg.classList.add('slideshowDialog');
@ -22,13 +123,21 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
html += '<div>'; html += '<div>';
html += '<div class="slideshowSwiperContainer"><div class="swiper-wrapper"></div></div>'; html += '<div class="slideshowSwiperContainer"><div class="swiper-wrapper"></div></div>';
html += '<paper-fab mini icon="slideshow:arrow-back" class="btnSlideshowExit" tabindex="-1"></paper-fab>'; html += '<paper-icon-button icon="slideshow:keyboard-arrow-left" class="btnSlideshowPrevious slideshowButton" tabindex="-1"></paper-icon-button>';
html += '<paper-icon-button icon="slideshow:keyboard-arrow-right" class="btnSlideshowNext slideshowButton" tabindex="-1"></paper-icon-button>';
html += '<div class="slideshowControlBar">'; html += '<paper-icon-button icon="slideshow:close" class="btnSlideshowExit" tabindex="-1"></paper-icon-button>';
html += '<paper-icon-button icon="slideshow:skip-previous" class="btnSlideshowPrevious slideshowButton"></paper-icon-button>';
html += '<div class="slideshowBottomBar hide">';
//html += '<paper-icon-button icon="slideshow:share" class="btnShare slideshowButton"></paper-icon-button>';
html += '<paper-icon-button icon="slideshow:pause" class="btnSlideshowPause slideshowButton" autoFocus></paper-icon-button>'; html += '<paper-icon-button icon="slideshow:pause" class="btnSlideshowPause slideshowButton" autoFocus></paper-icon-button>';
html += '<paper-icon-button icon="slideshow:skip-next" class="btnSlideshowNext slideshowButton"></paper-icon-button>'; if (appHost.supports('filedownload')) {
html += '<paper-icon-button icon="slideshow:file-download" class="btnDownload slideshowButton"></paper-icon-button>';
}
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';
} else { } else {
@ -44,7 +153,21 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
}); });
dlg.querySelector('.btnSlideshowNext').addEventListener('click', nextImage); dlg.querySelector('.btnSlideshowNext').addEventListener('click', nextImage);
dlg.querySelector('.btnSlideshowPrevious').addEventListener('click', previousImage); dlg.querySelector('.btnSlideshowPrevious').addEventListener('click', previousImage);
dlg.querySelector('.btnSlideshowPause').addEventListener('click', playPause);
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);
}
} }
document.body.appendChild(dlg); document.body.appendChild(dlg);
@ -56,6 +179,7 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
}); });
inputmanager.on(window, onInputCommand); inputmanager.on(window, onInputCommand);
document.addEventListener('mousemove', onMouseMove);
dlg.addEventListener('close', onDialogClosed); dlg.addEventListener('close', onDialogClosed);
@ -101,7 +225,8 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
function getSwiperSlideHtmlFromItem(item) { function getSwiperSlideHtmlFromItem(item) {
return getSwiperSlideHtmlFromSlide({ return getSwiperSlideHtmlFromSlide({
imageUrl: getImgUrl(item) imageUrl: getImgUrl(item),
originalImage: getImgUrl(item, true)
//title: item.Name, //title: item.Name,
//description: item.Overview //description: item.Overview
}); });
@ -128,7 +253,7 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
function getSwiperSlideHtmlFromSlide(item) { function getSwiperSlideHtmlFromSlide(item) {
var html = ''; var html = '';
html += '<div class="swiper-slide">'; html += '<div class="swiper-slide" data-original="' + item.originalImage + '">';
html += '<img data-src="' + item.imageUrl + '" class="swiper-lazy">'; html += '<img data-src="' + item.imageUrl + '" class="swiper-lazy">';
html += '<paper-spinner></paper-spinner>'; html += '<paper-spinner></paper-spinner>';
if (item.title || item.subtitle) { if (item.title || item.subtitle) {
@ -179,6 +304,32 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
} }
} }
function getCurrentImageUrl() {
if (swiperInstance) {
return document.querySelector('.swiper-slide-active').getAttribute('data-original');
} else {
return null;
}
}
function download() {
var url = getCurrentImageUrl();
require(['fileDownloader'], function (fileDownloader) {
fileDownloader.download([
{
url: url
}]);
});
}
function share() {
}
function play() { function play() {
dlg.querySelector('.btnSlideshowPause').icon = "slideshow:pause"; dlg.querySelector('.btnSlideshowPause').icon = "slideshow:pause";
@ -212,13 +363,9 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
} }
inputmanager.off(window, onInputCommand); inputmanager.off(window, onInputCommand);
document.removeEventListener('mousemove', onMouseMove);
} }
var currentTimeout;
var currentIntervalMs;
var currentOptions;
var currentIndex;
function startInterval(options) { function startInterval(options) {
currentOptions = options; currentOptions = options;
@ -232,93 +379,137 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
} }
} }
function getImgUrl(item) { var _osdOpen = false;
function isOsdOpen() {
return _osdOpen;
}
var apiClient = connectionManager.getApiClient(item.ServerId); function getOsdBottom() {
if (item.BackdropImageTags && item.BackdropImageTags.length) { return dlg.querySelector('.slideshowBottomBar');
return getBackdropImageUrl(item, { }
maxWidth: screen.availWidth
}, apiClient); function showOsd() {
} else {
return getImageUrl(item, { slideUpToShow(getOsdBottom());
type: "Primary", startHideTimer();
maxWidth: screen.availWidth }
}, apiClient);
function hideOsd() {
slideDownToHide(getOsdBottom());
}
var hideTimeout;
function startHideTimer() {
stopHideTimer();
hideTimeout = setTimeout(hideOsd, 4000);
}
function stopHideTimer() {
if (hideTimeout) {
clearTimeout(hideTimeout);
hideTimeout = null;
} }
} }
function getBackdropImageUrl(item, options, apiClient) { function slideUpToShow(elem) {
options = options || {}; if (!elem.classList.contains('hide')) {
options.type = options.type || "Backdrop"; return;
options.width = null;
delete options.width;
options.maxWidth = null;
delete options.maxWidth;
options.maxHeight = null;
delete options.maxHeight;
options.height = null;
delete options.height;
// 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) { _osdOpen = true;
elem.classList.remove('hide');
options.tag = item.BackdropImageTags[0]; requestAnimationFrame(function () {
return apiClient.getScaledImageUrl(item.Id, options);
}
return null; 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 = function () {
focusManager.focus(elem.querySelector('.btnSlideshowPause'));
};
});
} }
function getImageUrl(item, options, apiClient) { function slideDownToHide(elem) {
options = options || {}; if (elem.classList.contains('hide')) {
options.type = options.type || "Primary"; return;
if (typeof (item) === 'string') {
return apiClient.getScaledImageUrl(item, options);
} }
if (item.ImageTags && item.ImageTags[options.type]) { requestAnimationFrame(function () {
options.tag = item.ImageTags[options.type]; var keyframes = [
return apiClient.getScaledImageUrl(item.Id, options); { 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 = function () {
elem.classList.add('hide');
_osdOpen = false;
};
});
}
var lastMouseMoveData;
function onMouseMove(e) {
var eventX = e.screenX || 0;
var eventY = e.screenY || 0;
var obj = lastMouseMoveData;
if (!obj) {
lastMouseMoveData = {
x: eventX,
y: eventY
};
return;
} }
if (options.type == 'Primary') { // if coord are same, it didn't move
if (item.AlbumId && item.AlbumPrimaryImageTag) { if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) {
return;
options.tag = item.AlbumPrimaryImageTag;
return apiClient.getScaledImageUrl(item.AlbumId, options);
}
//else if (item.AlbumId && item.SeriesPrimaryImageTag) {
// imgUrl = ApiClient.getScaledImageUrl(item.SeriesId, {
// type: "Primary",
// width: downloadWidth,
// tag: item.SeriesPrimaryImageTag,
// minScale: minScale
// });
//}
//else if (item.ParentPrimaryImageTag) {
// imgUrl = ApiClient.getImageUrl(item.ParentPrimaryImageItemId, {
// type: "Primary",
// width: downloadWidth,
// tag: item.ParentPrimaryImageTag,
// minScale: minScale
// });
//}
} }
return null; obj.x = eventX;
obj.y = eventY;
showOsd();
}
function onInputCommand(e) {
switch (e.detail.command) {
case 'left':
if (!isOsdOpen()) {
e.preventDefault();
previousImage();
}
break;
case 'right':
if (!isOsdOpen()) {
e.preventDefault();
nextImage();
}
break;
case 'up':
case 'down':
case 'select':
case 'menu':
case 'info':
case 'play':
case 'playpause':
case 'pause':
case 'fastforward':
case 'rewind':
case 'next':
case 'previous':
showOsd();
break;
default:
break;
}
} }
function showNextImage(index, skipPreload) { function showNextImage(index, skipPreload) {
@ -397,33 +588,6 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'c
} }
} }
function onInputCommand(e) {
switch (e.detail.command) {
case 'left':
previousImage();
break;
case 'right':
nextImage();
break;
case 'play':
play();
break;
case 'pause':
pause();
break;
case 'playpause':
playPause();
break;
default:
return
break;
}
e.preventDefault();
}
self.show = function () { self.show = function () {
startInterval(options); startInterval(options);
}; };

View file

@ -8,7 +8,6 @@
right: 0; right: 0;
left: 0; left: 0;
bottom: 0; bottom: 0;
z-index: 1001;
background-position: center center; background-position: center center;
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
@ -46,43 +45,84 @@
top: 50%; top: 50%;
} }
.btnSlideshowExit { .slideshowDialog paper-icon-button {
width: 5.2vh;
height: 5.2vh;
color: #fff;
opacity: .7;
min-width: 40px;
min-height: 40px;
}
.layout-tv .slideshowDialog paper-icon-button {
width: 7vh;
height: 7vh;
}
@media only screen and (-webkit-min-device-pixel-ratio: 1.3), only screen and (min-device-pixel-ratio: 1.3), only screen and (min-resolution: 120dpi) {
.slideshowDialog paper-icon-button {
width: 11vmin;
height: 11vmin;
}
}
.btnSlideshowPrevious {
left: .5vh;
top: 45vh;
z-index: 1002; z-index: 1002;
position: absolute; position: absolute;
top: 1.5vh;
left: 1.5vh;
width: 6vh;
height: 6vh;
color: #eee;
} }
paper-fab.btnSlideshowExit { .btnSlideshowNext {
background-color: #444; right: .5vh;
top: 45vh;
z-index: 1002;
position: absolute;
} }
.slideshowControlBar { .btnSlideshowExit {
right: .5vh;
top: .5vh;
z-index: 1002;
position: absolute;
}
.slideshowBottomBar {
position: fixed; position: fixed;
left: 0; left: 0;
bottom: 0; bottom: 0;
right: 0; right: 0;
z-index: 1002; background-color: rgba(0, 0, 0, .7);
background: rgba(0,0,0,.5); color: #fff;
text-align: center; padding: .5%;
color: #eee; display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
} }
.mouseIdle .btnSlideshowExit { .slideshowTopBar {
position: fixed;
left: 0;
top: 0;
right: 0;
background-color: rgba(0, 0, 0, .7);
color: #fff;
padding: .5%;
display: flex;
flex-direction: row;
align-items: center;
text-align: right;
justify-content: flex-end;
}
.mouseIdle .btnSlideshowPrevious, .mouseIdle .btnSlideshowNext, .mouseIdle .btnSlideshowExit {
display: none; display: none;
} }
.mouseIdle .slideshowControlBar { .slideshowExtraButtons {
transform: translateY(100%); margin-left: auto;
transition: transform 600ms ease-out; text-align: right;
}
.slideshowButton {
width: 8vh;
height: 8vh;
} }
.slideText { .slideText {

View file

@ -30,14 +30,14 @@
"web-component-tester": "polymer/web-component-tester#^3.4.0" "web-component-tester": "polymer/web-component-tester#^3.4.0"
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/PolymerElements/iron-a11y-announcer", "homepage": "https://github.com/polymerelements/iron-a11y-announcer",
"_release": "1.0.4", "_release": "1.0.4",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.4", "tag": "v1.0.4",
"commit": "5ce3eb8c4282bb53cd72e348858dc6be6b4c50b9" "commit": "5ce3eb8c4282bb53cd72e348858dc6be6b4c50b9"
}, },
"_source": "git://github.com/PolymerElements/iron-a11y-announcer.git", "_source": "git://github.com/polymerelements/iron-a11y-announcer.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "PolymerElements/iron-a11y-announcer" "_originalSource": "polymerelements/iron-a11y-announcer"
} }

View file

@ -29,14 +29,14 @@
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/polymerelements/iron-behaviors", "homepage": "https://github.com/PolymerElements/iron-behaviors",
"_release": "1.0.13", "_release": "1.0.13",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.13", "tag": "v1.0.13",
"commit": "a7bc3428a6da2beed21987b3a8028206826a12bc" "commit": "a7bc3428a6da2beed21987b3a8028206826a12bc"
}, },
"_source": "git://github.com/polymerelements/iron-behaviors.git", "_source": "git://github.com/PolymerElements/iron-behaviors.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "polymerelements/iron-behaviors" "_originalSource": "PolymerElements/iron-behaviors"
} }

View file

@ -32,14 +32,14 @@
"web-component-tester": "^4.0.0", "web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"homepage": "https://github.com/PolymerElements/iron-icon", "homepage": "https://github.com/polymerelements/iron-icon",
"_release": "1.0.8", "_release": "1.0.8",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.8", "tag": "v1.0.8",
"commit": "f36b38928849ef3853db727faa8c9ef104d611eb" "commit": "f36b38928849ef3853db727faa8c9ef104d611eb"
}, },
"_source": "git://github.com/PolymerElements/iron-icon.git", "_source": "git://github.com/polymerelements/iron-icon.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "PolymerElements/iron-icon" "_originalSource": "polymerelements/iron-icon"
} }

View file

@ -36,7 +36,7 @@
"tag": "v1.4.0", "tag": "v1.4.0",
"commit": "554f7418fdbd97688eb21518b5f8172167d53a95" "commit": "554f7418fdbd97688eb21518b5f8172167d53a95"
}, },
"_source": "git://github.com/polymerelements/iron-selector.git", "_source": "git://github.com/PolymerElements/iron-selector.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "polymerelements/iron-selector" "_originalSource": "PolymerElements/iron-selector"
} }

View file

@ -0,0 +1,15 @@
{
"name": "multi-download",
"homepage": "https://github.com/sindresorhus/multi-download",
"version": "2.0.0",
"_release": "2.0.0",
"_resolution": {
"type": "version",
"tag": "v2.0.0",
"commit": "181dc2d27de96f81a951b8cc8b50106d13219bd8"
},
"_source": "https://github.com/sindresorhus/multi-download.git",
"_target": "^2.0.0",
"_originalSource": "multi-download",
"_direct": true
}

View file

@ -0,0 +1,15 @@
root = true
[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{package.json,*.yml}]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false

View file

@ -0,0 +1 @@
* text=auto

View file

@ -0,0 +1 @@
node_modules

View file

@ -0,0 +1,12 @@
{
"node": true,
"esnext": true,
"bitwise": true,
"curly": true,
"immed": true,
"newcap": true,
"noarg": true,
"undef": true,
"unused": "vars",
"strict": true
}

View file

@ -0,0 +1,73 @@
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.multiDownload = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
function fallback(urls) {
var i = 0;
(function createIframe() {
var frame = document.createElement('iframe');
frame.style.display = 'none';
frame.src = urls[i++];
document.documentElement.appendChild(frame);
// the download init has to be sequential otherwise IE only use the first
var interval = setInterval(function () {
if (frame.contentWindow.document.readyState === 'complete') {
clearInterval(interval);
// Safari needs a timeout
setTimeout(function () {
frame.parentNode.removeChild(frame);
}, 1000);
if (i < urls.length) {
createIframe();
}
}
}, 100);
})();
}
function isFirefox() {
// sad panda :(
return /Firefox\//i.test(navigator.userAgent);
}
function sameDomain(url) {
var a = document.createElement('a');
a.href = url;
return location.hostname === a.hostname && location.protocol === a.protocol;
}
function download(url) {
var a = document.createElement('a');
a.download = '';
a.href = url;
// firefox doesn't support `a.click()`...
a.dispatchEvent(new MouseEvent('click'));
}
module.exports = function (urls) {
if (!urls) {
throw new Error('`urls` required');
}
if (typeof document.createElement('a').download === 'undefined') {
return fallback(urls);
}
var delay = 0;
urls.forEach(function (url) {
// the download init has to be sequential for firefox if the urls are not on the same domain
if (isFirefox() && !sameDomain(url)) {
return setTimeout(download.bind(null, url), 100 * ++delay);
}
download(url);
});
}
},{}]},{},[1])(1)
});

View file

@ -0,0 +1,31 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="Sindre Sorhus">
<meta name="viewport" content="width=device-width">
<title>multi-download</title>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<style>
#download-btn {
width: 300px;
height: 50px;
position: absolute;
left: 50%;
top: 50%;
margin: -25px 0 0 -150px;
outline: none;
}
</style>
</head>
<body >
<button id="download-btn" class="btn btn-primary btn-lg" data-files="fixture/unicorn.jpg.zip fixture/rainbow.jpg.zip fixture/unicorn2.jpg.zip">Download multiple files</button>
<script src="browser.js"></script>
<script>
document.querySelector('#download-btn').addEventListener('click', function (e) {
var files = e.target.dataset.files.split(' ');
multiDownload(files);
});
</script>
</body>
</html>

View file

@ -0,0 +1,69 @@
'use strict';
function fallback(urls) {
var i = 0;
(function createIframe() {
var frame = document.createElement('iframe');
frame.style.display = 'none';
frame.src = urls[i++];
document.documentElement.appendChild(frame);
// the download init has to be sequential otherwise IE only use the first
var interval = setInterval(function () {
if (frame.contentWindow.document.readyState === 'complete') {
clearInterval(interval);
// Safari needs a timeout
setTimeout(function () {
frame.parentNode.removeChild(frame);
}, 1000);
if (i < urls.length) {
createIframe();
}
}
}, 100);
})();
}
function isFirefox() {
// sad panda :(
return /Firefox\//i.test(navigator.userAgent);
}
function sameDomain(url) {
var a = document.createElement('a');
a.href = url;
return location.hostname === a.hostname && location.protocol === a.protocol;
}
function download(url) {
var a = document.createElement('a');
a.download = '';
a.href = url;
// firefox doesn't support `a.click()`...
a.dispatchEvent(new MouseEvent('click'));
}
module.exports = function (urls) {
if (!urls) {
throw new Error('`urls` required');
}
if (typeof document.createElement('a').download === 'undefined') {
return fallback(urls);
}
var delay = 0;
urls.forEach(function (url) {
// the download init has to be sequential for firefox if the urls are not on the same domain
if (isFirefox() && !sameDomain(url)) {
return setTimeout(download.bind(null, url), 100 * ++delay);
}
download(url);
});
}

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,28 @@
{
"name": "multi-download",
"version": "2.0.0",
"description": "Download multiple files at once",
"license": "MIT",
"repository": "sindresorhus/multi-download",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"scripts": {
"build": "a=$npm_package_name; browserify -r ./index:$a -s $a index.js -o browser.js"
},
"files": [
"index.js"
],
"keywords": [
"browser",
"download",
"multiple",
"parallel",
"files"
],
"devDependencies": {
"browserify": "^10.0.0"
}
}

View file

@ -0,0 +1,62 @@
# multi-download
> Download multiple files at once
![](screenshot.gif)
It works by abusing the `a`-tag [`download` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download) and falling back to iframes on older browsers.
## [Demo](http://sindresorhus.com/multi-download)
## Install
```
$ npm install --save multi-download
```
## Usage
```html
<button id="download-btn" data-files="unicorn.jpg rainbow.jpg">Download</button>
```
```js
document.querySelector('#download-btn').addEventListener('click', function (e) {
var files = e.target.dataset.files.split(' ');
multiDownload(files);
});
```
```js
// with jQuery
$('#download-btn').on('click', function () {
var files = $(this).data('files').split(' ');
multiDownload(files);
});
```
## API
### multiDownload(urls)
#### urls
Type: `array`
URLs to files you want to download.
## Caveats
Chrome will ask the user before downloading multiple files (once per domain).
For the fallback to work you need to make sure the server sends the correct header for the browser to download the file rather than displaying it. This is usually achieved with the header `Content-Disposition: attachment; filename="<file name.ext>" `.
## License
MIT © [Sindre Sorhus](http://sindresorhus.com)

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

View file

@ -0,0 +1,103 @@
define(['appStorage', 'browser'], function (appStorage, browser) {
function getDeviceProfile() {
// TODO
return null;
}
function getCapabilities() {
var caps = {
PlayableMediaTypes: ['Audio', 'Video'],
SupportsPersistentIdentifier: false,
DeviceProfile: getDeviceProfile()
};
return caps;
}
function generateDeviceId() {
return new Promise(function (resolve, reject) {
require(['fingerprintjs2'], function (Fingerprint2) {
new Fingerprint2().get(function (result, components) {
console.log('Generated device id: ' + result); //a hash, representing your device fingerprint
resolve(result);
});
});
});
}
return {
getWindowState: function () {
return document.windowState || 'Normal';
},
setWindowState: function (state) {
alert('setWindowState is not supported and should not be called');
},
exit: function () {
alert('exit is not supported and should not be called');
},
supports: function (command) {
var features = [
'filedownload'
];
return features.indexOf(command.toLowerCase()) != -1;
},
appName: function () {
return 'Emby Mobile';
},
appVersion: function () {
return '2.0.1';
},
deviceName: function () {
var deviceName;
if (browser.chrome) {
deviceName = "Chrome";
} else if (browser.edge) {
deviceName = "Edge";
} else if (browser.firefox) {
deviceName = "Firefox";
} else if (browser.msie) {
deviceName = "Internet Explorer";
} else {
deviceName = "Web Browser";
}
if (browser.version) {
deviceName += " " + browser.version;
}
if (browser.ipad) {
deviceName += " Ipad";
} else if (browser.iphone) {
deviceName += " Iphone";
} else if (browser.android) {
deviceName += " Android";
}
return deviceName;
},
deviceId: function () {
var key = '_deviceId2';
var deviceId = appStorage.getItem(key);
if (deviceId) {
return Promise.resolve(deviceId);
} else {
return generateDeviceId().then(function (deviceId) {
appStorage.setItem(key, deviceId);
return deviceId;
});
}
},
capabilities: getCapabilities
};
});

View file

@ -1,9 +0,0 @@
define([], function () {
return function (items) {
items.forEach(function (item) {
window.location.href = item.url;
});
};
});

View file

@ -769,7 +769,7 @@
} }
if (item.CanDownload) { if (item.CanDownload) {
if (AppInfo.supportsDownloading) { if (appHost.supports('filedownload')) {
commands.push('download'); commands.push('download');
} }
} }
@ -987,7 +987,8 @@
api_key: ApiClient.accessToken() api_key: ApiClient.accessToken()
}); });
fileDownloader([{ fileDownloader.download([
{
url: downloadHref, url: downloadHref,
itemId: itemId itemId: itemId
}]); }]);

View file

@ -1,4 +1,4 @@
define(['appSettings', 'appStorage', 'libraryBrowser', 'jQuery'], function (appSettings, appStorage, LibraryBrowser, $) { define(['appSettings', 'appStorage', 'libraryBrowser', 'apphost', 'jQuery'], function (appSettings, appStorage, LibraryBrowser, appHost, $) {
var showOverlayTimeout; var showOverlayTimeout;
@ -270,7 +270,7 @@
}); });
} }
if (user.Policy.EnableContentDownloading && AppInfo.supportsDownloading) { if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) {
if (mediaType) { if (mediaType) {
items.push({ items.push({
name: Globalize.translate('ButtonDownload'), name: Globalize.translate('ButtonDownload'),
@ -491,7 +491,8 @@
api_key: ApiClient.accessToken() api_key: ApiClient.accessToken()
}); });
fileDownloader([{ fileDownloader.download([
{
url: downloadHref, url: downloadHref,
itemId: itemId itemId: itemId
}]); }]);
@ -1143,7 +1144,7 @@
}); });
} }
if (user.Policy.EnableContentDownloading && AppInfo.supportsDownloading) { if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) {
//items.push({ //items.push({
// name: Globalize.translate('ButtonDownload'), // name: Globalize.translate('ButtonDownload'),
// id: 'download', // id: 'download',
@ -1214,7 +1215,7 @@
combineVersions($.mobile.activePage, items); combineVersions($.mobile.activePage, items);
break; break;
case 'markplayed': case 'markplayed':
items.forEach(function(itemId) { items.forEach(function (itemId) {
ApiClient.markPlayed(Dashboard.getCurrentUserId(), itemId); ApiClient.markPlayed(Dashboard.getCurrentUserId(), itemId);
}); });
hideSelections(); hideSelections();

View file

@ -1383,8 +1383,6 @@ var AppInfo = {};
// This doesn't perform well on iOS // This doesn't perform well on iOS
AppInfo.enableHeadRoom = !isIOS; AppInfo.enableHeadRoom = !isIOS;
AppInfo.supportsDownloading = !(AppInfo.isNativeApp && isIOS);
// This currently isn't working on android, unfortunately // This currently isn't working on android, unfortunately
AppInfo.supportsFileInput = !(AppInfo.isNativeApp && isAndroid); AppInfo.supportsFileInput = !(AppInfo.isNativeApp && isAndroid);
@ -1696,8 +1694,10 @@ var AppInfo = {};
// hack for an android test before browserInfo is loaded // hack for an android test before browserInfo is loaded
if (Dashboard.isRunningInCordova() && window.MainActivity) { if (Dashboard.isRunningInCordova() && window.MainActivity) {
paths.appStorage = "cordova/android/appstorage"; paths.appStorage = "cordova/android/appstorage";
paths.apphost = "cordova/apphost";
} else { } else {
paths.appStorage = apiClientBowerPath + "/appstorage"; paths.appStorage = apiClientBowerPath + "/appstorage";
paths.apphost = "components/apphost";
} }
paths.playlistManager = "scripts/playlistmanager"; paths.playlistManager = "scripts/playlistmanager";
@ -1974,10 +1974,12 @@ var AppInfo = {};
define("loading", [embyWebComponentsBowerPath + "/loading/loading-lite"], returnFirstDependency); define("loading", [embyWebComponentsBowerPath + "/loading/loading-lite"], returnFirstDependency);
} }
define("multi-download", [bowerPath + '/multi-download/browser'], returnFirstDependency);
if (Dashboard.isRunningInCordova() && browser.android) { if (Dashboard.isRunningInCordova() && browser.android) {
define("fileDownloader", ['cordova/android/filedownloader'], returnFirstDependency); define("fileDownloader", ['cordova/android/filedownloader'], returnFirstDependency);
} else { } else {
define("fileDownloader", ['components/filedownloader'], returnFirstDependency); define("fileDownloader", [embyWebComponentsBowerPath + '/filedownloader'], returnFirstDependency);
} }
} }