diff --git a/src/assets/site.css b/src/assets/site.css index efc9084..9e695fb 100644 --- a/src/assets/site.css +++ b/src/assets/site.css @@ -647,6 +647,9 @@ tbody th a:hover code { text-decoration: underline; } at once for one a chat sent with the source in the link. What is said to one alone is not shown to the other; the class is on before the page paints (index.njk). */ .linked .when-unlinked, :root:not(.linked) .when-linked { display: none; } +/* A link whose source could not be read: what is said of the source it carried gives way to what + is said of the link, from when build-page.ts has tried it. */ +.unread .when-read, :root:not(.unread) .when-unread { display: none; } /* A bar at the top, then bands the width of the window, each holding a column of the page's width. */ :root { diff --git a/src/h5p/build/build-page.ts b/src/h5p/build/build-page.ts index 385f939..70dff9f 100644 --- a/src/h5p/build/build-page.ts +++ b/src/h5p/build/build-page.ts @@ -26,7 +26,8 @@ import { formatSource, jsonProblem, place, type Target } from './json-scan' * a sample that plays (`SAMPLE`), and finds the sample's source in the box, which the first paste * replaces whole (`prefillSample`). The markup says which words are for whom, and the class * `linked` on `` shows them, set before the page paints by the script in `index.njk` and - * kept in step with the address here. + * kept in step with the address here. A link whose source cannot be read is said to be damaged, + * with the ways to bring the source (`linkUnread`). */ type Opened = Awaited> @@ -41,6 +42,8 @@ const sourceField = $('source') const sourceLabel = $('source-label') const sourceState = $('source-state') const sourceFile = $('source-file') +const linkState = $('link-state') +const openSource = $('open-source') const filesStep = $('files-step') const fileList = $('file-list') const filesInput = $('files') @@ -117,6 +120,28 @@ function setStatus(text: string, state: 'idle' | 'building' | 'ready' | 'error') status.dataset.state = state } +/** + * A link whose source cannot be read. A chat writes the link out in its reply, and a compressed + * source survives no wrong character: a link ChatGPT gave held 43 characters of its own in place + * of 37, near its start, and was the command's output everywhere else. The page then said the link + * had carried the source, over an empty box, with the reason under Build, out of sight in a window + * 800px high. So it says the link is damaged where a person who opened it looks. The class `unread` + * on `` shows what the hero says of such a link in place of what it says of a source the link + * carried, for the rest of the visit, since the link carried none whatever comes after. The words + * above the box are the ways to bring the source, and stay until one is here (`checkSource`). + */ +function linkUnread(unread: boolean): void { + document.documentElement.classList.toggle('unread', unread) + showLinkState(unread) +} + +/** The words above the box, and with them the step's marker, which site.css draws from their state. */ +function showLinkState(show: boolean): void { + linkState.hidden = !show + if (show) linkState.dataset.state = 'error' + else delete linkState.dataset.state +} + /** Where a problem is in the source, for the button that goes there: its place in the text, or none. */ function target({ path, at }: Problem): Target { return at === undefined ? { path } : { at } @@ -316,6 +341,8 @@ player.addEventListener('error', (event) => { */ function checkSource(): void { const text = sourceField.value + // A source came after a link that could not be read, from a file or a paste: the ways to bring one go. + if (!linkState.hidden && compactSource(text)) showLinkState(false) const problem = jsonProblem(text) sourceState.dataset.state = problem ? 'error' : text.trim() ? 'ok' : '' if (!problem) { @@ -406,6 +433,8 @@ sourceFile.addEventListener('change', async () => { if (!file) return setSource(await file.text()) }) +// The same file field, from the words above the box on a link that could not be read. +openSource.addEventListener('click', () => sourceFile.click()) // The label is for the textarea, which the editor hides: a click on it goes to the editor. sourceLabel.addEventListener('click', () => editor?.focus()) @@ -537,9 +566,12 @@ async function fromLink(): Promise { try { text = await sourceFromFragment(location.hash) } catch (error) { - setStatus(error instanceof Error ? error.message : String(error), 'error') + // Why it cannot be read is for whoever looks into it; the person is told what to do. + console.warn(error instanceof Error ? error.message : String(error)) + linkUnread(true) return } + linkUnread(false) if (text === null) return carried = compactSource(text) ?? '' setSource(text) diff --git a/src/h5p/build/index.njk b/src/h5p/build/index.njk index bbc01e0..3a55f75 100644 --- a/src/h5p/build/index.njk +++ b/src/h5p/build/index.njk @@ -30,7 +30,10 @@ csp: "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' da (#source=), gets the build at once. One who came with none gets a landing page: what it makes, a sample that plays, how to make their own. What is said to one alone is marked when-linked or when-unlinked, and site.css shows it by the class this line puts on before the page - paints; build-page.ts keeps the class in step with the address from then on. -#} + paints; build-page.ts keeps the class in step with the address from then on. A link whose + source cannot be read is a third case, which build-page.ts finds once it has tried: it puts + `unread` on , and what is said of a source the link carried is marked when-read, what is + said in its place when-unread. -#} {% include "topbar.njk" %} @@ -51,11 +54,20 @@ csp: "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' da Make your own Paste your chat's JSON -

The link you opened carries an activity an AI chat wrote.

-

+

The link you opened carries an activity an AI chat wrote.

+

This page builds it in your browser, where you play it and download a .h5p file that Moodle or any other H5P site takes. Nothing is uploaded.

+ {#- A link whose source cannot be read: a chat writes the link out itself, and one wrong + character leaves nothing of a compressed source. The page says so here, first, in place + of saying the link carried an activity, and what to do above the source's box. These + two stay for the visit, so they say what stays true once the source has come another way. -#} +

The link you opened arrived damaged, so the activity in it cannot be read.

+

+ This page builds an activity in your browser from its source, which + step 1 says how to bring here. Nothing is uploaded. +

{#- The sample is /h5p/build/sample.h5p, which Vite builds from sample.json beside this file. build-page.ts gives the player its address only for a visitor who came with no source. -#} @@ -157,7 +169,16 @@ csp: "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' da

1 Source

The source is your activity as the chat wrote it. The sample's is here to start with: paste yours over it, or open it from a file.

-

The source is your activity as the chat wrote it. The link carried it here.

+

The source is your activity as the chat wrote it. The link carried it here.

+ {#- Shown by build-page.ts for a link whose source cannot be read, until a source is here: above + the box, where a person who opened the link looks, with each way to bring the source. -#} +