logo

auto_linker

AutoLinker-shim, based on https://git.pleroma.social/pleroma/auto_linker
commit: 4d5182ec1febb9d9963fce5825cb16a8f7e6e17d
parent: 6c56eb91efb4293bea185c524808c0a8b34d5d8b
Author: Stephen M. Pallen <smpallen99@yahoo.com>
Date:   Mon, 22 Jan 2018 19:46:47 -0500

added support for markdown style links

Diffstat:

MREADME.md3+++
Mlib/auto_linker.ex7+++++++
Mlib/auto_linker/builder.ex28++++++++++++++++++++++++----
Mlib/auto_linker/parser.ex14++++++++++----
Mmix.exs2+-
Mtest/auto_linker_test.exs15+++++++++++++++
6 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md @@ -45,6 +45,9 @@ iex> AutoLinker.link("or at home on 555.555.5555") iex> AutoLinker.link(", work (555) 555-5555") ~s{, work <a href="" class="phone-number" data-number="5555555555">(555) 555-5555</a>} +iex> AutoLinker.link("[Google Search](http://google.com)", markdown: true) +"<a href='http://google.com' class='auto-linker' target='_blank' rel='noopener noreferrer'>Google Search</a>" + See the [Docs](https://hexdocs.pm/auto_linker/) for more examples ## Configuration diff --git a/lib/auto_linker.ex b/lib/auto_linker.ex @@ -15,6 +15,12 @@ defmodule AutoLinker do iex> AutoLinker.link("google.com", new_window: false, rel: false, class: false) "<a href='http://google.com'>google.com</a>" + + iex> AutoLinker.link("[Google](http://google.com)", markdown: true, new_window: false, rel: false, class: false) + "<a href='http://google.com'>Google</a>" + + iex> AutoLinker.link("[Google Search](http://google.com)", markdown: true) + "<a href='http://google.com' class='auto-linker' target='_blank' rel='noopener noreferrer'>Google Search</a>" """ import AutoLinker.Parser @@ -33,6 +39,7 @@ defmodule AutoLinker do * `exclude_class: false` - Set to a class name when you don't want urls auto linked in the html of the give class * `exclude_id: false` - Set to an element id when you don't want urls auto linked in the html of the give element * `exclude_patterns: ["```"] - Don't link anything between the the pattern + * `markdown: false` - link markdown style links Each of the above options can be specified when calling `link(text, opts)` or can be set in the `:auto_linker's configuration. For example: diff --git a/lib/auto_linker/builder.ex b/lib/auto_linker/builder.ex @@ -15,6 +15,14 @@ defmodule AutoLinker.Builder do |> format_url(url, opts) end + def create_markdown_links(text, opts) do + [] + |> build_attrs(text, opts, :rel) + |> build_attrs(text, opts, :target) + |> build_attrs(text, opts, :class) + |> format_markdown(text, opts) + end + defp build_attrs(attrs, _, opts, :rel) do if rel = Map.get(opts, :rel, "noopener noreferrer"), do: [{:rel, rel} | attrs], else: attrs @@ -37,13 +45,25 @@ defmodule AutoLinker.Builder do url |> strip_prefix(Map.get(opts, :strip_prefix, true)) |> truncate(Map.get(opts, :truncate, false)) - attrs = - attrs - |> Enum.map(fn {key, value} -> ~s(#{key}='#{value}') end) - |> Enum.join(" ") + attrs = format_attrs(attrs) "<a #{attrs}>" <> url <> "</a>" end + defp format_attrs(attrs) do + attrs + |> Enum.map(fn {key, value} -> ~s(#{key}='#{value}') end) + |> Enum.join(" ") + end + + defp format_markdown(attrs, text, _opts) do + attrs = + case format_attrs(attrs) do + "" -> "" + attrs -> " " <> attrs + end + Regex.replace(~r/\[(.+?)\]\((.+?)\)/, text, "<a href='\\2'#{attrs}>\\1</a>") + end + defp truncate(url, false), do: url defp truncate(url, len) when len < 3, do: url defp truncate(url, len) do diff --git a/lib/auto_linker/parser.ex b/lib/auto_linker/parser.ex @@ -62,6 +62,11 @@ defmodule AutoLinker.Parser do defp do_parse(text, %{phone: false} = opts), do: do_parse(text, Map.delete(opts, :phone)) defp do_parse(text, %{url: false} = opts), do: do_parse(text, Map.delete(opts, :url)) + defp do_parse(text, %{markdown: true} = opts) do + text + |> Builder.create_markdown_links(opts) + |> do_parse(Map.delete(opts, :markdown)) + end defp do_parse(text, %{phone: _} = opts) do text |> do_parse(false, opts, {"", "", :parsing}, &check_and_link_phone/3) @@ -79,13 +84,16 @@ defmodule AutoLinker.Parser do defp do_parse(text, _), do: text - # state = {buffer, acc, state} - defp do_parse("", _scheme, _opts ,{"", acc, _}, _handler), do: acc defp do_parse("", scheme, opts ,{buffer, acc, _}, handler), do: acc <> handler.(buffer, scheme, opts) + defp do_parse("<a" <> text, scheme, opts, {buffer, acc, :parsing}, handler), + do: do_parse(text, scheme, opts, {"", acc <> buffer <> "<a", :skip}, handler) + + defp do_parse("</a>" <> text, scheme, opts, {buffer, acc, :skip}, handler), + do: do_parse(text, scheme, opts, {"", acc <> buffer <> "</a>", :parsing}, handler) defp do_parse("<" <> text, scheme, opts, {"", acc, :parsing}, handler), do: do_parse(text, scheme, opts, {"<", acc, {:open, 1}}, handler) @@ -131,7 +139,6 @@ defmodule AutoLinker.Parser do defp do_parse(<<ch::8>> <> text, scheme, opts, {buffer, acc, state}, handler), do: do_parse(text, scheme, opts, {buffer <> <<ch::8>>, acc, state}, handler) - def check_and_link(buffer, scheme, opts) do buffer |> is_url?(scheme) @@ -154,7 +161,6 @@ defmodule AutoLinker.Parser do end def is_url?(buffer, _) do - # IO.puts "..... '#{buffer}'" if Regex.match? @invalid_url, buffer do false else diff --git a/mix.exs b/mix.exs @@ -1,7 +1,7 @@ defmodule AutoLinker.Mixfile do use Mix.Project - @version "0.2.1" + @version "0.2.2" def project do [ diff --git a/test/auto_linker_test.exs b/test/auto_linker_test.exs @@ -8,4 +8,19 @@ defmodule AutoLinkerTest do ~s{, work <a href="#" class="phone-number" data-phone="5555555555">(555) 555-5555</a>} end + test "default link" do + assert AutoLinker.link("google.com") == + "<a href='http://google.com' class='auto-linker' target='_blank' rel='noopener noreferrer'>google.com</a>" + end + + test "markdown" do + assert AutoLinker.link("[google.com](http://google.com)", markdown: true) == + "<a href='http://google.com' class='auto-linker' target='_blank' rel='noopener noreferrer'>google.com</a>" + end + + test "does on link existing links" do + assert AutoLinker.link("<a href='http://google.com'>google.com</a>") == + "<a href='http://google.com'>google.com</a>" + end + end