ihf-annotation-launcher.js: vanilla JS, no framework dependency. Scans DOM for data-widget-id elements, injects Annotate trigger, opens inline form, POSTs to /widgets/:widgetId/annotations. Works in React/Vue-rendered pages via MutationObserver. Feature-gated by IHP_ANNOTATION_LAUNCHER=true env var (Config.hs AnnotationLauncherEnabled, FrontController layout conditional). Docs: docs/annotation-launcher.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2.2 KiB
IHF Annotation Launcher
static/js/ihf-annotation-launcher.js is a self-contained vanilla JS module
that injects an Annotate button adjacent to every element that carries a
data-widget-id attribute.
It works in IHP server-rendered pages and in React/Vue pages where IHP does
not own the DOM — the launcher relies solely on the presence of data-widget-id,
not on any framework-specific structure.
Activation
Set the environment variable before starting the server:
IHP_ANNOTATION_LAUNCHER=true devenv up
This causes IHP to emit the following tag in every page's <head>:
<script src="/js/ihf-annotation-launcher.js"></script>
When IHP_ANNOTATION_LAUNCHER is absent or not "true", the script is not
loaded.
Data attributes
| Attribute | Required | Description |
|---|---|---|
data-widget-id |
Yes | UUID of the widget (from the widget registry) |
data-hub-id |
No | UUID of the hub — read from element or nearest ancestor |
data-view-context |
No | Logical UI location (informational) |
Usage in React
Because the launcher uses MutationObserver, it will pick up React-rendered
elements after mount:
function MyWidget({ widgetId, hubId }) {
return (
<div data-widget-id={widgetId} data-hub-id={hubId}>
<button>Do something</button>
</div>
);
}
No other integration is required. The launcher injects the Annotate button and
handles POST submission to /widgets/:widgetId/annotations.
Programmatic re-scan
If your SPA does client-side navigation without full page reloads, call:
window.IHFAnnotationLauncher.scan();
Submission
The launcher POSTs application/x-www-form-urlencoded to:
POST /widgets/:widgetId/annotations
Fields submitted: body, category, severity (fixed low), CSRF token.
Responses:
200or redirect → success (form closes with confirmation)- Any non-OK response → inline error message
CSRF
The launcher reads the CSRF token from <meta name="csrf-token" content="...">.
IHP emits this tag automatically in authenticated layouts.