chiya/lib/chiya_web/markdown.ex

63 lines
1.5 KiB
Elixir
Raw Permalink Normal View History

2023-03-13 03:26:39 +01:00
defmodule ChiyaWeb.Markdown do
2023-07-04 22:46:00 +02:00
@moduledoc """
Module used for rendering markdown.
2023-03-13 03:26:39 +01:00
2023-07-04 22:46:00 +02:00
Rendering also collects and replaces internal [references](`Mirage.References`) to other entities like Lists and Tags.
"""
import Ecto.Changeset, only: [get_change: 2, put_change: 3]
2023-07-05 06:49:37 +02:00
def options(),
do: %Earmark.Options{
2023-07-04 22:46:00 +02:00
code_class_prefix: "lang- language-",
footnotes: true,
breaks: true,
escape: false,
registered_processors: processors()
}
@doc """
Renders markdown with Earmark.
"""
2023-03-31 16:58:10 +02:00
def render(markdown) do
markdown
2023-07-04 22:46:00 +02:00
|> ChiyaWeb.References.replace_references()
|> Earmark.as_html!(options())
end
@doc """
Renders markdown to HTML inside a changeset if markdown changed.
Markdown field and HTML field can be configured.
"""
def maybe_render(changeset, markdown_field, html_field) do
if markdown = get_change(changeset, markdown_field) do
html = render(markdown)
put_change(changeset, html_field, html)
else
changeset
end
end
def processors() do
heading = fn
{_, _, [content], _} = n when is_binary(content) ->
slug = Slugger.slugify_downcase(content)
Earmark.AstTools.merge_atts_in_node(n, id: slug)
node ->
node
end
[
Earmark.TagSpecificProcessors.new([
{"h1", heading},
{"h2", heading},
{"h3", heading},
{"h4", heading},
{"h5", heading},
{"h6", heading}
])
]
2023-03-31 16:58:10 +02:00
end
2023-03-13 03:26:39 +01:00
end