Kotoba.Renderer (Kotoba v0.5.0)

Copy Markdown View Source

Renders a Kotoba.Document as HTML, as plain text and as Markdown.

to_html/2 returns safe iodata from Phoenix.HTML. Every string in the document is escaped, and Kotoba never passes raw HTML through. Before it renders a node, the renderer calls Kotoba.Sanitizer.check/3. A node that fails the check renders as an unknown node: <span class="kotoba-unknown" data-type="..."> with no content.

HTML of the built-in nodes

NodeHTML
paragraphp
headingh1 to h4 (h5 and h6 become h4)
quoteblockquote
listul, ol (with start when it is not 1), ul.kotoba-check
list itemli; in a check list li.kotoba-checked or li.kotoba-unchecked
codepre with code.language-<language>, the text escaped
textthe text in strong, em, s, u, code, sub, sup, mark (mark.kotoba-highlight-<name> for a highlight color), and span.kotoba-lowercase, span.kotoba-uppercase, span.kotoba-capitalize; a text color is a span.kotoba-color-<name> around it
line breakbr
horizontal rulehr
tabletable.kotoba-table in a div.kotoba-table-scroll, with a thead for a first row of header cells and a tbody
table rowtr
table celltd, or th with scope="col" (header row) or scope="row" (header column); colspan and rowspan when they are more than 1
link, autolinka with rel="noopener nofollow", or the text when the URL is not safe
attachmentfigure.kotoba-attachment with an img, an object (PDF), a video, or a download link, and a figcaption
gallerydiv.kotoba-gallery with the figure of each attachment
mentionspan.kotoba-mention with data-kind and data-id
taba tab character, escaped
unknownspan.kotoba-unknown with data-type

Options

The options of the render callbacks

The renderer gives the options above to each render callback of a node, with these changes:

  • :policy - the policy map from Kotoba.Sanitizer.policy/1.
  • :parent - the parent node, or nil for the root node.
  • :index - the position of the node among the children of its parent, or nil for the root node.

A node gives the same opts to html_children/2, text_children/2 and markdown_children/3.

Summary

Types

An attribute of an HTML tag. A nil or false value is left out.

Functions

Escapes the Markdown characters in a plain string, for a Kotoba.Node.render_markdown/2 callback.

Returns a URL for the destination of a Markdown link, for a Kotoba.Node.render_markdown/2 callback. \, &, < and > get a backslash, so that a CommonMark renderer decodes no entity, and a URL with spaces or parentheses is in angle brackets, as it is. Check the URL with Kotoba.Sanitizer.link_url/2 first.

Renders the children of an element node as safe HTML.

Renders the children of an element node as Markdown.

Renders each child of an element node as Markdown. Returns a list of {child, markdown} tuples, in order.

Returns the policy map of the render options. See Kotoba.Sanitizer.policy/1.

Returns an HTML tag as safe HTML.

Renders the children of an element node as plain text.

Renders each child of an element node as plain text. Returns a list of {child, text} tuples, in order.

Renders a document as safe HTML.

Renders a document as Markdown, as well as Markdown can show it.

Renders a document as plain text. Blocks are separated by "\n".

Returns the safe HTML of an unknown node of type.

Types

attribute()

@type attribute() :: {atom() | String.t(), String.t() | integer() | boolean() | nil}

An attribute of an HTML tag. A nil or false value is left out.

Functions

escape_markdown(text)

@spec escape_markdown(String.t()) :: String.t()

Escapes the Markdown characters in a plain string, for a Kotoba.Node.render_markdown/2 callback.

