diff --git a/app/javascript/elements/download_button.js b/app/javascript/elements/download_button.js index 9fb292ba3..a49926c0c 100644 --- a/app/javascript/elements/download_button.js +++ b/app/javascript/elements/download_button.js @@ -18,27 +18,64 @@ export default targetable(class extends HTMLElement { this.toggleState() fetch(this.dataset.src).then((response) => response.json()).then((urls) => { - const fileRequests = urls.map((url) => { - return () => { - return fetch(url).then(async (resp) => { - const blobUrl = URL.createObjectURL(await resp.blob()) - const link = document.createElement('a') + const isSafariIos = /iPhone|iPad|iPod/i.test(navigator.userAgent) - link.href = blobUrl - link.setAttribute('download', decodeURI(url.split('/').pop())) + if (isSafariIos && urls.length > 1) { + this.downloadSafariIos(urls) + } else { + this.downloadUrls(urls) + } + }) + } + + downloadUrls (urls) { + const fileRequests = urls.map((url) => { + return () => { + return fetch(url).then(async (resp) => { + const blobUrl = URL.createObjectURL(await resp.blob()) + const link = document.createElement('a') + + link.href = blobUrl + link.setAttribute('download', decodeURI(url.split('/').pop())) + + link.click() + + URL.revokeObjectURL(blobUrl) + }) + } + }) - link.click() + fileRequests.reduce( + (prevPromise, request) => prevPromise.then(() => request()), + Promise.resolve() + ) - URL.revokeObjectURL(url) - }) - } + this.toggleState() + } + + downloadSafariIos (urls) { + const fileRequests = urls.map((url) => { + return fetch(url).then(async (resp) => { + const blob = await resp.blob() + const blobUrl = URL.createObjectURL(blob.slice(0, blob.size, 'application/octet-stream')) + const link = document.createElement('a') + + link.href = blobUrl + link.setAttribute('download', decodeURI(url.split('/').pop())) + + return link }) + }) - fileRequests.reduce( - (prevPromise, request) => prevPromise.then(() => request()), - Promise.resolve() - ) + Promise.all(fileRequests).then((links) => { + links.forEach((link, index) => { + setTimeout(() => { + link.click() + URL.revokeObjectURL(link.href) + }, index * 50) + }) + }).finally(() => { this.toggleState() }) } diff --git a/app/javascript/submission_form/completed.vue b/app/javascript/submission_form/completed.vue index 1759b1c3d..db7de608a 100644 --- a/app/javascript/submission_form/completed.vue +++ b/app/javascript/submission_form/completed.vue @@ -179,27 +179,62 @@ export default { this.isDownloading = true fetch(this.baseUrl + `/submitters/${this.submitterSlug}/download`).then((response) => response.json()).then((urls) => { - const fileRequests = urls.map((url) => { - return () => { - return fetch(url).then(async (resp) => { - const blobUrl = URL.createObjectURL(await resp.blob()) - const link = document.createElement('a') + const isSafariIos = /iPhone|iPad|iPod/i.test(navigator.userAgent) - link.href = blobUrl - link.setAttribute('download', decodeURI(url.split('/').pop())) + if (isSafariIos && urls.length > 1) { + this.downloadSafariIos(urls) + } else { + this.downloadUrls(urls) + } + }) + }, + downloadUrls (urls) { + const fileRequests = urls.map((url) => { + return () => { + return fetch(url).then(async (resp) => { + const blobUrl = URL.createObjectURL(await resp.blob()) + const link = document.createElement('a') + + link.href = blobUrl + link.setAttribute('download', decodeURI(url.split('/').pop())) + + link.click() + + URL.revokeObjectURL(blobUrl) + }) + } + }) - link.click() + fileRequests.reduce( + (prevPromise, request) => prevPromise.then(() => request()), + Promise.resolve() + ) - URL.revokeObjectURL(url) - }) - } + this.isDownloading = false + }, + downloadSafariIos (urls) { + const fileRequests = urls.map((url) => { + return fetch(url).then(async (resp) => { + const blob = await resp.blob() + const blobUrl = URL.createObjectURL(blob.slice(0, blob.size, 'application/octet-stream')) + const link = document.createElement('a') + + link.href = blobUrl + link.setAttribute('download', decodeURI(url.split('/').pop())) + + return link }) + }) - fileRequests.reduce( - (prevPromise, request) => prevPromise.then(() => request()), - Promise.resolve() - ) + Promise.all(fileRequests).then((links) => { + links.forEach((link, index) => { + setTimeout(() => { + link.click() + URL.revokeObjectURL(link.href) + }, index * 50) + }) + }).finally(() => { this.isDownloading = false }) }