makr.dk

Content Type: Text

Changes to how this Type behaves are requested through a GitHub Issue and implemented, together with this reference page, through the repository's normal workflow. See /_docs/posts for how Content Types, Roles, and Rank work in general, and docs/Internal/type-doc-templates.md for the Content Type Doc template this file follows.

A block of formatted (markdown) text — a paragraph, a bio, a footnote, a full article body. The most heavily used Content Type on the site: most Posts are built around one or more Text blocks.

Fields

  • Body (mandatory) — the markdown-formatted text itself, written in the admin's WYSIWYG editor and round-tripped to and from plain markdown. Fenced code blocks are treated as a protected, monospace region rather than formatted as rich text.
  • FormatMarkdown (the default, and every existing Text block) or HTML, an explicit mode for content that already exists as HTML and doesn't convert cleanly (e.g. content brought in from a historical import, or a third-party embed snippet). Content references ({{...}}) still resolve inside it either way; only the surrounding markdown-to-HTML conversion step is skipped. See "Safe rendering of HTML blocks," below, for how an HTML-format block is actually rendered.
  • Embed height (optional, HTML format only) — the sandboxed iframe's height in pixels. Left blank, the iframe uses a fixed default height; set this when the embedded content is taller or shorter than that default.
  • Metadata (optional) — a small set of descriptive fields (a label, description, creator/attribution, source, rights, and similar) that travel with the block but aren't rendered on the page itself — mainly useful for content brought in from elsewhere, to preserve facts about where it came from. See /_docs/json-import for the full field list.

Safe rendering of HTML blocks

An HTML-format block's Body is never injected directly into the surrounding page. Instead it renders inside a sandboxed <iframe> with its own opaque origin — the embedded content cannot read or modify the rest of the page, the visitor's cookies, or anything else on hoejriis.dk, even if it tries. Scripts, forms, and pop-ups inside the frame still work (useful for a genuine third-party embed like a widget or a form), but the frame starts inert: a visitor must explicitly click "Load embedded content" before it activates. Until then — and always, alongside it — the block's extracted plain text (the same text used for the block's own search indexing) and any external links the HTML references are shown directly on the page, so the block stays readable and its links stay reachable without ever needing to activate the frame. In the admin editor, an HTML-format block also shows which external domain(s) it references, so an admin can see at a glance what a block will contact before publishing it.

A footnote-role Text block (referenced elsewhere via {{footnote:N}}) is the one exception to the iframe treatment: a footnote is spliced inline into its referencing block's own text rather than rendered as a separate element, so an HTML-format footnote falls back to its extracted plain text instead — it is never sandboxed as an iframe, and its raw HTML is never rendered at all.

A static PDF/print snapshot of a Post (see /_docs/posts's "Static PDF export") always shows the extracted-text-and-links fallback in place of the interactive frame — there is no way to "activate" an embed in a static export.

An HTML-format block with genuinely no content (an empty Body) never shows the activation prompt at all — since there would be nothing to load, it shows a short, neutral "This embedded content isn't available" note instead, so an empty block never disappears silently.

Otherwise, no separate title or caption; a Text block is just its markdown (or HTML) content.

Semantic HTML and accessibility

Rendered markdown (via marked) into a <div>, using whatever native semantic elements the markdown itself maps to — paragraphs, headings, lists, <code>/<pre> for fenced code, <a> for links, <table> for a markdown table. No additional ARIA is added on top of what marked's own output already produces. Every authored heading level is shifted down by one before rendering — an authored # Heading becomes an <h2>, ## Heading becomes <h3>, and so on — so a Text block's own headings can never outrank the Post's own title (always an <h1>), while still nesting correctly among themselves. A {{map:role}} reference resolves to an inert placeholder <div> that's hydrated into a real Leaflet map after render (see client/src/lib/map.ts) — see /_docs/media's coverage of the interactive map itself for what accessibility that carries. An HTML-format block skips the marked conversion step entirely and instead renders via the sandboxed iframe described above — a visitor who never activates the frame, or a screen reader, still gets the block's extracted plain text and source links, which is why that fallback is always present rather than only shown on request.

Role, Rank, and Reference

A Post can hold several Text blocks at once — a short intro and a longer body, or a set of footnotes numbered by Rank — see /_docs/posts for what Role and Rank mean in general. Several Text blocks sharing the same Role (e.g. footnote) are distinguished by Rank, which also doubles as their reference number when linked to from elsewhere in the text (see Rendering contexts, below). Every Text block also has an optional Reference — a separate, Post-unique name for addressing it inline instead of by Role/Rank — see /_docs/posts's "Reference: inline addressing" for the full detail.

Editing

In the admin Post editor, the Texts section holds one block per Text element, each with a Role field, a Position (Rank) field when more than one Text block shares a Role, and the WYSIWYG markdown editor itself. Every Post Type's editor shows the same Texts section regardless of which Type is active — see /_docs/posts.

Rendering contexts

Inline

This is the one Content Type whose own content can reference other Content Elements inline, via {{role}} / {{kind:identifier}} syntax — e.g. {{cover}} embeds the Post's cover image right where the reference sits, {{footnote:3}} links down to footnote 3, {{map: route-start}} renders an embedded map. See /_docs/markdown for the full reference syntax and what each form does. A Text block itself is never embedded inline into another Text block — there's no {{text-role}} self-referential form.

Additional Information group

Text/Markdown and Free-form HTML never appear in Additional Information, in any form — no preview list, no full-content group, no placeholder. This is deliberate: a non-inline Text simply isn't presented anywhere outside its own standalone page (still reachable from the Post Metadata page) — its absence there is not treated as an empty state needing a fallback. A footnote-role Text is unaffected by this either way — it's fully accounted for by its inline {{footnote:n}} splice and trailing footnote list, whether or not it would otherwise have had anywhere else to appear.

Post metadata-page traversal

Every Text block the Post has ever held (current Version, or full history via /metadata/history) is enumerated with its raw markdown body as JSON-LD/native JSON — see /_docs/posts's Metadata page section. Content references inside it aren't re-resolved for this export; the raw markdown is what's carried.

Standalone Content Element page

/_element/text/:id renders the block's markdown as plain HTML (via marked, no content-reference resolution — a decontextualized page has no other elements of the same Post on hand to resolve {{...}} against), gated exactly like the owning Post's own page. An HTML-format block renders here the same way as everywhere else — via the sandboxed iframe, behind the same activation gate.