11

Long story short, I have a website made under Wix.com editor, and coding was made possible a few months ago. I have set up a custom comment box, so users can post their comments, and read others'.

Now the thing is, the "comment Input" takes plain text, and whenever a link is posted, it is displayed as plain text, no color, no clickability.

I want a code that 'reads' the list of comments, and convert every text that begins with 'https' or 'http' or 'www' ... orange and clickable (opening in a new tab)

Any solution please ?

Thanks !

I have tried many things such as :

$w('#text95').html = 
       (/((http:|https:)[^\s]+[\w])/g, '<a href="$1" target="_blank">$1</a>').replace;

text95 = the displayed comments (it is a text that repeats itself for as many comments as there are)

Ivar
  • 5,377
  • 12
  • 50
  • 56
Tristan
  • 111
  • 1
  • 1
  • 3
  • When you say it is "a text that repeats itself for as many comments as there are", is it a `
      ` or what? That's an ID, so there shouldn't be more than one of them in any given page.
    – samanime Apr 03 '18 at 16:27
  • it's inside a 'repeater' (I'm using Wix) – Tristan Apr 04 '18 at 19:37

6 Answers6

19

It looks like you're replace syntax is wrong.

Try something like this, I'm pretty sure this will work.

function linkify(inputText) {
    var replacedText, replacePattern1, replacePattern2, replacePattern3;

    //URLs starting with http://, https://, or ftp://
    replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
    replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');

    //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
    replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
    replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');

    //Change email addresses to mailto:: links.
    replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
    replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');

    return replacedText;
}

Calling it with:

$w('#text95').innerHTML = linkify($w('#text95').html);
5

Here is my answer (improved Version including video links).

See also this Codepen here.

const convertLinks = ( input ) => {

  let text = input;
  const linksFound = text.match( /(?:www|https?)[^\s]+/g );
  const aLink = [];

  if ( linksFound != null ) {

    for ( let i=0; i<linksFound.length; i++ ) {
      let replace = linksFound[i];
      if ( !( linksFound[i].match( /(http(s?)):\/\// ) ) ) { replace = 'http://' + linksFound[i] }
      let linkText = replace.split( '/' )[2];
      if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) }
      if ( linkText.match( /youtu/ ) ) {

        let youtubeID = replace.split( '/' ).slice(-1)[0];
        aLink.push( '<div class="video-wrapper"><iframe src="https://www.youtube.com/embed/' + youtubeID + '" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>' )
      }
      else if ( linkText.match( /vimeo/ ) ) {
        let vimeoID = replace.split( '/' ).slice(-1)[0];
        aLink.push( '<div class="video-wrapper"><iframe src="https://player.vimeo.com/video/' + vimeoID + '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' )
      }
      else {
        aLink.push( '<a href="' + replace + '" target="_blank">' + linkText + '</a>' );
      }
      text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] );
    }
    return text;

  }
  else {
    return input;
  }
}

This replaces long and clumsy links within plain texts to short clickable links within that text. (And also wraps videos in responsive iframes)

Example:

This clumsy link https://stackoverflow.com/questions/49634850/javascript-convert-plain-text-links-to-clickable-links/52544985#52544985 is very clumsy and this http://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split is not much better. This one www.apple.com is nice but www can be removed.

Becomes:

This clumsy link <a href="https://stackoverflow.com/questions/49634850/javascript-convert-plain-text-links-to-clickable-links/52544985#52544985" target="_blank">stackoverflow.com</a> is very clumsy and this <a href="http://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split" target="_blank">developer.mozilla.org</a> is not much better. This one <a href="http://www.apple.com" target="_blank">apple.com</a> is nice but www can be removed.

The linkified text then displays as follows:

This clumsy link stackoverflow.com is very clumsy and this developer.mozilla.org is not much better. This one apple.com is nice but www can be removed.

Brett Donald
  • 3,491
  • 4
  • 20
  • 46
philipeachille
  • 177
  • 1
  • 6
  • Awesome! Could you also add in if statements for social links like facebook, twitter, instagram and linked in? That way if it finds a facebook link in the text it converts it to a facebook url icon? So it would render it like so – Aaron Aug 24 '21 at 16:59
  • @Aaron you could try this module: https://github.com/valueinstrument/v-alpha/blob/master/web-interface/app/vcore/src/helper/v-description.js – philipeachille Sep 19 '21 at 20:11
  • 1
    I love it, thanks! However, I made a couple of improvements and posted these as another answer. https://stackoverflow.com/a/71734086/2518285 – Brett Donald Apr 06 '22 at 01:17
2

I'm not sure what $w is or if you can really assign the html like that, but i'm guessing this is jquery since the $ most commonly refers to the jquery object.

Your try was close, it would be..

$('#text95').html($('#text95').html().replace(/((http:|https:)[^\s]+[\w])/g, '<a href="$1" target="_blank">$1</a>'));

try it..

