The document: a tree of nodes stored as plain JSON (a jsonb column).
%{
"version" => 1,
"root" => %{
"id" => "Wq0m2Lx9Ka",
"type" => "root",
"props" => %{},
"style" => %{},
"attrs" => %{"css" => "selector { padding: 8px }"},
"children" => [
%{
"id" => "b3Rt9Lm1Qe",
"type" => "heading",
"props" => %{"text" => "Hello", "level" => "h2"},
"style" => %{"desktop" => %{"color" => "var(--color-primary)"}, "mobile" => %{"font-size" => "28px"}},
"attrs" => %{"class" => "tracking-tight", "hide_on" => ["mobile"]},
"children" => []
}
]
}
}Every node has:
"id"- stable id (ElementorexCms.Id)"type"- the block type (ElementorexCms.Registry)"props"- content of the block, as declared by its props"style"- declarations per state:"desktop","tablet","mobile"and"hover"(seeElementorexCms.Style)"attrs"- Advanced settings:"id","class","hide_on","css","animation","animation_delay"and"label"(name in the tree)"children"- child nodes (containers only)
The functions here are pure: they take a document and return a new one.
Tree operations validate what they are asked (a node cannot go inside itself,
only containers take children, the root cannot be removed) and return
{:error, reason} otherwise.
Summary
Functions
Entrance animations of the Advanced tab.
Removes every style of a node (all states).
Number of nodes, the root included.
Devices of the responsive styles.
Copies the node id (with new ids for it and its children) right after it.
Returns the document and the id of the copy.
Whether the document has no content.
Like get/2, as {:ok, node} or {:error, :not_found}.
Decodes and normalizes a JSON document (an invalid one gives new/0).
The node with id, or nil.
Inserts node in the container parent_id at index (clamped to the
children list). Checks that the parent takes that kind of child and the
document limits.
Limits applied by normalize/2: %{nodes: 2000, depth: 24}.
Moves the node id into parent_id at index. The index is counted in the
target's current children (the node itself included when it already is
there), which is what the editor's drop indicator shows.
An empty document, optionally with root children.
A new node of type. props are stored as given (string keys); pass
registry: to fill in the defaults of the block and its default children.
Every node, depth first, the root included.
Makes any map a valid document for registry: fills missing keys, casts and
sanitizes props with the definitions of each block, keeps only valid styles
and Advanced attributes, drops children of non-containers, gives new ids to
invalid or repeated ones and enforces the limits (limits/0).
Keeps only valid Advanced attributes.
Keeps only valid states and declarations of a style map.
The parent of the node with id and the node's index in it.
Nodes from the root down to the node with id (both included), or [] if
it does not exist.
Sets an Advanced attribute of a node (validated with normalize_attrs/1;
an invalid value removes the attribute).
Sets a prop of a node (the value is stored as given; cast it first).
Sets (or with nil/"" removes) a style declaration of a node for a state
("desktop", "tablet", "mobile" or "hover"). Invalid values are
rejected with {:error, :invalid}.
A copy of a node (or of a whole document) with new ids everywhere.
Removes the node id and its children. The root cannot be removed.
The root node.
Style states a node can have (desktop, tablet, mobile, hover).
Encodes a document as JSON.
Applies fun to the node with id. The id and type cannot change.
Current version of the document format.
Whether id is ancestor_id or one of its descendants.
Types
Functions
Entrance animations of the Advanced tab.
Removes every style of a node (all states).
@spec count(t() | tree_node()) :: non_neg_integer()
Number of nodes, the root included.
Devices of the responsive styles.
@spec duplicate(t(), String.t(), ElementorexCms.Registry.t() | nil) :: {:ok, t(), String.t()} | {:error, atom()}
Copies the node id (with new ids for it and its children) right after it.
Returns the document and the id of the copy.
Whether the document has no content.
Like get/2, as {:ok, node} or {:error, :not_found}.
@spec from_json(String.t(), ElementorexCms.Registry.t() | nil) :: t()
Decodes and normalizes a JSON document (an invalid one gives new/0).
The node with id, or nil.
@spec insert( t(), tree_node(), String.t(), integer(), ElementorexCms.Registry.t() | nil ) :: {:ok, t()} | {:error, atom()}
Inserts node in the container parent_id at index (clamped to the
children list). Checks that the parent takes that kind of child and the
document limits.
Limits applied by normalize/2: %{nodes: 2000, depth: 24}.
@spec move(t(), String.t(), String.t(), integer(), ElementorexCms.Registry.t() | nil) :: {:ok, t()} | {:error, atom()}
Moves the node id into parent_id at index. The index is counted in the
target's current children (the node itself included when it already is
there), which is what the editor's drop indicator shows.
An empty document, optionally with root children.
A new node of type. props are stored as given (string keys); pass
registry: to fill in the defaults of the block and its default children.
Options: :children, :style, :attrs, :id, :registry.
Every node, depth first, the root included.
@spec normalize(term(), ElementorexCms.Registry.t() | nil) :: t()
Makes any map a valid document for registry: fills missing keys, casts and
sanitizes props with the definitions of each block, keeps only valid styles
and Advanced attributes, drops children of non-containers, gives new ids to
invalid or repeated ones and enforces the limits (limits/0).
Nodes of unknown types are kept as they are (they render nothing), so a document never loses content because a block was removed from the registry.
Run it on everything that comes from outside: stored JSON, imports, the editor's events.
Keeps only valid Advanced attributes.
Keeps only valid states and declarations of a style map.
@spec parent(t(), String.t()) :: {:ok, tree_node(), non_neg_integer()} | :error
The parent of the node with id and the node's index in it.
Nodes from the root down to the node with id (both included), or [] if
it does not exist.
Sets an Advanced attribute of a node (validated with normalize_attrs/1;
an invalid value removes the attribute).
Sets a prop of a node (the value is stored as given; cast it first).
@spec put_style(t(), String.t(), String.t(), String.t(), term()) :: {:ok, t()} | {:error, :not_found | :invalid}
Sets (or with nil/"" removes) a style declaration of a node for a state
("desktop", "tablet", "mobile" or "hover"). Invalid values are
rejected with {:error, :invalid}.
A copy of a node (or of a whole document) with new ids everywhere.
Removes the node id and its children. The root cannot be removed.
The root node.
Style states a node can have (desktop, tablet, mobile, hover).
Encodes a document as JSON.
Applies fun to the node with id. The id and type cannot change.
Current version of the document format.
Whether id is ancestor_id or one of its descendants.