<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>