Skip to content

Commit 30ee601

Browse files
committed
Document the build page's source editor (#27)
1 parent 1c2a8da commit 30ee601

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

‎docs/h5p-build-page.md‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,27 @@ Nothing leaves the browser. A link can carry the source in its fragment, which n
99
| [src/h5p/build/index.njk](../src/h5p/build/index.njk) | The page's markup, in the site's layout, and its Content-Security-Policy: GitHub Pages sends no headers, so a `<meta>` tag is the only policy it gets |
1010
| [src/h5p/build/build-page.ts](../src/h5p/build/build-page.ts) | The page's wiring: the build, the player, the download, a link's source |
1111
| [src/h5p/build/build-source.ts](../src/h5p/build/build-source.ts) | What it does with a source with no DOM: the link's fragment, the files a source names, the content types it is written in, the text for the chat |
12+
| [src/h5p/build/editor.ts](../src/h5p/build/editor.ts) | The source's editor, CodeMirror 6, mounted in a shadow root and loaded apart from the page: see [The source editor](#the-source-editor) |
13+
| [src/h5p/build/json-scan.ts](../src/h5p/build/json-scan.ts) | What it reads of JSON text with no DOM: where a text stops being JSON and what is wrong there, and where a problem's path points |
1214
| [src/assets/site.css](../src/assets/site.css) | Its styles, under *H5P build page* |
1315
| [vite.config.ts](../vite.config.ts) | The page's script, `/h5p/build/build-page.js`, with the player, its runtime, the pack and their licence files in `/h5p/assets/`, and the type files in `/h5p/build/types/` |
14-
| [e2e/](../e2e/), [playwright.config.ts](../playwright.config.ts) | The browser tests: a pasted source, one from a link and one with a file of its own build, play and download; a source's problems are listed, and copied for the chat with the type files; `/h5p/bundles/` serves every bundle and part, and its tool and a bundle build a quiz in an empty folder; `/h5p/skill/` serves the skill's files as the package carries them, and writes out every address |
16+
| [e2e/](../e2e/), [playwright.config.ts](../playwright.config.ts) | The browser tests: a pasted source, one from a link and one with a file of its own build, play and download; the source's editor marks a mistake and the problems the build finds, and `json-scan.spec.ts` tests the reading of JSON with no browser; a source's problems are listed, and copied for the chat with the type files; `/h5p/bundles/` serves every bundle and part, and its tool and a bundle build a quiz in an empty folder; `/h5p/skill/` serves the skill's files as the package carries them, and writes out every address |
1517

1618
The player's Service Worker is in `/h5p/assets/` too, so its scope is `/h5p/assets/h5p/`: no other page of the site is under it. The address names who runs the page, as H5P Group's trademark policy asks of a name with "H5P" in it, and the page uses the word descriptively.
1719

1820
The page and the bundles were embed-my.github.io's `/build` and `/bundles/` until 2026-11-10. Its `/build` is now a page that sends a visit here with its fragment, so the links chats wrote before still build ([embed-my/embed-my.github.io#18](https://github.com/embed-my/embed-my.github.io/pull/18)).
1921

22+
## The source editor
23+
24+
A person who gets a source from a chat is a teacher, not a developer, and a missing comma or quote is invisible in a textarea until Build says the source cannot be read. So the source is edited in an editor. `editor.ts` is CodeMirror 6, and `build-page.ts` loads it apart from the page (`import('./editor')`, a chunk of its own in `/h5p/assets/`). Where it cannot load, the textarea stays as the source and the page works. The textarea stays under the editor, hidden, holding the same text, so the rest of the page reads the source as it always did.
25+
26+
- **JSON in colours**, with line numbers, matching brackets and undo. The colours are the site's token colours, custom properties that reach into the editor, so light and dark need no code.
27+
- **A mistake in the JSON is marked as it is typed**, and said under the source with its line and column, in words for someone who does not write JSON ("A comma is missing here"), with a button that goes there. `JSON.parse` still decides whether text is JSON. `json-scan.ts` says where, because `JSON.parse` says it differently in each browser and Safari does not say at all. `parseSource` uses it too, so the copy for the chat carries the line and the column.
28+
- **The problems the build finds are marked where they are**, and the name of a problem in the list is a button that goes there. A problem's path, `params.chapters[0].metadata.title`, is looked up in the text by `locate`: a name and its value, and for what the source is missing, the object it is missing from. The marks are of the text as it was built, so a change to the text clears them.
29+
- **Format** lays the source out, and takes it out of the code fence a chat may have put it in.
30+
31+
The editor has to fit the page's policy, which has no `style-src 'unsafe-inline'`: an editor that adds a `<style>` to the page is refused. In a shadow root CodeMirror adopts its styles as a constructed stylesheet instead, which the policy does not govern. Chrome's own editing also gives text typed over a selection of coloured text a `style` attribute, which the policy refuses and reports; `contenteditable="plaintext-only"` does not stop it. So the editor takes that typing itself (`typeOverSelection`), through its input handlers, and a bracket or a quote typed over a selection still wraps it. Tab is not the editor's: it leaves it, so the keyboard is never trapped. The browser tests that watch the page fail on any policy report.
32+
2033
## The type files
2134

2235
A chat in a browser, such as Gemini in Chrome, has the skill's text and none of its files, and can run nothing. It guesses how a content type is written, and each round of problems tells it the names of one level. So **Copy the problems for the chat** copies more than the list: after the problems come the skill's type files of the source's own content type and of the libraries named below it, each a type's notes, an example and its fields. The source's own type is the one the build takes it to be, h5p-author's `sourceType` (since 0.8.0): its `type` as written or as it is spoken of, `"interactive-book"`, or with none the one under `contentType` or `library`, as a chat with no skill text writes it. Below it, a library counts by its machine name, under any key: a slide's element `{ "type": "text" }` is no H5P.Text.

0 commit comments

Comments
 (0)