Browse Source

feat: generate links from cross-ref markers

main
Inhji Y. 9 months ago
parent
commit
3e08ead7d7
  1. 31
      lib/mirage/markdown.ex
  2. 4
      lib/mirage/notes.ex
  3. 21
      test/mirage/notes_test.exs
  4. 2
      test/mirage_web/controllers/note_controller_test.exs

31
lib/mirage/markdown.ex

@ -1,15 +1,38 @@
defmodule Mirage.Markdown do
import Phoenix.HTML.Link, only: [link: 2]
import Phoenix.HTML, only: [raw: 1, safe_to_string: 1]
import Ecto.Changeset, only: [get_change: 2, put_change: 3]
def maybe_render_markdown(changeset, markdown_field, html_field) do
if markdown = get_change(changeset, markdown_field) do
html = Earmark.as_html!(markdown, %Earmark.Options{
code_class_prefix: "lang- language-"
})
html = render(markdown)
put_change(changeset, html_field, html)
else
changeset
end
end
end
@crossref_regex ~r/\[\[(?<id>\d+)\]\]/
def render(markdown) do
options = %Earmark.Options{
code_class_prefix: "lang- language-"
}
@crossref_regex
|> Regex.scan(markdown, capture: :all_but_first)
|> List.flatten()
|> Enum.reduce(markdown, fn note_id, markdown ->
case Mirage.Notes.get_note(note_id) do
nil ->
markdown
note ->
a_element = link(note.title, to: "/notes/#{note.id}") |> safe_to_string()
String.replace(markdown, "[[#{note_id}]]", a_element)
end
end)
|> Earmark.as_html!(options)
end
end

4
lib/mirage/notes.ex

@ -6,7 +6,7 @@ defmodule Mirage.Notes do
import Ecto.Query, warn: false
alias Mirage.Repo
alias Mirage.Notes.{Note, Topic, Tags}
alias Mirage.Notes.{Note, Topic}
@note_preloads [:links, :topics]
@ -43,6 +43,8 @@ defmodule Mirage.Notes do
"""
def get_note!(id), do: Repo.get!(Note, id)
def get_note(id), do: Repo.get(Note, id)
def preload_note(note), do: Repo.preload(note, @note_preloads)
@doc """

21
test/mirage/notes_test.exs

@ -8,6 +8,9 @@ defmodule Mirage.NotesTest do
@valid_attrs %{content: "some content", title: "some title"}
@update_attrs %{content: "some updated content"}
@update_attrs_with_link %{
content: "some updated content with a reference [[@OWN_ID]] [[@NOTE_ID]]"
}
@invalid_attrs %{content: nil}
def note_fixture(attrs \\ %{}) do
@ -46,6 +49,24 @@ defmodule Mirage.NotesTest do
assert note.content == "some updated content"
end
test "update_note/2 with a cross-ref link renders a link to the referenced note" do
note = note_fixture()
attrs =
Map.update!(@update_attrs_with_link, :content, fn content ->
content
|> String.replace("@OWN_ID", to_string(note.id))
|> String.replace("@NOTE_ID", to_string(note.id + 1))
end)
assert {:ok, %Note{} = note} = Notes.update_note(note, attrs)
assert note.content ==
"some updated content with a reference [[#{note.id}]] [[#{note.id + 1}]]"
assert note.content_html =~ "#{note.title}"
end
test "update_note/2 with invalid data returns error changeset" do
note = note_fixture()
assert {:error, %Ecto.Changeset{}} = Notes.update_note(note, @invalid_attrs)

2
test/mirage_web/controllers/note_controller_test.exs

@ -65,7 +65,7 @@ defmodule MirageWeb.NoteControllerTest do
conn = get(conn, Routes.note_path(conn, :show, note))
assert html_response(conn, 200) =~ "some updated content"
assert html_response(conn, 200) =~ "some other tag"
refute html_response(conn, 200) =~ "some tag"
refute html_response(conn, 200) =~ "some tag"
end
test "renders errors when data is invalid", %{conn: conn, note: note} do

Loading…
Cancel
Save