- JavaScript 63.7%
- Nix 21.5%
- CSS 8.9%
- HTML 5.9%
Federated Wiki - Topicmap Plugin (dm6-elm AppEmbed)
This plugin renders a Federated Wiki topicmap inline and reuses dm6-elm's AppEmbed.
It loads an Elm bundle into the page and mounts window.Elm.AppEmbed inside the plugin viewport.
dm6-elm's public/cold-boot.html remains the reference harness in dm6-elm, and is not used directly by this plugin.
Quick Start (integration-first)
- Build and install the plugin into a local wiki:
cd ~/workspace/wiki-plugin-topicmap
npm pack -s
cd ~/workspace/wiki/node_modules/wiki
npm i $(npm pack ../../../wiki-plugin-topicmap | tail -1)
- Add a
topicmapitem to a page, and configure the Elm bundle in the item text:
ELM_BUNDLE /assets/dm6-elm/app.js
# Optional:
# ELM_BUNDLE_DEBUG /assets/dm6-elm/app.debug.js
# DEBUG true
# HEIGHT 480
# THEME auto
- Ensure the bundle exports
window.Elm.AppEmbed.
Runtime Contract (authoritative)
The plugin always boots window.Elm.AppEmbed and passes flags shaped like:
{ slug: String, stored: String }
stored is a JSON string. If the page data is unavailable, the plugin sends "{}" by default.
Exact boot behavior from client/topicmap.js:
slugcomes from the closest.pageelement, in order:data-slugidwith apage_prefix removed- the last segment of
location.pathname - the literal fallback
"empty"
storedis built fromwiki.getData()when available; otherwise it uses"{}":- if
wiki.getData()returnsnull/undefinedor throws, the plugin sends"{}" - otherwise it sends
JSON.stringify(pageData)
- if
Elm Bundle Loading
The plugin loads an Elm bundle by inserting a script tag and then calling:
window.Elm.AppEmbed.init({ node: viewport, flags })
Item text options control the bundle path (these are parsed by client/topicmap.js):
ELM_BUNDLE(default:/assets/dm6-elm/app.js)ELM_BUNDLE_DEBUG(optional; used whenDEBUG true)DEBUG(true/false) selects which bundle to loadINLINEis accepted for forward compatibility but ignored today (inline-only build)AMBIENT(true/false) enables Ambient input mode (default: false)AMBIENT_EXCLUDES(comma-separated selectors) to exclude in Ambient mode
Your bundle must export Elm.AppEmbed on window. If it does not, the plugin fails with:
Elm module not found: Elm.AppEmbed.
Conceptual Alignment: Topics vs Boxes (dm6-elm)
In dm6-elm terms:
- Topics store content.
- Boxes store topics or other boxes.
boxIdis the active container.- Only boxes can be fullscreen or act as drop targets.
The plugin aligns with these ideas by treating the current page as a container context
and sending the page's data (stored) to AppEmbed for reconciliation.
Input Modes (Scoped and Ambient)
The client/topicmap-input-modes.js module defines explicit input modes for routing pointer,
wheel, and key events to Elm:
- Scoped (default): only events that originate inside the topicmap viewport are forwarded.
- Ambient (opt-in): page-level listeners are enabled, but with guard rails.
- Enable with
AMBIENT truein the item text (default is false). - Add selector exclusions with
AMBIENT_EXCLUDES .selector1,.selector2.
- Enable with
Ambient mode behavior:
- Shows a badge in the viewport: "Ambient ON — press Esc to return to Scoped".
- Pressing
Escexits Ambient and returns to Scoped. - A click on the badge also returns to Scoped.
- Events are ignored when the target matches excluded selectors.
Exclusions include built-ins plus your own selectors:
- Built-ins:
input,textarea,select,[contenteditable=""],[contenteditable="true"],.page,.editor - Custom: pass
excludes: []when creating the controller
Input events are currently logged via console.debug until Elm-side ports are defined.
Troubleshooting
- Missing module error:
- Verify the bundle is loaded and that
window.Elm.AppEmbedexists. - Run in the console:
window.Elm && window.Elm.AppEmbed && typeof window.Elm.AppEmbed.init === 'function'
- Verify the bundle is loaded and that
- Flags decode failures:
- Ensure
flags.slugandflags.storedare strings and that Elm decoders accept them.
- Ensure
- Stored JSON not parseable:
- The plugin always sends a string. Confirm
storedcontains valid JSON and that your decoder treats it as a JSON string (default is"{}").
- The plugin always sends a string. Confirm
- Bundle path not loading:
- Confirm
ELM_BUNDLEis correct and the file is accessible at that URL.
- Confirm
Note: Debug mode requires a stable DOM; the plugin may auto-fallback to the non-debug bundle during refresh/rebind if the viewport is not connected.
Smoke Test (real wiki page)
This is a minimal end-to-end check in a real wiki page with the current plugin.
- Install the plugin and load a wiki page that includes a
topicmapitem. - Set item text to ensure debug mode and the bundle path:
ELM_BUNDLE /assets/dm6-elm/app.js
DEBUG true
- Open DevTools console and verify boot logs show flags:
- Look for
[topicmap] Elm inline bootedand confirmslug/stored.
- Look for
- Click inside the viewport and observe input logs:
- Look for
[topicmap] inputentries (scoped by default).
- Look for
TODO: add a minimal demo page under docs/ or public/ once one of those
directories exists in this repo.
License
MIT