defmodule ContentfulRenderer do require Logger @doc """ Renders a Contentful node, in a tree of `Map`s and `List`s, to HTML. It accepts custom renderers for each node type, passed in as `Keyword`s in the `options` parameter. To override the `heading-1` renderer, pass in: ``` heading_1_node_renderer: fn node, options -> "
Paragraph 1
Paragraph 2
" ``` """ def render(node, options \\ []) def render(content, options) when is_list(content) do content |> Enum.map(&render(&1, options)) |> Enum.join("") end def render(%{nodeType: nodeType} = node, options) do renderer = case nodeType do "document" -> &render_content/2 "paragraph" -> Keyword.get(options, :paragraph_node_renderer, &default_paragraph_node_renderer/2) "text" -> Keyword.get(options, :text_node_renderer, &default_text_node_renderer/2) "heading-1" -> Keyword.get(options, :heading_1_node_renderer, &default_heading_1_node_renderer/2) "heading-2" -> Keyword.get(options, :heading_2_node_renderer, &default_heading_2_node_renderer/2) "heading-3" -> Keyword.get(options, :heading_3_node_renderer, &default_heading_3_node_renderer/2) "heading-4" -> Keyword.get(options, :heading_4_node_renderer, &default_heading_4_node_renderer/2) "heading-5" -> Keyword.get(options, :heading_5_node_renderer, &default_heading_5_node_renderer/2) "heading-6" -> Keyword.get(options, :heading_6_node_renderer, &default_heading_6_node_renderer/2) "unordered-list" -> Keyword.get( options, :unordered_list_node_renderer, &default_unordered_list_node_renderer/2 ) "ordered-list" -> Keyword.get( options, :ordered_list_node_renderer, &default_ordered_list_node_renderer/2 ) "list-item" -> Keyword.get( options, :list_item_node_renderer, &default_list_item_node_renderer/2 ) "hyperlink" -> Keyword.get(options, :hyperlink_node_renderer, &default_hyperlink_node_renderer/2) "embedded-entry-inline" -> Keyword.get( options, :embedded_entry_inline_node_renderer, &default_embedded_entry_inline_node_renderer/2 ) "embedded-entry-block" -> Keyword.get( options, :embedded_entry_block_node_renderer, &default_embedded_entry_block_node_renderer/2 ) end renderer.(node, options) end @doc """ Renders the content inside a node. Useful if you've overriden a renderer, but you don't want to replement how the renderer walks into the content. """ def render_content(node, options \\ []) do node |> Map.get(:content, []) |> render(options) end defp default_paragraph_node_renderer(node, options) do "#{render_content(node, options)}
" end defp default_heading_1_node_renderer(node, options) do "#{text}"
end
defp default_italic_mark_renderer(text, _options) do
"#{text}"
end
defp render_marks(marks, text, options) do
marks
|> Enum.reduce(
text,
fn mark, text_acc ->
type = Map.fetch!(mark, :type)
case type do
"bold" ->
default_bold_mark_renderer(text_acc, options)
"underline" ->
default_underline_mark_renderer(text_acc, options)
"code" ->
default_code_mark_renderer(text_acc, options)
"italic" ->
default_italic_mark_renderer(text_acc, options)
end
end
)
end
end