It escapes the inline syntax everywhere (`, *, _, [, ], ~, <, & and \), and the block syntax at the start of a line: # headings, > quotes, - and + bullets, 1. and 1) list markers, and --- or === lines. So a node that renders its text at the start of a block cannot make a heading or a list.

Examples

iex> Kotoba.Renderer.escape_markdown("*not* [a link]")
"\\*not\\* \\[a link\\]"

iex> Kotoba.Renderer.escape_markdown("# not a heading")
"\\# not a heading"

iex> Kotoba.Renderer.escape_markdown("1. not a list")
"1\\. not a list"

escape_markdown_url(url)

@spec escape_markdown_url(String.t()) :: String.t()

Returns a URL for the destination of a Markdown link, for a Kotoba.Node.render_markdown/2 callback. \, &, < and > get a backslash, so that a CommonMark renderer decodes no entity, and a URL with spaces or parentheses is in angle brackets, as it is. Check the URL with Kotoba.Sanitizer.link_url/2 first.

Examples

iex> Kotoba.Renderer.escape_markdown_url("/docs/a page (draft)")
"</docs/a page (draft)>"

iex> Kotoba.Renderer.escape_markdown_url("/search?q=a&b")
"/search?q=a\\&b"

html_children(node, opts)

@spec html_children(Kotoba.Node.t(), keyword()) :: Phoenix.HTML.safe()

Renders the children of an element node as safe HTML.

markdown_children(node, opts, separator \\ "\n\n")

@spec markdown_children(Kotoba.Node.t(), keyword(), String.t()) :: String.t()

Renders the children of an element node as Markdown.

Consecutive inline nodes are joined. The blocks are separated by separator (the default is a blank line). Empty blocks are left out.

markdown_each(node, opts)

@spec markdown_each(Kotoba.Node.t(), keyword()) :: [{Kotoba.Node.t(), String.t()}]

Renders each child of an element node as Markdown. Returns a list of {child, markdown} tuples, in order.

policy(opts)

@spec policy(keyword()) :: Kotoba.Sanitizer.policy()

Returns the policy map of the render options. See Kotoba.Sanitizer.policy/1.

tag(name, attrs, content)

@spec tag(String.t(), [attribute()], Phoenix.HTML.safe() | String.t() | :void) ::
  Phoenix.HTML.safe()

Returns an HTML tag as safe HTML.

The attribute values and a string content are escaped. content can also be safe HTML. A nil or false attribute is left out, and a true attribute has no value. When content is :void, the tag has no end tag.

Examples

iex> Kotoba.Renderer.tag("a", [href: "/x?a=1&b=2", title: nil], "A & B") |> Phoenix.HTML.safe_to_string()
~s(<a href="/x?a=1&amp;b=2">A &amp; B</a>)

iex> Kotoba.Renderer.tag("br", [], :void) |> Phoenix.HTML.safe_to_string()
"<br>"

text_children(node, opts)

@spec text_children(Kotoba.Node.t(), keyword()) :: String.t()

Renders the children of an element node as plain text.

Consecutive inline nodes are joined. Each block child gives one line, and the lines are separated by "\n". A decorator in the root node is a block; it gives no line when it has no text.

text_each(node, opts)

@spec text_each(Kotoba.Node.t(), keyword()) :: [{Kotoba.Node.t(), String.t()}]

Renders each child of an element node as plain text. Returns a list of {child, text} tuples, in order.

to_html(document, opts \\ [])

@spec to_html(Kotoba.Document.t(), keyword()) :: Phoenix.HTML.safe()

Renders a document as safe HTML.

Examples

iex> {:ok, doc} =
...>   Kotoba.Document.parse(%{
...>     "kotoba" => 1,
...>     "lexical" => "0.51",
...>     "root" => %{
...>       "type" => "root",
...>       "children" => [
...>         %{"type" => "paragraph", "children" => [%{"type" => "text", "text" => "<b>hi</b>"}]}
...>       ]
...>     }
...>   })
iex> doc |> Kotoba.Renderer.to_html() |> Phoenix.HTML.safe_to_string()
"<p>&lt;b&gt;hi&lt;/b&gt;</p>"

to_markdown(document, opts \\ [])

@spec to_markdown(Kotoba.Document.t(), keyword()) :: String.t()

Renders a document as Markdown, as well as Markdown can show it.

Headings, lists, code blocks, bold, italic, strikethrough, inline code, links and images become Markdown. The other nodes and formats give their plain text. Blocks are separated by a blank line.

to_text(document, opts \\ [])

@spec to_text(Kotoba.Document.t(), keyword()) :: String.t()

Renders a document as plain text. Blocks are separated by "\n".

unknown_html(type)

@spec unknown_html(String.t()) :: Phoenix.HTML.safe()

Returns the safe HTML of an unknown node of type.