$('#text95').html($('#text95').html().replace(/((http:|https:)[^\s]+[\w])/g, '<a href="$1" target="_blank">$1</a>'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id=text95>
stuff and stuff and http://ww.stuff.com stuff
</div>
I wrestled a bear once.
  • 21,988
  • 17
  • 67
  • 115
  • I had to tweak it a little, since it showed me error (it should be $w in front of elements) https://www.noelshack.com/2018-14-3-1522864719-capture-d-ecran-46.png – Tristan Apr 04 '18 at 17:56
  • also, the second snippet shows me errors : https://www.noelshack.com/2018-14-3-1522865204-capture-d-ecran-49.png – Tristan Apr 04 '18 at 18:07
  • you're putting markup inside a script which indicates to me that you haven't even made the slightest effort to learn javascript. that's like the first thing you learn. stack overflow is not a free code writing service so, either make some effort to learn on your own or hire a developer. good luckm – I wrestled a bear once. Apr 04 '18 at 18:41
  • What do you mean ? I just did as you said. – Tristan Apr 04 '18 at 19:35
1

I correct errors philipeachille's code because youtubeID parameter is not correct. I also correct direct youtube links.

convertLinks = input => {
    let text = input;
    const aLink = [];
    const linksFound = text.match(/(?:www|https?)[^\s]+/g);

    if (linksFound != null) {
        for (let i = 0; i < linksFound.length; i++) {
            let replace = linksFound[i];

            if (!(linksFound[i].match(/(http(s?)):\/\//))) {
                replace = 'http://' + linksFound[i]
            }

            let linkText = replace.split('/')[2];

            if (linkText.substring(0, 3) == 'www') {
                linkText = linkText.replace('www.', '')
            }

            if (linkText.match(/youtu/)) {
                const youtubeID = replace.split('/').slice(-1)[0].split('=')[1];

                if (youtubeID === undefined || youtubeID === '') {
                    aLink.push('<a href="' + replace + '" target="_blank">' + linkText + '</a>');
                } else {
                    aLink.push('<span class="video-wrapper"><iframe src="https://www.youtube.com/embed/' + youtubeID + '" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></span>');
                }
            } else {
                aLink.push('<a href="' + replace + '" target="_blank">' + linkText + '</a>');
            }

            text = text.split(linksFound[i]).map(item => {
                return aLink[i].includes('iframe') ? item.trim() : item
            }).join(aLink[i]);
        }
        return text;
    }
    else {
        return input;
    }
};

Usage:

const text = 'Hello. This is a link https://www.google.com and this is youtube video https://www.youtube.com/watch?v=O-hnSlicxV4';

convertLinks(text);
cenksari
  • 11
  • 3
  • 1
    No one here has accounted for a link being at the end of a sentence, which means there's going to be a period. So, therefore, with all these solutions the period is being included as part of the link and shouldn't be. – scottrod Dec 28 '20 at 18:16
  • 1
    That's true @scottrod, so I have fixed that in my answer. https://stackoverflow.com/a/71734086/2518285 – Brett Donald Apr 06 '22 at 01:18
1

I really like the solution by @philipeachille. It’s lightweight and does the essentials. However, it has a couple of issues I needed to address:

  • if a link is followed immediately by a punctuation mark, the punctuation is included in the link
  • if the same link is included more than once, the logic gets confused
  • some links don’t start with either www or http, for example microsoft.com

I derived the following from his code, fixing these issues and omitting the video embedding stuff, which I didn’t want:

const linkify = t => {
  const m = t.match(/(?:http|\S+\.\S).+?(?=[.,;:?!-]?(?:\s|$))/g)
  if (!m) return t
  const a = []
  m.forEach(x => {
    const [t1, ...t2] = t.split(x)
    a.push(t1)
    t = t2.join(x)
    const y = (!(x.match(/(http(s?)):\/\//)) ? 'https://' : '') + x
    a.push('<a href="' + y + '" target="_blank">' + y.split('/')[2] + '</a>')
  })
  a.push(t)
  return a.join('')
}

To explain the main regular expression:

  • (?:http|\S+\.\S) matches the start of a link – either ‘http’ or xxx.x (characters followed by a dot followed by another character).
  • .+? matches the rest of the link.
  • (?=[.,;:?!-]?(?:\s|$)) looks ahead (after) the link to determine where the link ends.

Let’s now look in greater detail at the third part of this expression, but we’ll do it backwards and inside out:

  • (?:\s|$) the link is ended either by any white space or by the end of the string.
  • [.,;:?!-]? unless the white space or end of string is immediately preceded by one of these seven punctuation marks, in which case this punctuation mark ends the link.
  • (?= ) all contained in a positive lookahead.
Brett Donald
  • 3,491
  • 4
  • 20
  • 46
0

If string contains URL anywhere, convert that string into link. I try above code but this is not working properly for me. After adding some conditions it worked. Thank you for helping me out @user9590073

function convertLink(inputText) {
        var replacedText, replacePattern1, replacePattern2, replacePattern3;
    
    //URLs starting with http://, https://, or ftp://
    replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&#\/%?=~_|!:,.;]*[-A-Z0-9+&#\/%=~_|])/gim;
    if (replacePattern1.test(inputText))
        inputText = inputText.replace(replacePattern1, '<a href="$1" target="_blank" style="color:blue">$1</a>');

    //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
    replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
    if (replacePattern2.test(inputText))
        inputText = inputText.replace(replacePattern2, '$1<a href="http://$2" target="_blank" style="color:blue">$2</a>');

    //Change email addresses to mailto:: links.
    replacePattern3 = /(([a-zA-Z0-9\-\_\.])+[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
    if (replacePattern3.test(inputText))
        replacedText = inputText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');

    return inputText;
}

And then I pass my text into ConverLink Func to open my modal with clickable URL.

$modalBody.find('div.news-content').html('<p>' + convertLink(response.NewsContent) + '</p>');