HTML Rendering¶
Two classes turn a Viper document into HTML. DocumentNode walks a document as a
typed tree, carrying the metadata a renderer needs — component name, value,
editability, and the concrete type behind each leaf. Html renders, either the whole
tree in one call or one piece at a time.
When to use: reach for Html when the default rendering will do, and
for DocumentNode directly when the markup is yours — a form, a custom
layout, a template engine’s data. Nothing here is browser-specific: the same tree
feeds a server-rendered page, and the Qt widgets do the same thing with it.
Quick Start¶
An Express route rendering one document as a collapsible tree:
const express = require('express');
const { CommitDatabase, CommitStateBuilder, DocumentNode, Html, ValueKey } =
require('@digitalsubstrate/dsviper');
const app = express();
app.get('/document/:instanceId', (req, res) => {
const db = CommitDatabase.open('model.cdb');
try {
const key = ValueKey.create(concept, ValueUUId.create(req.params.instanceId));
const getting = CommitStateBuilder.state(db, db.lastCommitId()).attachmentGetting();
// Build the document tree for every attachment on that key.
const nodes = DocumentNode.createDocuments(key, getting);
res.send(Html.document('Document', Html.style(),
Html.body(Html.documentsDetails(nodes, true))));
} finally { db.close(); }
});
Html.style() returns the stylesheet the other helpers assume, Html.body() wraps
content, and Html.document() assembles a standalone page — so a working page needs
no CSS of its own.
Walking the tree yourself¶
DocumentNode answers what a renderer needs to decide, so a custom renderer is a
recursion over predicates:
function renderNode(node, level = 0) {
if (node.isExpandable()) {
const children = node.children().map((c) => renderNode(c, level + 1)).join('');
return `<details open><summary>${node.stringComponent()}</summary>${children}</details>`;
}
if (node.isEditable()) {
if (node.isBoolean()) return checkbox(node);
if (node.isEnumeration()) return select(node);
if (node.isString()) return textInput(node);
}
return `<div>${node.stringComponent()} = ${node.stringValue()}</div>`;
}
The predicate family is wide — isPrimitive, isCollection, isKey, isNumeric
and the exact-width isInt32 / isUint64 / isFloat … — so a renderer can be as
coarse or as precise as it needs. Html.type(node.value().type()) renders the type
itself when a column should show it.
See also
dsviper-node-web-cdbe is a complete worked example: an Express Commit Database
Editor, pure HTML5 with no client JavaScript, built on exactly these two classes.
Its Python twin dsviper-web-cdbe renders the same tree through Flask.
Key classes¶
Class |
Purpose |
Example |
|---|---|---|
One node of a document seen as a tree |
||
Renders Viper data as HTML |
The mirror of this page for the Python binding is HTML Rendering.
Classes¶
Class |
Description |
|---|---|
One node of a document seen as a tree |
|
Renders Viper data as HTML, in two stages |
Reference¶
- class DocumentNode()¶
One node of a document seen as a tree.
Carries its component name, its value, its type, and what a renderer needs to decide: editable, expandable, and which concrete type it holds.
Note: Not directly instantiable.
exported from
index.d- DocumentNode.attachment()¶
Return the attachment the document belongs to.
- Returns:
Attachment
- DocumentNode.children()¶
Return the nodes one level below this one.
- Returns:
DocumentNode[]
- DocumentNode.document()¶
- Return the whole document this node is part of: the Value stored under the key,
from which the tree was built.
- Returns:
Value
- DocumentNode.isBlobId()¶
Return true if the node holds a blobId.
- Returns:
boolean
- DocumentNode.isBoolean()¶
Return true if the node holds a boolean.
- Returns:
boolean
- DocumentNode.isCollection()¶
Return true if the node holds a collection.
A vector, a map, a set, an optional, an xarray or an any.
Every collection is also a container. A structure, a vec, a mat, a tuple, a map entry and a variant are containers that are not collections.
- Returns:
boolean
- DocumentNode.isContainer()¶
Return true if the node stands for a value that holds other nodes.
Every kind but a primitive, an enumeration and a key: a structure, a vec, a mat, a tuple, a vector, a set, a map and its entries, an optional, an xarray, an any and a variant. Its value() is that container, and stringValue() summarises it.
- Returns:
boolean
- DocumentNode.isDouble()¶
Return true if the node holds a double.
- Returns:
boolean
- DocumentNode.isEditable()¶
- Return true if the node carries a value a UI may write - not a container, and not
read-only.
- Returns:
boolean
- DocumentNode.isEnumeration()¶
Return true if the node holds an enumeration.
- Returns:
boolean
- DocumentNode.isExpandable()¶
Return true if the node has children to unfold.
- Returns:
boolean
- DocumentNode.isFloat()¶
Return true if the node holds a float.
- Returns:
boolean
- DocumentNode.isInt16()¶
Return true if the node holds an int16.
- Returns:
boolean
- DocumentNode.isInt32()¶
Return true if the node holds an int32.
- Returns:
boolean
- DocumentNode.isInt64()¶
Return true if the node holds an int64.
- Returns:
boolean
- DocumentNode.isInt8()¶
Return true if the node holds an int8.
- Returns:
boolean
- DocumentNode.isInteger()¶
Return true if the node holds an integer.
- Returns:
boolean
- DocumentNode.isKey()¶
- Return true if the node holds a ValueKey - the type, not the key this document is
filed under.
- Returns:
boolean
- DocumentNode.isNumeric()¶
Return true if the node holds a number.
- Returns:
boolean
- DocumentNode.isPrimitive()¶
Return true if the node’s kind is ‘Primitive’.
A boolean, a number, a string, a uuid, a blob id, a commit id or a blob.
An enumeration and a key are kinds of their own: they answer false here and false to isContainer() too - isEnumeration() and isKey() name them.
- Returns:
boolean
- DocumentNode.isReadonly()¶
Return true if the node refuses a write.
isEditable() is the one a UI binds to: a value a UI may write - not a container, and not read-only.
- Returns:
boolean
- DocumentNode.isReal()¶
Return true if the node holds a real.
- Returns:
boolean
- DocumentNode.isString()¶
Return true if the node holds a string.
- Returns:
boolean
- DocumentNode.isUint16()¶
Return true if the node holds a uint16.
- Returns:
boolean
- DocumentNode.isUint32()¶
Return true if the node holds a uint32.
- Returns:
boolean
- DocumentNode.isUint64()¶
Return true if the node holds a uint64.
- Returns:
boolean
- DocumentNode.isUint8()¶
Return true if the node holds a uint8.
- Returns:
boolean
- DocumentNode.isUuid()¶
Return true if the node holds a uuid.
- Returns:
boolean
- DocumentNode.key()¶
Return the ValueKey the document this node is part of is filed under.
- Returns:
ValueKey
- DocumentNode.parent()¶
Return the parent, or undefined at the root of a document.
- Returns:
DocumentNode | undefined
- DocumentNode.path()¶
Return the Path from the document root down to this node.
- Returns:
PathConst
- DocumentNode.stringComponent()¶
- Return the label for the node itself: a field name, an index, a map key, or,
at the root, the identifier of the attachment the document is filed under. An element of a set has no label and answers ‘-‘.
- Returns:
string
- DocumentNode.stringComponentTooltip()¶
Return the tooltip for the component label: the type representation.
- Returns:
string
- DocumentNode.stringPath()¶
Return the path, rendered for display.
- Returns:
string
- DocumentNode.stringType()¶
Return the type of the value, rendered for display.
- Returns:
string
- DocumentNode.stringValue()¶
Return the value rendered for display.
A vector, a map or an xarray answers its size (‘2 elements’, ‘1 entry’), an optional or an any whether it holds a value and of which type, a vec, a mat, a tuple or a map entry its representation. A structure answers its representation when its fields are all booleans or numbers, and ‘-’ otherwise; a set answers ‘-‘.
- Returns:
string
- DocumentNode.stringValueTooltip()¶
Return the tooltip for the value label.
The element type below a vec, a mat, a vector, a set or a map; the key type and the element type for the key and the value of a map entry; the detailed type for a key. Anywhere else, the same text as stringPath().
- Returns:
string
- DocumentNode.type()¶
Return the kind of node.
One of ‘Primitive’, ‘Vec’, ‘Mat’, ‘Tuple’, ‘Optional’, ‘Vector’, ‘Set’, ‘Map’, ‘MapEntry’, ‘XArray’, ‘Any’, ‘Variant’, ‘Enumeration’, ‘Structure’ or ‘Key’.
Not the type of the value, which is stringType().
- Returns:
string
- DocumentNode.uuid()¶
Return the uuid identifying this node in the tree.
- Returns:
ValueUUId
- DocumentNode.value()¶
Return the Value this node stands for.
- Returns:
Value
- static DocumentNode.createDocuments(key, attachmentGetting)¶
Return the root DocumentNode of each document filed under key.
- Arguments:
key (ValueKey)
attachmentGetting (AttachmentGetting)
- Returns:
DocumentNode[]
- class Html()¶
Renders Viper data as HTML, in two stages. Every method is static.
The renderers return a FRAGMENT, not a page: value(), valuePretty(), type(), dsmDefinitions() and documentsDetails() each answer a run of markup carrying CSS class names.
The assemblers wrap one into a page: style() answers a <style> element defining those classes, body() wraps a fragment in a <body>, and document(title, style, body) takes what those two answered and returns a complete page - Html.document(t, Html.style(), Html.body(content)).
Every string a value or a declaration carries is HTML-escaped on the way out, so stored text cannot reach the page as markup.
Note: Not directly instantiable.
exported from
index.d- static Html.body(content)¶
Wrap a rendered fragment in a <body> element, for document().
content is inserted as it is, not escaped: pass a fragment a renderer answered.
- Arguments:
content (string)
- Returns:
string
- static Html.document(title, style, body)¶
Return a complete HTML page.
title is HTML-escaped. style and body are what style() and body() answered; they are inserted as they are, not wrapped or escaped again.
- Arguments:
title (string)
style (string)
body (string)
- Returns:
string
- static Html.documentsDetails(documents, showType)¶
- Return the document trees - the roots DocumentNode.createDocuments() answered -
as nested markup: a node holding others is a <details> the reader opens, and a leaf is a <div> row.
With showType, each row carries its element type.
- Arguments:
documents (DocumentNode[])
showType (boolean | null)
- Returns:
string
- static Html.dsmDefinitions(definitions, showDocumentation, showRuntimeId)¶
Return the HTML representation of the DSMDefinitions.
- Arguments:
definitions (DSMDefinitions)
showDocumentation (boolean | null)
showRuntimeId (boolean | null)
- Returns:
string
- static Html.style()¶
Return a <style> element defining the CSS classes the renderers emit.
Pass it to document(), or substitute your own sheet defining the same classes.
- Returns:
string
- static Html.type(type)¶
Return the representation of the type in HTML.
- Arguments:
type (Type)
- Returns:
string
- static Html.value(value, useDescription)¶
Return the representation of the value in HTML.
- Arguments:
value (Value)
useDescription (boolean | null)
- Returns:
string
- static Html.valuePretty(value, showType)¶
Return the value as a nested, indented block, one element per line.
value() answers the same content inline, on one run. With showType, each line carries its element type.
- Arguments:
value (Value)
showType (boolean | null)
- Returns:
string