dipth

dipth

Autolinking urls in string (replacing urls with link tags)

I’m having a bit of trouble wrapping my head around how to implement an autolinking feature in my Phoenix application. Something like rails_autolink from rails (https://github.com/tenderlove/rails_autolink)

The idea is that I want to scan some user-content and replace all urls with link-tags.

Now, I could technically just make a regular expression and just use it with String.replace to replace the urls, but since I will be using this in combination with text_to_html to also split the text into paragraphs it becomes a little more complex, since text_to_html returns a {:safe, string} tuple. Furthermore when I start replacing the urls by using the Phoenix.HTML.Link.link it becomes a bit of a mess, since I end up with something like:

["<p>This is a test:\r<br>\n", {:safe, [60, "a", [[32, "class", 61, 34, "embed", 34], [32, "href", 61, 34, "https://www.youtube.com/watch?v=CmAI_MwdASw", 34]], 62, "https://www.youtube.com/watch?v=CmAI_MwdASw", 60, 47, "a", 62]} | "</p>\n"]

Which Phoenix seems to choke on:

ArgumentError at GET /forums/4/forum_topics/16
argument error
nofile
No code available.
:erlang.iolist_to_binary/1
Called with 1 arguments
["<p>This is a test:\r<br>\n", {:safe, [60, "a", [[32, "class", 61, 34, "embed", 34], [32, "href", 61, 34, "https://www.youtube.com/watch?v=CmAI_MwdASw", 34]], 62, "https://www.youtube.com/watch?v=CmAI_MwdASw", 60, 47, "a", 62]} | "</p>\n"]

I think I’m missing something here. What would be the “correct” way to accomplish this?

Most Liked

alexparker

alexparker

I’m working on this as well, if I figure it out and remember to come back, I’ll add my solution here. Or if you figured it out, do update please.

voughtdq

voughtdq

Have you tried using Phoenix.HTML.safe_to_string/1 on the result of text_to_html?

MKoussa

MKoussa

For anyone who arrives here, this is what I found to work. Not perfect, but a starting point.

  # only accepts https
  @url_regex ~r/(https:\/\/[^\s<]+)/i

  def linkify(text) when is_binary(text) do
    text
    # Escape ALL user content
    |> html_escape()
    # Get the escaped HTML string
    |> safe_to_string()
    # Inject safe <a> tags
    |> replace_urls()
    # Mark final output as safe
    |> raw()
  end

  defp replace_urls(escaped_html) do
    Regex.replace(@url_regex, escaped_html, fn url ->
      ~s(<a href="#{url}" target="_blank" rel="noopener noreferrer">#{url}</a>)
    end)
  end

And then in your HEEX:

<%= linkify(@content_to_linkify) %>

If anyone knows of a better way, I am open to improvements and suggestions!

Where Next?

Popular in Questions Top

albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43591 214
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
RisingFromAshes
I've read in another post that it may be possible with a router helper - but I couldn't find an appropriate one, and tbh, I'm still just ...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126226 1237
New

We're in Beta

About us Mission Statement