try fflate
This commit is contained in:
parent
2b727e1755
commit
0f450e4189
5 changed files with 134 additions and 69 deletions
File diff suppressed because one or more lines are too long
104
content.js
104
content.js
|
|
@ -267,21 +267,66 @@ async function getArchiveViewerHtmlSource() {
|
||||||
return response.text()
|
return response.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bundle the viewer's JSZip runtime so the exported archive can be browsed offline.
|
// Bundle the viewer's fflate runtime so the exported archive can be browsed offline.
|
||||||
async function getArchiveViewerJsZipSource() {
|
async function getArchiveViewerFflateSource() {
|
||||||
const candidates = [
|
const response = await fetch(chrome.runtime.getURL("lib/fflate.min.js"))
|
||||||
"lib/jszip.min.js"
|
|
||||||
]
|
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
if (!response.ok) {
|
||||||
const response = await fetch(chrome.runtime.getURL(candidate))
|
throw new Error("Failed to load archive viewer dependency")
|
||||||
|
}
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
return response.text()
|
return response.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFflate() {
|
||||||
|
if (typeof fflate === "undefined") {
|
||||||
|
throw new Error("fflate is not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("Failed to load archive viewer dependency")
|
return fflate
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createZipBlob(entries, onProgress = () => { }) {
|
||||||
|
const { strToU8, zip } = getFflate()
|
||||||
|
const archiveEntries = {}
|
||||||
|
let processedEntries = 0
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.data instanceof Blob) {
|
||||||
|
archiveEntries[entry.path] = new Uint8Array(await entry.data.arrayBuffer())
|
||||||
|
} else if (entry.data instanceof Uint8Array) {
|
||||||
|
archiveEntries[entry.path] = entry.data
|
||||||
|
} else {
|
||||||
|
archiveEntries[entry.path] = strToU8(String(entry.data ?? ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.data = null
|
||||||
|
processedEntries += 1
|
||||||
|
onProgress({
|
||||||
|
phase: "preparing",
|
||||||
|
processedEntries,
|
||||||
|
totalEntries: entries.length
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onProgress({
|
||||||
|
phase: "generating",
|
||||||
|
processedEntries,
|
||||||
|
totalEntries: entries.length
|
||||||
|
})
|
||||||
|
|
||||||
|
const archiveBytes = await new Promise((resolve, reject) => {
|
||||||
|
zip(archiveEntries, { level: 0, consume: true }, (error, data) => {
|
||||||
|
if (error != null) {
|
||||||
|
reject(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return new Blob([archiveBytes], { type: "application/zip" })
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadBlob(blob, fileName) {
|
function downloadBlob(blob, fileName) {
|
||||||
|
|
@ -470,7 +515,7 @@ function rip(event) {
|
||||||
|
|
||||||
console.log("Preparing zip archive...")
|
console.log("Preparing zip archive...")
|
||||||
progressDialog.setStatus("Preparing zip archive...")
|
progressDialog.setStatus("Preparing zip archive...")
|
||||||
const zip = new JSZip()
|
const archiveEntries = []
|
||||||
const successfulApplicants = []
|
const successfulApplicants = []
|
||||||
|
|
||||||
applicantDetailsResults.forEach((result) => {
|
applicantDetailsResults.forEach((result) => {
|
||||||
|
|
@ -479,30 +524,53 @@ function rip(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const applicantDetails = result.value
|
const applicantDetails = result.value
|
||||||
const dirName = getApplicantDirectoryName(applicantDetails)
|
|
||||||
const applicantDir = zip.folder(`${APPLICATIONS_DIRECTORY}/${dirName}`)
|
|
||||||
const archiveFiles = getApplicantArchiveFiles(applicantDetails)
|
const archiveFiles = getApplicantArchiveFiles(applicantDetails)
|
||||||
|
|
||||||
successfulApplicants.push(applicantDetails)
|
successfulApplicants.push(applicantDetails)
|
||||||
|
|
||||||
archiveFiles.forEach((archiveFile, index) => {
|
archiveFiles.forEach((archiveFile, index) => {
|
||||||
const afile = applicantDetails.application_files[index]
|
const afile = applicantDetails.application_files[index]
|
||||||
applicantDir.file(archiveFile.fileName, afile.blob)
|
archiveEntries.push({
|
||||||
|
path: archiveFile.relativePath,
|
||||||
|
data: afile.blob
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const [viewerHtmlSource, viewerFflateSource] = await Promise.all([
|
||||||
|
getArchiveViewerHtmlSource(),
|
||||||
|
getArchiveViewerFflateSource()
|
||||||
|
])
|
||||||
|
|
||||||
console.log("Creating applicants.csv")
|
console.log("Creating applicants.csv")
|
||||||
zip.file("applicants.csv", createApplicantsCsv(successfulApplicants))
|
archiveEntries.push({
|
||||||
|
path: "applicants.csv",
|
||||||
|
data: createApplicantsCsv(successfulApplicants)
|
||||||
|
})
|
||||||
|
|
||||||
console.log("Creating index.html")
|
console.log("Creating index.html")
|
||||||
zip.file("viewer.html", await getArchiveViewerHtmlSource())
|
archiveEntries.push({
|
||||||
|
path: "viewer.html",
|
||||||
|
data: viewerHtmlSource
|
||||||
|
})
|
||||||
|
|
||||||
console.log("Adding viewer Javascript to archive")
|
console.log("Adding viewer Javascript to archive")
|
||||||
zip.file("jszip.min.js", await getArchiveViewerJsZipSource())
|
archiveEntries.push({
|
||||||
|
path: "fflate.min.js",
|
||||||
|
data: viewerFflateSource
|
||||||
|
})
|
||||||
|
|
||||||
console.log("Generating zip archive...")
|
console.log("Generating zip archive...")
|
||||||
const zipBlob = await zip.generateAsync({ type: "blob" })
|
const zipBlob = await createZipBlob(archiveEntries, ({ phase, processedEntries, totalEntries }) => {
|
||||||
|
if (phase === "preparing") {
|
||||||
|
if (processedEntries === totalEntries || processedEntries === 1 || processedEntries % 10 === 0) {
|
||||||
|
progressDialog.setStatus(`Preparing zip archive (${processedEntries}/${totalEntries})...`)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
progressDialog.setStatus("Generating zip archive in background... Firefox should stay responsive.")
|
||||||
|
})
|
||||||
|
|
||||||
console.log("Zip archive is ready.")
|
console.log("Zip archive is ready.")
|
||||||
progressDialog.setStatus("Download ready.")
|
progressDialog.setStatus("Download ready.")
|
||||||
|
|
|
||||||
1
lib/fflate.min.js
vendored
Normal file
1
lib/fflate.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
13
lib/jszip.min.js
vendored
13
lib/jszip.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -12,7 +12,7 @@
|
||||||
"https://personal.uni-graz.at/*"
|
"https://personal.uni-graz.at/*"
|
||||||
],
|
],
|
||||||
"js": [
|
"js": [
|
||||||
"lib/jszip.min.js",
|
"lib/fflate.min.js",
|
||||||
"content.js"
|
"content.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
{
|
{
|
||||||
"resources": [
|
"resources": [
|
||||||
"archive-viewer/index.html",
|
"archive-viewer/index.html",
|
||||||
"lib/jszip.min.js"
|
"lib/fflate.min.js"
|
||||||
],
|
],
|
||||||
"matches": [
|
"matches": [
|
||||||
"https://personal.uni-graz.at/*"
|
"https://personal.uni-graz.at/*"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue