A host from the web site; the same page kept once; deleting from the Notebooks chooser

From the development repository at 299f73d, 2026-10-11:
hosting from the site documented; a page loaded from a notebook and left
unchanged is not kept again; notebooks and pages are deleted from the
chooser, to the system's Trash (--trash); the Notebooks button.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ackandClaude Fable 5.1 committed 2026-10-11 16:59:03 +02:00
1 parent 4e3a281d65
commit 0d01e23d7c
15 files changed
+711 -63

No files matched your search

+37 -4
View File
@@ -17,6 +17,26 @@ const PAGES = 'pages';
const IDENTITY_KEY = 'kokkoja_identity';
const CURRENT_PAGE = 'Current.svg';
const KEPT_PAGE = /^(\d{4}_\d{2}_\d{2})_(\d{2,})\.svg$/;
/**
* What names a page file rather than describes the page: the session,
* the host, the page's id and number on the root element, and the title.
* A page loaded from a notebook is a new page with new ones of these, so
* two files of the same page differ here and nowhere else. They stand
* before the paper's <rect>, and only there; typed text may contain
* anything. The same rule as page_content() in kokkoja.py.
*/
const VOLATILE = / data-(?:session|host|page|number)="[^"]*"|<title>[^<]*<\/title>\n?/g;
/**
* @param {string} text A page file.
* @returns {string} The file without what names it, for telling the
* same page in two files.
*/
function pageContent(text) {
const paper = text.indexOf('<rect ');
return paper < 0 ? text.replace(VOLATILE, '')
: text.slice(0, paper).replace(VOLATILE, '') + text.slice(paper);
}
/**
* @typedef {object} StoredPage
@@ -112,7 +132,7 @@ export const backend = {
const keys = /** @type {[string, string][]} */ (await result(pages.getAllKeys()));
return [...new Set(keys.map(([notebook]) => notebook))].sort();
});
return { directory: '', notebooks: names };
return { directory: '', notebooks: names, trash: false };
},
async listPages(notebook) {
@@ -132,15 +152,17 @@ export const backend = {
},
// The same rules as keep_page() in kokkoja.py: nothing is kept of a
// blank page or of one already kept; the name is the day the page was
// last changed and a serial number.
// blank page or of one already kept (the same page, whatever names the
// file); the name is the day the page was last changed and a serial
// number.
async keepPage(notebook) {
return transaction('readwrite', async (pages) => {
const current = /** @type {StoredPage | undefined} */ (await result(pages.get([notebook, CURRENT_PAGE])));
const blank = !['data-stroke=', 'data-text=', '<image'].some((mark) => current?.text.includes(mark));
if (!current || blank) return { kept: null, new: false };
const kept = (await pagesOf(pages, notebook)).filter((page) => KEPT_PAGE.test(page.name));
const same = kept.find((page) => page.text === current.text);
const content = pageContent(current.text);
const same = kept.find((page) => pageContent(page.text) === content);
if (same) return { kept: same.name, new: false };
const day = dayOf(current.changed);
const serials = kept.map((page) => /** @type {RegExpExecArray} */ (KEPT_PAGE.exec(page.name)))
@@ -150,4 +172,15 @@ export const backend = {
return { kept: name, new: true };
});
},
// The browser has no trash: a deleted page is gone.
async discardNotebook(notebook) {
await transaction('readwrite', async (pages) => {
for (const page of await pagesOf(pages, notebook)) await result(pages.delete([notebook, page.name]));
});
},
async discardPage(notebook, pageName) {
await transaction('readwrite', async (pages) => { await result(pages.delete([notebook, pageName])); });
},
};