diff --git a/lib/service/formatter/formatter.ex b/lib/service/formatter/formatter.ex
index cf8c9526a..bba56b741 100644
--- a/lib/service/formatter/formatter.ex
+++ b/lib/service/formatter/formatter.ex
@@ -66,7 +66,15 @@ defmodule Mobilizon.Service.Formatter do
def hashtag_handler("#" <> tag = tag_text, _buffer, _opts, acc) do
tag = String.downcase(tag)
url = "#{Endpoint.url()}/tag/#{tag}"
- link = "#{tag_text}"
+
+ link =
+ Tag.content_tag(:a, tag_text,
+ class: "hashtag",
+ "data-tag": tag,
+ href: url,
+ rel: "tag ugc"
+ )
+ |> Phoenix.HTML.safe_to_string()
{link, %{acc | tags: MapSet.put(acc.tags, {tag_text, tag})}}
end
@@ -81,7 +89,8 @@ defmodule Mobilizon.Service.Formatter do
options = linkify_opts() ++ options
acc = %{mentions: MapSet.new(), tags: MapSet.new()}
- {text, %{mentions: mentions, tags: tags}} = Linkify.link_map(text, acc, options)
+ {text, %{mentions: mentions}} = Linkify.link_map(text, acc, options)
+ {text, tags} = extract_tags(text)
{text, MapSet.to_list(mentions), MapSet.to_list(tags)}
end
@@ -135,10 +144,45 @@ defmodule Mobilizon.Service.Formatter do
defp linkify_opts do
Mobilizon.Config.get(__MODULE__) ++
[
- hashtag: true,
- hashtag_handler: &__MODULE__.hashtag_handler/4,
+ hashtag: false,
mention: true,
mention_handler: &__MODULE__.mention_handler/4
]
end
+
+ @match_hashtag ~r/(?:^|[^\p{L}\p{M}\p{Nd}\)])(?\#[[:word:]_]*[[:alpha:]_·][[:word:]_·\p{M}]*)/u
+
+ @spec extract_tags(String.t()) :: {String.t(), MapSet.t()}
+ def extract_tags(text) do
+ matches =
+ @match_hashtag
+ |> Regex.scan(text, capture: [:tag])
+ |> Enum.map(&hd/1)
+ |> Enum.map(&{&1, tag_text_strip(&1)})
+ |> MapSet.new()
+
+ text =
+ @match_hashtag
+ |> Regex.replace(text, &generate_tag_link/2)
+ |> String.trim()
+
+ {text, matches}
+ end
+
+ @spec generate_tag_link(String.t(), String.t()) :: String.t()
+ defp generate_tag_link(_, tag_text) do
+ tag = tag_text_strip(tag_text)
+ url = "#{Endpoint.url()}/tag/#{tag}"
+
+ Tag.content_tag(:a, tag_text,
+ class: "hashtag",
+ "data-tag": tag,
+ href: url,
+ rel: "tag ugc"
+ )
+ |> Phoenix.HTML.safe_to_string()
+ |> (&" #{&1}").()
+ end
+
+ defp tag_text_strip(tag), do: tag |> String.trim("#") |> String.downcase()
end
diff --git a/test/service/formatter/formatter_test.exs b/test/service/formatter/formatter_test.exs
index 79e12429a..3dd7ba167 100644
--- a/test/service/formatter/formatter_test.exs
+++ b/test/service/formatter/formatter_test.exs
@@ -13,7 +13,7 @@ defmodule Mobilizon.Service.FormatterTest do
text = "I love #cofe and #2hu"
expected_text =
- "I love #cofe and #2hu"
+ "I love #cofe and #2hu"
assert {^expected_text, [], _tags} = Formatter.linkify(text)
end
@@ -22,7 +22,7 @@ defmodule Mobilizon.Service.FormatterTest do
text = "#fact_3: pleroma does what mastodon't"
expected_text =
- "#fact_3: pleroma does what mastodon't"
+ "#fact_3: pleroma does what mastodon't"
assert {^expected_text, [], _tags} = Formatter.linkify(text)
end
@@ -174,6 +174,12 @@ defmodule Mobilizon.Service.FormatterTest do
assert {_text, [], ^expected_tags} = Formatter.linkify(text)
end
+
+ test "parses tags in HTML" do
+ text = "Hello #there
"
+
+ assert {_text, [], [{"#there", "there"}]} = Formatter.linkify(text)
+ end
end
test "it can parse mentions and return the relevant users" do