Sebastiankay
commited on
Create demo-read-file.js
Browse files- demo-read-file.js +159 -0
demo-read-file.js
ADDED
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* global zip, document, URL, MouseEvent, AbortController, alert */
|
2 |
+
|
3 |
+
(() => {
|
4 |
+
|
5 |
+
if (typeof TransformStream == "undefined") {
|
6 |
+
const script = document.createElement("script");
|
7 |
+
script.src = "lib/web-streams-polyfill.min.js";
|
8 |
+
document.body.appendChild(script);
|
9 |
+
}
|
10 |
+
|
11 |
+
const model = (() => {
|
12 |
+
|
13 |
+
return {
|
14 |
+
getEntries(file, options) {
|
15 |
+
return (new zip.ZipReader(new zip.BlobReader(file))).getEntries(options);
|
16 |
+
},
|
17 |
+
async getURL(entry, options) {
|
18 |
+
return URL.createObjectURL(await entry.getData(new zip.BlobWriter(), options));
|
19 |
+
}
|
20 |
+
};
|
21 |
+
|
22 |
+
})();
|
23 |
+
|
24 |
+
(() => {
|
25 |
+
|
26 |
+
const appContainer = document.getElementById("container");
|
27 |
+
const fileInput = document.getElementById("file-input");
|
28 |
+
const encodingInput = document.getElementById("encoding-input");
|
29 |
+
const fileInputButton = document.getElementById("file-input-button");
|
30 |
+
const passwordInput = document.getElementById("password-input");
|
31 |
+
let fileList = document.getElementById("file-list");
|
32 |
+
let entries;
|
33 |
+
let selectedFile;
|
34 |
+
passwordInput.onchange = async () => fileList.querySelectorAll("a[download]").forEach(anchor => anchor.download = "");
|
35 |
+
fileInput.onchange = selectFile;
|
36 |
+
encodingInput.onchange = selectEncoding;
|
37 |
+
appContainer.onclick = downloadFile;
|
38 |
+
fileInputButton.onclick = () => fileInput.dispatchEvent(new MouseEvent("click"));
|
39 |
+
|
40 |
+
async function downloadFile(event) {
|
41 |
+
const target = event.target;
|
42 |
+
let href = target.getAttribute("href");
|
43 |
+
if (target.dataset.entryIndex !== undefined && !target.download && !href) {
|
44 |
+
target.removeAttribute("href");
|
45 |
+
event.preventDefault();
|
46 |
+
try {
|
47 |
+
await download(entries[Number(target.dataset.entryIndex)], target.parentElement.parentElement, target);
|
48 |
+
href = target.getAttribute("href");
|
49 |
+
} catch (error) {
|
50 |
+
alert(error);
|
51 |
+
}
|
52 |
+
target.setAttribute("href", href);
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
async function selectFile() {
|
57 |
+
try {
|
58 |
+
fileInputButton.disabled = true;
|
59 |
+
encodingInput.disabled = true;
|
60 |
+
selectedFile = fileInput.files[0];
|
61 |
+
await loadFiles();
|
62 |
+
} catch (error) {
|
63 |
+
alert(error);
|
64 |
+
} finally {
|
65 |
+
fileInputButton.disabled = false;
|
66 |
+
fileInput.value = "";
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
async function selectEncoding() {
|
71 |
+
try {
|
72 |
+
encodingInput.disabled = true;
|
73 |
+
fileInputButton.disabled = true;
|
74 |
+
await loadFiles(encodingInput.value);
|
75 |
+
} catch (error) {
|
76 |
+
alert(error);
|
77 |
+
} finally {
|
78 |
+
fileInputButton.disabled = false;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
async function loadFiles(filenameEncoding) {
|
83 |
+
entries = await model.getEntries(selectedFile, { filenameEncoding });
|
84 |
+
if (entries && entries.length) {
|
85 |
+
fileList.classList.remove("empty");
|
86 |
+
const filenamesUTF8 = Boolean(!entries.find(entry => !entry.filenameUTF8));
|
87 |
+
const encrypted = Boolean(entries.find(entry => entry.encrypted));
|
88 |
+
encodingInput.value = filenamesUTF8 ? "utf-8" : filenameEncoding || "cp437";
|
89 |
+
encodingInput.disabled = filenamesUTF8;
|
90 |
+
passwordInput.value = "";
|
91 |
+
passwordInput.disabled = !encrypted;
|
92 |
+
refreshList();
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
function refreshList() {
|
97 |
+
const newFileList = fileList.cloneNode();
|
98 |
+
entries.forEach((entry, entryIndex) => {
|
99 |
+
const li = document.createElement("li");
|
100 |
+
const filenameContainer = document.createElement("span");
|
101 |
+
const filename = document.createElement("a");
|
102 |
+
filenameContainer.classList.add("filename-container");
|
103 |
+
li.appendChild(filenameContainer);
|
104 |
+
filename.classList.add("filename");
|
105 |
+
filename.dataset.entryIndex = entryIndex;
|
106 |
+
filename.textContent = filename.title = entry.filename;
|
107 |
+
filename.title = `${entry.filename}\n Last modification date: ${entry.lastModDate.toLocaleString()}`;
|
108 |
+
if (!entry.directory) {
|
109 |
+
filename.href = "";
|
110 |
+
filename.title += `\n Uncompressed size: ${entry.uncompressedSize.toLocaleString()} bytes`;
|
111 |
+
}
|
112 |
+
filenameContainer.appendChild(filename);
|
113 |
+
newFileList.appendChild(li);
|
114 |
+
});
|
115 |
+
fileList.replaceWith(newFileList);
|
116 |
+
fileList = newFileList;
|
117 |
+
}
|
118 |
+
|
119 |
+
async function download(entry, li, a) {
|
120 |
+
if (!li.classList.contains("busy")) {
|
121 |
+
const unzipProgress = document.createElement("progress");
|
122 |
+
li.appendChild(unzipProgress);
|
123 |
+
const controller = new AbortController();
|
124 |
+
const signal = controller.signal;
|
125 |
+
const abortButton = document.createElement("button");
|
126 |
+
abortButton.onclick = () => controller.abort();
|
127 |
+
abortButton.textContent = "✖";
|
128 |
+
abortButton.title = "Abort";
|
129 |
+
li.querySelector(".filename-container").appendChild(abortButton);
|
130 |
+
li.classList.add("busy");
|
131 |
+
li.onclick = event => event.preventDefault();
|
132 |
+
try {
|
133 |
+
const blobURL = await model.getURL(entry, {
|
134 |
+
password: passwordInput.value,
|
135 |
+
onprogress: (index, max) => {
|
136 |
+
unzipProgress.value = index;
|
137 |
+
unzipProgress.max = max;
|
138 |
+
},
|
139 |
+
signal
|
140 |
+
});
|
141 |
+
a.href = blobURL;
|
142 |
+
a.download = entry.filename;
|
143 |
+
const clickEvent = new MouseEvent("click");
|
144 |
+
a.dispatchEvent(clickEvent);
|
145 |
+
} catch (error) {
|
146 |
+
if (!signal.reason || signal.reason.code != error.code) {
|
147 |
+
throw error;
|
148 |
+
}
|
149 |
+
} finally {
|
150 |
+
li.classList.remove("busy");
|
151 |
+
unzipProgress.remove();
|
152 |
+
abortButton.remove();
|
153 |
+
}
|
154 |
+
}
|
155 |
+
}
|
156 |
+
|
157 |
+
})();
|
158 |
+
|
159 |
+
})();
|