0

How can I dynamically create anchor elements in any text with a URL?

eg.

Turn this

<p>go to http://google.com</p>

into this

<p>go to <a href="http://google.com">link</a></p>

jonhid
  • 2,075
  • 1
  • 11
  • 18
Adil
  • 127
  • 1
  • 8

3 Answers3

2

You could do it yourself with regexp, but it is much easier to use 3rd party module (especially when you want to do it on text that already contains some HTML), like autolinker:

https://github.com/gregjacobs/Autolinker.js/

var linkedText = Autolinker.link(textToAutolink);
Martin Adámek
  • 16,771
  • 5
  • 45
  • 64
2

Getting the regex from this answer you may loop on paragraphs and change the url, if any:

$('p').each(function(idx, ele) {
    var retVal = getUrl(ele.textContent);
    if (retVal) {
        this.textContent = this.textContent.replace(retVal, '');
        $('<a/>', {href: retVal, html: retVal}).appendTo($(this));
    }
})


function getUrl(t) {
  var expression = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
  var regex = new RegExp(expression);
  var result = t.match(regex);
  if (result) {
      return result[0];
  } else {
      return '';
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<p>go to http://google.com</p>
<p>go to hhhhh</p>
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
0

$.prototype.anchor = function() {
  if (this[0].textContent) {
    this.html(this[0].textContent.replace(/((https?:\/\/)?((\w){1,63}\.)?(\w){1,253}\.(\w){2,63}([\w:=-_\/]+)?)/gi, '<a>$1</a>'))
      .find('a').each(function() { this.href = this.textContent; });
  }
  return this;
};
//call .anchor() on any jQuery object to parse it
$('p').each(function() { $(this).anchor(); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>go to http://stackoverflow.com/questions</p>
<p>dont go here</p>
<p>google.com is meh</p>
<p>go to http://www.google.com or https://www.google.com</p>
<p>not a phishing link www.google.com!</p>
<p>violets are foo.bar, roses are Lorem.ipsum:42/dolor?sit=amet</p>

Whats going on

The regex:

/((https?:\/\/)?((\w){1,63}\.)?(\w){1,253}\.(\w){2,63}([\w:=-_\/]+)?)/gi

/( - / starts a regular expression. ( opens the first group so we can capture the entire URL

(https?:\/\/)? - optionally match the protocol

((\w){1,63}\.)? - optionally match a hostname

(\w){1,253}\.(\w){2,63} - match the domain followed by a . followed by a top level domain

([\w:=-_\/]+)? - optionally match any other path or parameters

)/gi - ) closes the first grouping, / closes the regex, g searches for all instances, i ignores text case

The non-regex:

$.prototype.anchor = fucntion() - add .anchor() method to jQuery

if (this[0].textContent) - prevents errors if used on a non-text object

this.html() - you could also use this[0].innerHTML = ... , but that isn't chainable

this[0].textContent.replace(..., '<a>$1</a>') - if a URL is matched, wrap it in anchor tags. If it's not matched, the text is left unchanged

.find('a') - find any anchors that we may have just added

this.href = this.textContent - make the anchor and actual hyperlink

return this - maintains chainability

Pros

  • compact
  • will anchor multiple URLs in a text
  • doesn't require an external library
  • doesn't require cryptic variables
Community
  • 1
  • 1
PoorlyWrittenCode
  • 1,003
  • 1
  • 7
  • 10
  • The regex doesn't support in-URL credentials (e.g. https://username:password@example.com). Here's an updated one which does: `((https?:\/\/)?(\w+:\w+@)?((\w){1,63}\.)?(\w){1,253}\.(\w){2,63}([\w:=-_\/]+)?)` – WackGet Jan 11 '22 at 11:41
  • Furthermore it doesn't support dashes in URLs e.g. `example.com/some-url/1.jpg`. Here's a further improved one: `((https?:\/\/)?(\w+:\w+@)?((\w){1,63}\.)?(\w){1,253}\.(\w){2,63}([\w.:=\-_\/]+)?)` – WackGet Jan 12 '22 at 11:15