From a48fe732ce14327dc5aa8fbeca00f5904fb76b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martynas=20Jusevi=C4=8Dius?= Date: Fri, 11 Sep 2026 15:12:11 +0200 Subject: [PATCH 1/6] Node identity and parentage are XPath, not DOM calls Nine reads reached through ixsl:call/ixsl:get for facts the data model already exposes, so the module asked JavaScript a question XPath answers. isSameNode($a, $b) is `$a is $b`; parentNode is `..`; parentElement, which is null when the parent is not an element, is exactly `parent::*`; and a Range container's nodeType = 3 test is `instance of text()`. The event targets that carried two of the identity tests take `as="node()?"` so the comparison has a node to compare - the same typing relatedTarget already had in navigate.xsl, and the reason `is` was reachable there and not here. Two constructions follow: Object() through ixsl:call is ixsl:new('Object', []), the extension that exists for it; and typeahead's three-line scroll options object - allocate, set `block`, pass - is one XDM map literal, the form navigate.xsl was already passing to the same scrollIntoView on the line above its own call. Nothing moves in the DOM layer proper. Building detached subtrees through rdfae:element and splicing them with insertNode/appendChild/before stays: xsl:result-document emits at a location and returns nothing to hold, and the insertion model hands the constructed node onward to be spliced, to receive the caret and to seed a Range. That is an architecture, not a workaround, and converting it would be a redesign of the editing core. make sef compiles both entries; make test passes 52; make test-browser reports 532 assertions true with the two pre-existing canonicalSource paste-probe values unchanged. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd --- src/annotate.xsl | 14 +++++++------- src/edit.xsl | 7 ++++--- src/index.xsl | 2 +- src/navigate.xsl | 2 +- src/typeahead.xsl | 4 +--- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/annotate.xsl b/src/annotate.xsl index 6d40458..ca6e509 100644 --- a/src/annotate.xsl +++ b/src/annotate.xsl @@ -85,11 +85,10 @@ version="3.0"> - - - + + + - + + diff --git a/src/edit.xsl b/src/edit.xsl index d4c9019..b838e05 100644 --- a/src/edit.xsl +++ b/src/edit.xsl @@ -896,7 +896,8 @@ version="3.0"> - + + @@ -1193,7 +1194,7 @@ version="3.0"> - + @@ -1710,7 +1711,7 @@ version="3.0"> - + diff --git a/src/index.xsl b/src/index.xsl index ae7e71e..31fe9cd 100644 --- a/src/index.xsl +++ b/src/index.xsl @@ -60,7 +60,7 @@ version="3.0"> LinkedDataHub's window.LinkedDataHub); reached everywhere via rdfae:editor-state(). Hosts with their own initial template call this from there instead of main --> - + - - - - + From d75c0018085a1f39813032e8ebe6d2995519de1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martynas=20Jusevi=C4=8Dius?= Date: Mon, 14 Sep 2026 15:40:07 +0200 Subject: [PATCH 2/6] Every string the editor shows comes from a catalog a host can replace. The chrome hardcoded its English. 159 sites across eight modules - dialog labels and buttons, the toolbar, the slash menu, the breadcrumb and inspector, confirm() prompts, the titles set through ixsl:set-attribute - each one a literal in the template that rendered it. A host wanting the editor in its own language had nowhere to put a translation: overriding a whole dialog to change a word forks markup it would rather inherit, and editing a vendored copy of the source is worse, because the next copy silently reverts it. So the strings move to translations.rdf and the templates read them through rdfae:label(). The catalog is plain RDF/XML - rdf:Description keyed by rdf:nodeID, carrying rdfs:label per language - which needs no manifest format of its own and is the shape a host is likely to keep its own strings in already. A host translates the editor by overriding rdfae:translations() to return its catalog, or by pointing $translations-href at another document; overriding rdfae:label() as well replaces the language selection for a host that resolves it from something richer than $translations-lang. The keys are named after the concept rather than the English, so a catalog can be written against them without reading the templates. rdfae:translations() is two declarations under use-when rather than one with a branch: in SaxonJS the catalog resolves against the page URI the way the vocabularies do, so doc() hits the preloaded pool, and under Saxon there is no page and static-base-uri() reaches the file the test drivers read. A runtime branch cannot span that, because ixsl:location() does not exist to compile against outside SaxonJS. Like the vocabularies, the catalog has to be preloaded by the host page - index.html and the four test fixtures now do, and generate-sef.sh copies it into dist/. Two things a host should not have to patch travel with it. Every dialog label now carries @for and its control an @id, so clicking the label focuses the field it names - the labels were bare, pointing at nothing. And the block drag handle's class becomes rdfa-editor-drag-handle: `drag-handle` is a token a host is likely to have styled already, and when it has, its own rule hides the editor's handle. The 52 headless assertions and the browser suites pass unchanged, the two tolerated false results (noId, noMsoClass) being exactly the two on master. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd --- generate-sef.sh | 3 + index.html | 6 +- src/annotate.xsl | 6 +- src/edit.xsl | 110 +++--- src/index.xsl | 2 + src/input.xsl | 24 +- src/ldh-blocks.xsl | 44 +-- src/navigate.xsl | 46 +-- src/overlay.xsl | 44 +-- src/select.xsl | 2 +- src/tables.xsl | 20 +- src/translations.xsl | 61 ++++ src/typeahead.xsl | 2 +- tests/browser/editor.mjs | 2 +- tests/browser/features.mjs | 2 +- tests/browser/multiinstance.mjs | 2 +- tests/browser/tables.mjs | 2 +- tests/fixture-blocks.html | 2 +- tests/fixture-dragnest.html | 2 +- tests/fixture-nesting.html | 2 +- tests/fixture.html | 4 +- tests/fixtures/08-rendering-skip.xhtml | 2 +- .../fixtures/canonical/01-chrome-strip.xhtml | 10 +- .../canonical/02-rendering-strip.xhtml | 2 +- .../08-editor-emission-roundtrip.xhtml | 2 +- .../canonical/23-ldh-block-placeholder.xhtml | 2 +- .../canonical/23-nested-chrome-strip.xhtml | 16 +- translations.rdf | 345 ++++++++++++++++++ 28 files changed, 589 insertions(+), 178 deletions(-) create mode 100644 src/translations.xsl create mode 100644 translations.rdf diff --git a/generate-sef.sh b/generate-sef.sh index 769e659..68436ef 100644 --- a/generate-sef.sh +++ b/generate-sef.sh @@ -36,3 +36,6 @@ fi mkdir -p dist/vocabs cp vocabs/*.rdf dist/vocabs/ echo "✓ Vocabularies copied to dist/vocabs/" + +cp translations.rdf dist/ +echo "✓ Translations copied to dist/" diff --git a/index.html b/index.html index c45d8bb..13a8fd3 100644 --- a/index.html +++ b/index.html @@ -9,9 +9,9 @@