logo

auto_linker

AutoLinker-shim, based on https://git.pleroma.social/pleroma/auto_linker

builder.ex (4111B)


      1 defmodule AutoLinker.Builder do
      2   @moduledoc """
      3   Module for building the auto generated link.
      4   """
      5 
      6   @doc """
      7   Create a link.
      8   """
      9   def create_link(url, opts) do
     10     []
     11     |> build_attrs(url, opts, :rel)
     12     |> build_attrs(url, opts, :target)
     13     |> build_attrs(url, opts, :class)
     14     |> build_attrs(url, opts, :href)
     15     |> format_url(url, opts)
     16   end
     17 
     18   def create_markdown_links(text, opts) do
     19     []
     20     |> build_attrs(text, opts, :rel)
     21     |> build_attrs(text, opts, :target)
     22     |> build_attrs(text, opts, :class)
     23     |> format_markdown(text, opts)
     24   end
     25 
     26   defp build_attrs(attrs, uri, %{rel: get_rel}, :rel) when is_function(get_rel, 1) do
     27     case get_rel.(uri) do
     28       nil -> attrs
     29       rel -> [{:rel, rel} | attrs]
     30     end
     31   end
     32 
     33   defp build_attrs(attrs, _, opts, :rel) do
     34     if rel = Map.get(opts, :rel, "noopener noreferrer"), do: [{:rel, rel} | attrs], else: attrs
     35   end
     36 
     37   defp build_attrs(attrs, _, opts, :target) do
     38     if Map.get(opts, :new_window, true), do: [{:target, :_blank} | attrs], else: attrs
     39   end
     40 
     41   defp build_attrs(attrs, _, opts, :class) do
     42     if cls = Map.get(opts, :class, "auto-linker"), do: [{:class, cls} | attrs], else: attrs
     43   end
     44 
     45   defp build_attrs(attrs, url, _opts, :href) do
     46     [{:href, url} | attrs]
     47   end
     48 
     49   defp format_url(attrs, url, _opts) do
     50     attrs = format_attrs(attrs)
     51     "<a #{attrs}>#{url}</a>"
     52   end
     53 
     54   defp format_attrs(attrs) do
     55     attrs
     56     |> Enum.map(fn {key, value} -> ~s(#{key}="#{value}") end)
     57     |> Enum.join(" ")
     58   end
     59 
     60   defp format_markdown(attrs, text, _opts) do
     61     attrs =
     62       case format_attrs(attrs) do
     63         "" -> ""
     64         attrs -> " " <> attrs
     65       end
     66 
     67     Regex.replace(~r/\[(.+?)\]\((.+?)\)/, text, "<a href='\\2'#{attrs}>\\1</a>")
     68   end
     69 
     70   defp truncate(url, false), do: url
     71   defp truncate(url, len) when len < 3, do: url
     72 
     73   defp truncate(url, len) do
     74     if String.length(url) > len, do: String.slice(url, 0, len - 2) <> "...", else: url
     75   end
     76 
     77   def create_phone_link([], buffer, _), do: buffer
     78 
     79   def create_phone_link([h | t], buffer, opts) do
     80     create_phone_link(t, format_phone_link(h, buffer, opts), opts)
     81   end
     82 
     83   def format_phone_link([h | _], buffer, opts) do
     84     val =
     85       h
     86       |> String.replace(~r/[\.\+\- x\(\)]+/, "")
     87       |> format_phone_link(h, opts)
     88 
     89     # val = ~s'<a href="#" class="phone-number" data-phone="#{number}">#{h}</a>'
     90     String.replace(buffer, h, val)
     91   end
     92 
     93   def format_phone_link(number, original, opts) do
     94     tag = opts[:tag] || "a"
     95     class = opts[:class] || "phone-number"
     96     data_phone = opts[:data_phone] || "data-phone"
     97     attrs = format_attributes(opts[:attributes] || [])
     98     href = opts[:href] || "#"
     99 
    100     ~s'<#{tag} href="#{href}" class="#{class}" #{data_phone}="#{number}"#{attrs}>#{original}</#{
    101       tag
    102     }>'
    103   end
    104 
    105   def create_mention_link("@" <> name, _buffer, opts) do
    106     mention_prefix = opts[:mention_prefix]
    107 
    108     url = mention_prefix <> name
    109 
    110     []
    111     |> build_attrs(url, opts, :rel)
    112     |> build_attrs(url, opts, :target)
    113     |> build_attrs(url, opts, :class)
    114     |> build_attrs(url, opts, :href)
    115     |> format_mention(name, opts)
    116   end
    117 
    118   def create_hashtag_link("#" <> tag, _buffer, opts) do
    119     hashtag_prefix = opts[:hashtag_prefix]
    120 
    121     url = hashtag_prefix <> tag
    122 
    123     []
    124     |> build_attrs(url, opts, :rel)
    125     |> build_attrs(url, opts, :target)
    126     |> build_attrs(url, opts, :class)
    127     |> build_attrs(url, opts, :href)
    128     |> format_hashtag(tag, opts)
    129   end
    130 
    131   def create_email_link(email, opts) do
    132     []
    133     |> build_attrs(email, opts, :class)
    134     |> build_attrs("mailto:#{email}", opts, :href)
    135     |> format_email(email, opts)
    136   end
    137 
    138   def format_mention(attrs, name, _opts) do
    139     attrs = format_attrs(attrs)
    140     "<a #{attrs}>@#{name}</a>"
    141   end
    142 
    143   def format_hashtag(attrs, tag, _opts) do
    144     attrs = format_attrs(attrs)
    145     "<a #{attrs}>##{tag}</a>"
    146   end
    147 
    148   def format_email(attrs, email, _opts) do
    149     attrs = format_attrs(attrs)
    150     ~s(<a #{attrs}>#{email}</a>)
    151   end
    152 
    153   defp format_attributes(attrs) do
    154     Enum.reduce(attrs, "", fn {name, value}, acc ->
    155       acc <> ~s' #{name}="#{value}"'
    156     end)
    157   end
    158 end