Skip to content

Commit 1b2d978

Browse files
committed
download multiple files on safari ios
1 parent 30582b2 commit 1b2d978

2 files changed

Lines changed: 102 additions & 30 deletions

File tree

app/javascript/elements/download_button.js

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,64 @@ export default targetable(class extends HTMLElement {
1818
this.toggleState()
1919

2020
fetch(this.dataset.src).then((response) => response.json()).then((urls) => {
21-
const fileRequests = urls.map((url) => {
22-
return () => {
23-
return fetch(url).then(async (resp) => {
24-
const blobUrl = URL.createObjectURL(await resp.blob())
25-
const link = document.createElement('a')
21+
const isSafariIos = /iPhone|iPad|iPod/i.test(navigator.userAgent)
2622

27-
link.href = blobUrl
28-
link.setAttribute('download', decodeURI(url.split('/').pop()))
23+
if (isSafariIos && urls.length > 1) {
24+
this.downloadSafariIos(urls)
25+
} else {
26+
this.downloadUrls(urls)
27+
}
28+
})
29+
}
30+
31+
downloadUrls (urls) {
32+
const fileRequests = urls.map((url) => {
33+
return () => {
34+
return fetch(url).then(async (resp) => {
35+
const blobUrl = URL.createObjectURL(await resp.blob())
36+
const link = document.createElement('a')
37+
38+
link.href = blobUrl
39+
link.setAttribute('download', decodeURI(url.split('/').pop()))
40+
41+
link.click()
42+
43+
URL.revokeObjectURL(blobUrl)
44+
})
45+
}
46+
})
2947

30-
link.click()
48+
fileRequests.reduce(
49+
(prevPromise, request) => prevPromise.then(() => request()),
50+
Promise.resolve()
51+
)
3152

32-
URL.revokeObjectURL(url)
33-
})
34-
}
53+
this.toggleState()
54+
}
55+
56+
downloadSafariIos (urls) {
57+
const fileRequests = urls.map((url) => {
58+
return fetch(url).then(async (resp) => {
59+
const blob = await resp.blob()
60+
const blobUrl = URL.createObjectURL(blob.slice(0, blob.size, 'application/octet-stream'))
61+
const link = document.createElement('a')
62+
63+
link.href = blobUrl
64+
link.setAttribute('download', decodeURI(url.split('/').pop()))
65+
66+
return link
3567
})
68+
})
3669

37-
fileRequests.reduce(
38-
(prevPromise, request) => prevPromise.then(() => request()),
39-
Promise.resolve()
40-
)
70+
Promise.all(fileRequests).then((links) => {
71+
links.forEach((link, index) => {
72+
setTimeout(() => {
73+
link.click()
4174

75+
URL.revokeObjectURL(link.href)
76+
}, index * 50)
77+
})
78+
}).finally(() => {
4279
this.toggleState()
4380
})
4481
}

app/javascript/submission_form/completed.vue

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -179,27 +179,62 @@ export default {
179179
this.isDownloading = true
180180
181181
fetch(this.baseUrl + `/submitters/${this.submitterSlug}/download`).then((response) => response.json()).then((urls) => {
182-
const fileRequests = urls.map((url) => {
183-
return () => {
184-
return fetch(url).then(async (resp) => {
185-
const blobUrl = URL.createObjectURL(await resp.blob())
186-
const link = document.createElement('a')
182+
const isSafariIos = /iPhone|iPad|iPod/i.test(navigator.userAgent)
187183
188-
link.href = blobUrl
189-
link.setAttribute('download', decodeURI(url.split('/').pop()))
184+
if (isSafariIos && urls.length > 1) {
185+
this.downloadSafariIos(urls)
186+
} else {
187+
this.downloadUrls(urls)
188+
}
189+
})
190+
},
191+
downloadUrls (urls) {
192+
const fileRequests = urls.map((url) => {
193+
return () => {
194+
return fetch(url).then(async (resp) => {
195+
const blobUrl = URL.createObjectURL(await resp.blob())
196+
const link = document.createElement('a')
197+
198+
link.href = blobUrl
199+
link.setAttribute('download', decodeURI(url.split('/').pop()))
200+
201+
link.click()
202+
203+
URL.revokeObjectURL(blobUrl)
204+
})
205+
}
206+
})
190207
191-
link.click()
208+
fileRequests.reduce(
209+
(prevPromise, request) => prevPromise.then(() => request()),
210+
Promise.resolve()
211+
)
192212
193-
URL.revokeObjectURL(url)
194-
})
195-
}
213+
this.isDownloading = false
214+
},
215+
downloadSafariIos (urls) {
216+
const fileRequests = urls.map((url) => {
217+
return fetch(url).then(async (resp) => {
218+
const blob = await resp.blob()
219+
const blobUrl = URL.createObjectURL(blob.slice(0, blob.size, 'application/octet-stream'))
220+
const link = document.createElement('a')
221+
222+
link.href = blobUrl
223+
link.setAttribute('download', decodeURI(url.split('/').pop()))
224+
225+
return link
196226
})
227+
})
197228
198-
fileRequests.reduce(
199-
(prevPromise, request) => prevPromise.then(() => request()),
200-
Promise.resolve()
201-
)
229+
Promise.all(fileRequests).then((links) => {
230+
links.forEach((link, index) => {
231+
setTimeout(() => {
232+
link.click()
202233
234+
URL.revokeObjectURL(link.href)
235+
}, index * 50)
236+
})
237+
}).finally(() => {
203238
this.isDownloading = false
204239
})
205240
}

0 commit comments

Comments
 (0)