hydrogen-web/prototypes/idb-store-files.html

162 lines
5.7 KiB
HTML

<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<ul id="files"></ul>
<p>
<input type="file" id="file" multiple capture="user" accept="image/*">
<button id="addFile">Add</button>
<button id="drop">Delete all</button>
</p>
<script type="text/javascript">
function reqAsPromise(req) {
return new Promise((resolve, reject) => {
req.onsuccess = () => resolve(req);
req.onerror = (err) => reject(err);
});
}
function fetchResults(cursor, isDone, resultMapper) {
return new Promise((resolve, reject) => {
const results = [];
cursor.onerror = (event) => {
reject(new Error("Query failed: " + event.target.errorCode));
};
// collect results
cursor.onsuccess = (event) => {
const cursor = event.target.result;
if (!cursor) {
resolve(results);
return; // end of results
}
results.push(resultMapper(cursor));
if (!isDone(results)) {
cursor.continue();
} else {
resolve(results);
}
};
});
}
class Storage {
constructor(databaseName) {
this._databaseName = databaseName;
this._database = null;
}
async open() {
const req = window.indexedDB.open(this._databaseName);
req.onupgradeneeded = (ev) => {
const db = ev.target.result;
const oldVersion = ev.oldVersion;
this._createStores(db, oldVersion);
};
await reqAsPromise(req);
this._database = req.result;
}
async drop() {
if (this._database) {
this._database.close();
this._database = null;
}
await reqAsPromise(window.indexedDB.deleteDatabase(this._databaseName));
}
_createStores(db) {
db.createObjectStore("files", {keyPath: "id"});
}
async storeFile(file) {
const id = Math.floor(Math.random() * 10000000000);
console.log(`adding a file as id ${id}`);
const tx = this._database.transaction(["files"], "readwrite");
const store = tx.objectStore("files");
await reqAsPromise(store.add({id, file}));
}
getFiles() {
const tx = this._database.transaction(["files"], "readonly");
const store = tx.objectStore("files");
const cursor = store.openCursor();
return fetchResults(cursor,
() => false,
(cursor) => cursor.value);
}
}
async function reloadFiles(storage, fileList) {
const files = await storage.getFiles();
const fileNodes = files.map(f => {
const {type, size, name} = f.file;
const txt = document.createTextNode(`${f.id} - ${name} of type ${type} - size: ${Math.round(size / 1024, 2)}kb`);
const li = document.createElement("li");
li.addEventListener("click", async () => {
const reader = new FileReader();
const promise = new Promise((resolve, reject) => {
reader.onload = e => resolve(e.target.result);
reader.onerror = e => reject(e.target.error);
});
reader.readAsArrayBuffer(f.file);
try {
const buf = await promise;
alert(`read blob, len is ${buf.byteLength}`);
} catch(e) {
alert(e.message);
}
});
li.appendChild(txt);
return li;
});
fileList.innerHTML = "";
for(const li of fileNodes) {
fileList.appendChild(li);
}
}
async function main() {
let storage = new Storage("idb-store-files-test");
await storage.open();
const fileList = document.getElementById("files");
const dropButton = document.getElementById("drop");
const addButton = document.getElementById("addFile");
const filePicker = document.getElementById("file");
addButton.addEventListener("click", async () => {
const files = Array.from(filePicker.files);
try {
for(const file of files) {
await storage.storeFile(file);
}
alert(`stored ${files.length} files!`);
reloadFiles(storage, fileList);
} catch(e) {
alert(e.message);
}
});
dropButton.addEventListener("click", async () => {
try {
if (storage) {
await storage.drop();
storage = null;
alert("dropped db");
}
} catch(e) {
alert(e.message);
}
});
reloadFiles(storage, fileList);
}
main();
</script>
</body>
</html>