User2121315
User2121315

Reputation: 283

JavaScript converting plain text to links && smilies

Working example: http://alpha.jsfiddle.net/gTpWv/

Both of the methods work separately, but once regexp for smilies gets raw HTML code to process, things get ugly.

    K = K.replace(/\b((http:\/\/)|(www\.))[^ ]{5,}/g, function (x) {
    var b = x;
    if (b.indexOf("www") == 0) {
        b = "http://" + b
    }
    return '<a href="' + b + '" target="_blank">' + x + "</a>"
// K is now /"Testing <a href="http://www.google.com," target="_blank">http://www.google.com,</a> :D, ^^"/


    for (var d = 0; d < smiliesArray.length; d++) {
        K = K.replace(new RegExp(smiliesArray[d][0], "g"), '<img src="' + smiliesArray[d][1] + '">');
    }
// K is now Testing <a href="http%3Cimg%20src=" http:="" i.imgur.com="" mvk87.gif"="">/www.google.com," target="_blank"&gt;http<img src="http://i.imgur.com/MVk87.gif">/www.google.com,</a> <img src="http%3Cimg%20src=" http:="" i.imgur.com="" mvk87.gif"="">/i.imgur.com/7JJNL.gif"&gt;, <img src="http%3Cimg%20src=" http:="" i.imgur.com="" mvk87.gif"="">/i.imgur.com/vRgA3.gif"&gt;

I did find regexp claiming to solve this issue, but inserting it into the regexp: http://alpha.jsfiddle.net/gTpWv/1/ returns nothing.

I've also found interesting the idea to follow this procedure, but I would be left with two seperate lines, one with links and one with smilies and it would take another regexp to inject one into another.

I'm not sure should I meddle with a better regexp(s) or try to find another way to solve this problem.

Upvotes: 1

Views: 540

Answers (1)

Humberto
Humberto

Reputation: 7199

The problem is that :/ will be caught in places where it shouldn't. Every time K changes during replaces, it is fed with some http:// strings that contain the seeds of evil... the :/ bits. At the next iteration, these will be replaced with the corresponding enter image description here smilie, corrupting the generated HTML stored in K.

My approach was to do a 2-phase search and replace. See it in action here http://alpha.jsfiddle.net/gTpWv/7/, and read on for further explanation.

We start by changing every url and smilie to intermediate forms. To use your example string "Testing www.google.com, :D, ^^ :/":

$each(N.split("\n"), function(K) {
    // First pass: creating url and smilie maps
    var urlSubstitutions = [];
    var smilieSubstitutions = [];

    K = K.replace(/\b((http:\/\/)|(www\.))[^ ]{5,}/g, function(match) {
        var b = match;
        if (b.indexOf("www") == 0) {
            b = "http://" + b
        }

        urlSubstitutions.push({ anchor: match, url: b });
        return "{{_u_" + urlSubstitutions.length + "_}}";
    });

    for (var d = 0; d < smiliesArray.length; d++) {
        K = K.replace(new RegExp(smiliesArray[d][0], "g"), function(x){
            smilieSubstitutions.push({ smilie: x, image: smiliesArray[d][1] });
            return "{{_s_" + smilieSubstitutions.length + "_}}";
        });
    }

By now, K will contain Testing {{_u_1_}} {{_s_1_}}, {{_s_2_}} {{_s_3_}}. I hope it's clear that these {{}} strings are the aforementioned intermediate forms of urls and smilies. The actual values of these strings are stored in two arrays named urlSubstitutions and smilieSubstitutions. The next step is simply to decode the intermediate forms into their formatted versions:

    // Second pass: applying urls and smilies
    K = K.replace(/{{_u_(\d+)_}}/g, function(match, index) {
        var substitution = urlSubstitutions[parseInt(index)-1];
        return '<a href="' + substitution.url + '" target="_blank">' + substitution.anchor + "</a>";
    });

    K = K.replace(/{{_s_(\d+)_}}/g, function(match, index) {
        var substitution = smilieSubstitutions[parseInt(index)-1];
        return '<img src="' + substitution.image + '">';
    });

    document.write(K)
});

Hope it helps!

Upvotes: 2

Related Questions