philomena/lib/philomena_web/textile_renderer.ex

135 lines
3.3 KiB
Elixir
Raw Normal View History

2020-05-08 04:19:08 +02:00
defmodule PhilomenaWeb.TextileRenderer do
alias Philomena.Textile.Parser
2019-11-11 00:35:52 +01:00
alias Philomena.Images.Image
alias Philomena.Repo
import Phoenix.HTML
import Phoenix.HTML.Link
import Ecto.Query
# Kill bogus compile time dependency on ImageView
@image_view Module.concat(["PhilomenaWeb.ImageView"])
def render(text, conn) do
opts = %{image_transform: &Camo.Image.image_url/1}
parsed = Parser.parse(opts, text)
images =
parsed
|> Enum.flat_map(fn
{:text, text} ->
[text]
_ ->
[]
end)
|> find_images
parsed
|> Enum.map(fn
{:text, text} ->
text
|> replacement_entities()
|> replacement_images(conn, images)
{_k, markup} ->
markup
end)
|> Enum.join()
2019-11-11 00:35:52 +01:00
end
defp replacement_entities(t) do
t
|> String.replace("->", "→")
|> String.replace("--", "—")
|> String.replace("...", "…")
|> String.replace(~r|(\s)-(\s)|, "\\1—\\2")
|> String.replace("(tm)", "™")
2019-11-11 00:35:52 +01:00
|> String.replace("(c)", "©")
|> String.replace("(r)", "®")
|> String.replace("'", "’")
end
2019-12-01 18:11:00 +01:00
defp replacement_images(t, conn, images) do
2019-11-11 00:35:52 +01:00
t
|> String.replace(~r|>>(\d+)([pts])?|, fn match ->
# Stupid, but the method doesn't give us capture group information
match_data = Regex.run(~r|>>(\d+)([pts])?|, match, capture: :all_but_first)
[image_id | rest] = match_data
image = images[String.to_integer(image_id)]
case [image | rest] do
[nil, _] ->
match
[nil] ->
match
[image, "p"] when not image.hidden_from_users ->
2020-01-11 05:20:19 +01:00
Phoenix.View.render(@image_view, "_image_target.html",
image: image,
size: :medium,
conn: conn
)
2019-11-11 00:35:52 +01:00
|> safe_to_string()
[image, "t"] when not image.hidden_from_users ->
2020-01-11 05:20:19 +01:00
Phoenix.View.render(@image_view, "_image_target.html",
image: image,
size: :small,
conn: conn
)
2019-11-11 00:35:52 +01:00
|> safe_to_string()
[image, "s"] when not image.hidden_from_users ->
2020-01-11 05:20:19 +01:00
Phoenix.View.render(@image_view, "_image_target.html",
image: image,
size: :thumb_small,
conn: conn
)
2019-11-11 00:35:52 +01:00
|> safe_to_string()
[image, suffix] when suffix in ["p", "t", "s"] ->
2021-09-12 16:33:05 +02:00
link(">>#{image.id}#{suffix}#{link_postfix(image)}", to: "/images/#{image.id}")
|> safe_to_string()
2019-11-11 00:35:52 +01:00
[image] ->
2021-09-12 16:33:05 +02:00
link(">>#{image.id}#{link_postfix(image)}", to: "/images/#{image.id}")
2019-11-11 00:35:52 +01:00
|> safe_to_string()
end
end)
end
defp find_images(text_segments) do
2019-12-26 06:03:27 +01:00
text_segments
|> Enum.flat_map(fn t ->
Regex.scan(~r|>>(\d+)|, t, capture: :all_but_first)
|> Enum.map(fn [first] -> String.to_integer(first) end)
2020-05-20 20:23:57 +02:00
|> Enum.filter(&(&1 < 2_147_483_647))
2019-12-26 06:03:27 +01:00
end)
|> load_images()
end
2019-11-11 00:35:52 +01:00
2019-12-26 06:03:27 +01:00
defp load_images([]), do: %{}
2020-01-11 05:20:19 +01:00
2019-12-26 06:03:27 +01:00
defp load_images(ids) do
2019-11-11 00:35:52 +01:00
Image
2019-12-26 06:03:27 +01:00
|> where([i], i.id in ^ids)
|> preload(tags: :aliases)
2019-11-11 00:35:52 +01:00
|> Repo.all()
2019-12-26 06:03:27 +01:00
|> Map.new(&{&1.id, &1})
2019-11-11 00:35:52 +01:00
end
defp link_postfix(image) do
cond do
not is_nil(image.duplicate_id) ->
" (merged)"
2021-07-22 22:15:30 +02:00
image.hidden_from_users ->
" (deleted)"
true ->
""
end
end
end