philomena/lib/philomena/textile/renderer.ex

123 lines
3.1 KiB
Elixir
Raw Normal View History

2019-11-11 00:35:52 +01:00
defmodule Philomena.Textile.Renderer do
2019-12-01 18:11:00 +01:00
# todo: belongs in PhilomenaWeb
2019-11-11 00:35:52 +01:00
alias Textile.Parser
alias Philomena.Images.Image
alias Philomena.Repo
import Phoenix.HTML
import Phoenix.HTML.Link
import Ecto.Query
@parser %Parser{
image_transform: &Camo.Image.image_url/1
}
# Kill bogus compile time dependency on ImageView
@image_view Module.concat(["PhilomenaWeb.ImageView"])
2019-12-01 18:11:00 +01:00
def render_one(post, conn) do
hd(render_collection([post], conn))
2019-11-11 00:35:52 +01:00
end
2019-12-01 18:11:00 +01:00
def render_collection(posts, conn) do
2019-11-11 00:35:52 +01:00
parsed =
posts
|> Enum.map(fn post ->
2019-11-18 02:33:50 +01:00
Parser.parse(@parser, post.body)
2019-11-11 00:35:52 +01:00
end)
images =
parsed
|> Enum.flat_map(fn tree ->
tree
|> Enum.flat_map(fn
{:text, text} ->
[text]
_ ->
[]
end)
end)
|> find_images
parsed
|> Enum.map(fn tree ->
tree
|> Enum.map(fn
{:text, text} ->
text
|> replacement_entities()
2019-12-01 18:11:00 +01:00
|> replacement_images(conn, images)
2019-11-11 00:35:52 +01:00
{_k, markup} ->
markup
end)
|> Enum.join()
end)
end
defp replacement_entities(t) do
t
|> String.replace("->", "→")
|> String.replace("--", "—")
|> String.replace("...", "…")
|> String.replace(~r|(\s)-(\s)|, "\\1—\\2")
|> String.replace("(tm)", "&tm;")
|> 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"] ->
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"] ->
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"] ->
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] ->
link(">>#{image.id}", to: "/#{image.id}")
|> safe_to_string()
end
end)
end
defp find_images(text_segments) do
2019-12-23 00:42:07 +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)
end)
|> find_image_ids()
end
2019-11-11 00:35:52 +01:00
2019-12-23 00:42:07 +01:00
defp find_image_ids([]), do: %{}
defp find_image_ids(image_ids) do
2019-11-11 00:35:52 +01:00
Image
|> where([i], i.id in ^image_ids)
|> where([i], i.hidden_from_users == false)
2019-12-23 00:42:07 +01:00
|> join(:left, [i], _ in assoc(i, :tags))
|> preload([_i, t], tags: t)
2019-11-11 00:35:52 +01:00
|> Repo.all()
|> Map.new(fn image -> {image.id, image} end)
end
end