Offline edits that send when back online, books saved on the device, and keyboard access for dialogs and Bible verses; roadmap
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
275ef2009f
commit
95ade02bf2
11 files changed
+96
-18
No files matched your search
+16
-1
@@ -77,11 +77,26 @@ async function rdLibrary() {
|
||||
$('#rdhint').insertAdjacentHTML('beforeend', ' Press and hold, or right-click, a book for more.');
|
||||
}
|
||||
|
||||
function rdBookMenu(b) {
|
||||
const rdOffKey = id => `/api/read/book/${id}/file`;
|
||||
const rdSaved = async id => { try { return !!(await (await caches.open('hub-offline')).match(rdOffKey(id))); } catch { return false; } };
|
||||
/** Keep a book (and what the reader needs to open it) on this device, so it opens with no signal. */
|
||||
async function rdSaveOffline(b) {
|
||||
if (!('caches' in window)) return toast('This browser cannot save for offline');
|
||||
try {
|
||||
toast('Saving “' + b.title + '”…'); const c = await caches.open('hub-offline'), r = await fetch(rdOffKey(b.id) + '?inline=1'); if (!r.ok) throw new Error('Could not download the book (' + r.status + ')');
|
||||
await c.put(rdOffKey(b.id), r); if (b.cover) { try { const cv = await fetch(`/api/read/book/${b.id}/cover`); if (cv.ok) await c.put(`/api/read/book/${b.id}/cover`, cv); } catch { /* the cover is a nicety */ } }
|
||||
await rdLibs(rdKind(b.ext)).catch(() => {}); // (so the reader's own scripts are in the cache too)
|
||||
if (navigator.storage && navigator.storage.persist) navigator.storage.persist().catch(() => {}); toast('Saved on this device. It opens with no signal.');
|
||||
} catch (e) { try { await (await caches.open('hub-offline')).delete(rdOffKey(b.id)); } catch {} toast(e.message || 'Could not save'); }
|
||||
}
|
||||
async function rdRemoveOffline(b) { try { const c = await caches.open('hub-offline'); await c.delete(rdOffKey(b.id)); await c.delete(`/api/read/book/${b.id}/cover`); toast('Removed from this device'); } catch { /* nothing saved */ } }
|
||||
async function rdBookMenu(b) {
|
||||
if (!b) return;
|
||||
const saved = await rdSaved(b.id);
|
||||
actionSheet(b.title, b.author || b.ext.toUpperCase(), [
|
||||
{ icon: 'book', label: 'Open', run: () => { location.hash = '#/read/open/' + b.id; } },
|
||||
{ icon: 'edit', label: 'Edit title and author', run: () => rdEditBook(b) },
|
||||
saved ? { icon: 'dl', label: 'Remove from this device', run: () => rdRemoveOffline(b) } : { icon: 'dl', label: 'Save on this device (read offline)', run: () => rdSaveOffline(b) },
|
||||
...(allowed('files') ? [{ icon: 'files', label: 'Save to Files', run: () => saveToFiles(b.title, { kind: 'book', id: b.id }) }] : []),
|
||||
{ icon: 'dl', label: 'Download', run: () => { const a = document.createElement('a'); a.href = `/api/read/book/${b.id}/file`; a.download = b.title + '.' + b.ext; document.body.appendChild(a); a.click(); a.remove(); } },
|
||||
{ icon: 'trash', label: 'Delete from library', danger: true, run: () => confirmSheet('Delete this book?', `"${b.title}" and your bookmarks, notes and highlights in it are removed.`, 'Delete', async () => {
|
||||
|
||||
Reference in new issue
Block a user