Linking users in the comment - javascript

I would like to link users in the comments. So far I did the back end (in Django) and now I'm struggling with the front end. I managed to write something with JavaScript to make usernames clickable when a comment has the character "#" in front of the name.
function urlify(texts) {
var urlRegex = /(#[^\s]+)/g;
return texts.replace(urlRegex, function(url) {
return '' + url + '';
})
}
var texts = $(".content1").text();
var html = urlify(texts);
$('.test1').prepend(html);
$('.content1').prepend(html);
Now I can get the first comment and make the usernames clickable.
How do I rewrite the code so every comment is replaced? I thought about a for loop but I'm not sure how to write it. Is there an easy way where I can replace all "#"s on the template with one function?

var string = 'Hey #user123, can you upload a file';
function urlify(texts) {
var urlRegex = /(#[\w]+)/g;
return string.replace(urlRegex, function(match){
var name = match.slice(1);
return '' + match + ''
})
}
console.log(urlify(string));
Returns Hey #user123, can you upload a file
Edit for multiple:
Using the string Hey #user123, can you upload a file, otherwise #admin can you take a look
Yields:
Hey #user123, can you upload a file, otherwise #admin can you take a look
...so no loop necessary.
Edit 2:
function urlify(texts) {
var urlRegex = /(#[\w]+)/g;
return texts.replace(urlRegex, function(match){
var name = match.slice(1);
return '' + match + ''
})
}
$(document).ready(function(){
var text = $('.comment').html(function(index, text) {
return urlify(text)
});
});
http://plnkr.co/edit/tehEF4ESYXf4TTRR5lz8?p=preview

Related

Escape user-generated chat messages but render links

User enter chat messages, which gets rendered directly to the page using Mustache templates. Obviously, HTML should be escaped to prevent HTML injection, but then again links should be rendered as <a href='...'>.
There are different approaches I've tried to use {{{ ... }}} to return the unescaped HTML content, which means the link would get rendered and I need to take care of HTML escaping myself. Is there a safe way of doing that without relying on a half-baked solution I write myself?
jQuery.text() would be great, but I guess it will render the <a> again as text.
What else can I do here?
If you don't want to write your own escaping or parsing solution there is a jQuery plugin to handle links called Linkify. You could simply escape messages and then parse them client-side.
Example of how it works:
var text = "<div>Test<br>Test<br>Test http://stackoverflow.com</div>";
$('div').text(text);
// Before: <div>Test<br>Test<br>Test http://stackoverflow.com</div>
$('div').linkify();
// After: lt;div>Test<br>Test<br>Test http://stackoverflow.com</div>
Just an idea: You could build your own escaping function
escape : function () {
return function(val, render) {
var $s = $(val);
var $elements = $s.find("*").not("a"); //add other white-listed elements seperated by comma
for (var i = $elements.length - 1; i >= 0; i--) {
var e = $elements[i];
$(e).replaceWith(e.innerHTML);
}
return $s.html();
}
}
You can call the function by
{{#escape}}{{{YOUR_TEXT}}}{{/escape}}
I have not tested this. This solution needs jQuery. The code above is based on this solution: https://stackoverflow.com/a/27764431/1479486
try inserting first in .text() and then use regexp for render the link with .html(). Here you can see a vanilla example:
var a="see formula a<b>c in http://test.com or https://x.com?p=3";
var hold=document.createElement('div');
hold.textContent=a;
hold.innerHTML=hold.innerHTML.replace(
/(https?:\/\/[-$A-Za-z0-9%_?&.~+\/=]+)/g,
'$1'
);
window.addEventListener('load',function(){
document.body.appendChild(hold);
});
For a more acurate regexp you can see here
If you end up going down the regex route the following filter and regex was the most aggressive one i found for picking up all kinds of urls that your users will try to type.
Heres a regexr to play around with it: http://regexr.com/3bjk9
(function () {
'use strict';
angular
.module('core.filters')
.filter('urlToA', urlToA);
// --------------------
function urlToA () {
return function (string, noClick) {
var urlPattern = /((?:(http|https|Http|Https|rtsp|Rtsp):\/\/(?:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,64}(?:\:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,25})?\#)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\:\d{1,5})?)(\/(?:(?:[a-zA-Z0-9\;\/\?\:\#\&\=\#\~\-\.\+\!\*\'\(\)\,\_])|(?:\%[a-fA-F0-9]{2}))*)?(?:\b|$)/gi; // jshint ignore:line
return string ? string.replace(urlPattern, replace) : string;
function replace (url) {
var httpUrl = url.indexOf('http') === -1 ? 'http://' + url : url;
if (noClick) {
return '<a>' + url + '</a>';
} else {
return '' + url + '';
}
}
};
}
})();

passing a variable to map & replace

I am trying to "clean" a text string that looks something like this:
DATABASE:madsat NL:Show all platforms of Salute generated from NAIs with no go mobility.
The cleaned string should look like this:
Show all platforms of Salute generated from NAIs with no go mobility.
I am trying the following code but it doesn't seem to like it when I pass in a variable as the string gets returned unchanged:
$(document).ready(function(){
$.get('inputQueryExamples.txt',function(data){
var queryString = data;
var cleanString = "";
var db = '';
$('#database-list').change(function(){
db = $('#database-list').val();
// /(^DATABASE:.*\r\n)(^NL.*)/gm
// http://regex101.com/r/mN4hS2
regex = new RegExp('(^DATABASE:'+ db +'\r\n)(^NL.*)' ,'gm');
console.log(db);
console.log(regex);
//put code in here to replace un-needed stuff
$('#what').append(regex + '<br>');
cleanString = queryString.match(regex);
var nlString = cleanString.map(function(el) {return el.replace('DATABASE:' + db + ' NL:','');});
for (i=0; i<nlString.length; i++){
$('#what').append(nlString[i]+'<br>');
}
}); // end change
Any insight into what i am doing wrong will be appreciated. Thanks
So this works, but I am not sure why I have to process the string twice. Can anyone explain?
var nlString = cleanString.map(function(el) {return el.replace('DATABASE:' + db,'');});
nlString = nlString.map(function(el){return el.replace('NL:',''); });
Something like this?
var s = "DATABASE:madsat \r\nNL:Show all platforms of Salute generated from NAIs with no go mobility.";
var db = "madsat";
var r = new RegExp('(^DATABASE:'+ db + '[\\s\\r\\n]*)(^NL:)' ,'gm');
s1.replace(r, "");
//=> "Show all platforms of Salute generated from NAIs with no go mobility."
Update
It took a while for what you're trying to do to sink in (and your sample data was pretty buried in that regex101 link.)
But I think this JSBin is something close to what you want to do: It still does one pass to find the matches, and a second one to remove the unwanted parts of that match. But the second pass is handled by a single regex replace call rather than your double replaces above. (Click the "Run with JS" button and enter "madsat" or "geoquery" in the box.)
This is the relevant code:
$(document).ready(function() {
$.ajax('http://jsbin.com/fase/1.js', {dataType:'text'}).done(function(data){
var $what = $("#what");
$('#database-list').change(function(){
var db = $(this).val(),
base = '(^DATABASE:'+ db + '[\\s\\r\\n]*)(^NL:)';
var regex1 = new RegExp(base + '(.*)' ,'gm');
var regex2 = new RegExp(base, 'gm');
(data.match(regex1) || []).map(function(str) {
return str.replace(regex2, "");
}).forEach(function(query) {
$what.append(query + "<br/>");
});
});
});
});
Note that the two regexes are identical except that the first one matches the remainder of the "NL:"-line, and the second one doesn't.

Replace url with link but with an added difficult

In an editable iframe I am replacing the plain urls with links thanks to this regex:
function linkify(text) {
var regex = /(http|https|ftp)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?\/?([a-zA-Z0-9\-\._\?\,\'\/\\\+&%\$#\=~])*/g;
return text.replace(regex,"<a href='$&'>$&</a>");
}
var content = linkify($('.div').html());
My problem comes when I try to 'linkify' a string wich contain links, it creates a monster like this:
http://google.com
I think that this problem can be solved if I iterate over the DOM instead of analyze the html string, but before to try it I want to ask here if someone have any idea.
Thanks!
I had a similar problem, and solved it by first stripping the html tags:
function strip_tags(str, allow) {
allow = (((allow || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('');
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi;
var commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
return str.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
return allow.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
});
}
And then running the urlify function:
function urlify(text) {
var exp = /(\b(http):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
return text.replace(exp,"<a href='$1'>$1</a>");
}
See my fiddle to try it out: http://jsfiddle.net/gerbenzomp/UJMeR/3/

Regex to match urls but not urls in hyperlinks

I am trying to wrap any url that is in some text and turn it into a hyperlink... but I do not want to wrap a url that is already wrapped by a hyperlink.
For example:
Go To Twitter
here is a url http://anotherurl.com
The following code:
function replaceURLWithHTMLLinks(text) {
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
return text.replace(exp, "<a href='$1'>$1</a>");
}
Gives the following output:
#BIR
http://anotherurl.com
How can I modify the regex to exclude already hyperlinked urls?
Thanks
Answer:
The new method is:
function replaceURLWithHTMLLinks(text) {
var exp = /(?:^|[^"'])((ftp|http|https|file):\/\/[\S]+(\b|$))/gi
return text.replace(exp, " <a href='$1'>$1</a>");
}
The above code functions as required. I modified the regex from a link in the comments because it contained a bug where it would include the full stop, it now excludes any full stops that come after a full url.
Since javascript doesn't seem to support negative look-behind, you will have to trick it by using a replace function.
Capture the href (maybe you should also also consider src) :
function repl(text) {
var exp = /((href|src)=["']|)(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
return text.replace(exp, function() {
return arguments[1] ?
arguments[0] :
"" + arguments[3] + ""
});
}
See the demo
EDIT
A "better" version which will only replace links in actual text nodes:
function repl(node) {
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/i;
var nodes=node.childNodes;
for (var i=0, m=nodes.length; i<m; i++){
var n=nodes[i];
if (n.nodeType==n.TEXT_NODE) {
var g=n.textContent.match(exp);
while(g) {
var idx=n.textContent.indexOf(g[0]);
var pre=n.textContent.substring(0,idx);
var t=document.createTextNode(pre);
var a=document.createElement("a");
a.href=g[0];
a.innerText=g[0];
n.textContent = n.textContent.substring(idx+g[0].length);
n.parentElement.insertBefore(t,n);
n.parentElement.insertBefore(a,n);
g=n.textContent.match(exp);
}
}
else {
repl(n);
}
}
}
var r=repl(document.getElementById("t"))
​
See the demo

Converting text into a link with JavaScript returns an error

function assert() {
document.write.apply(document, arguments);
}
var testLink = "google.com";
function makeIntoLink(link) {
if (link.match(/^[a-zA-Z0-9]+(.com)/)) {
link.replace(link, "<a href=\"http://www." + link+ "\">" + link + "<\/a>");
}
return link;
}
assert(makeIntoLink(testLink));
It writes it down but not in link form. Just "google.com" without the link. What could've gone wrong?
A function like link.replace doesn't actually replace stuff inside the string, it actually returns a NEW string with the replacements made. For example:
function replaceText() {
var searchText = ".com";
var link = "google.com";
var newLink = link.replace(searchText, ".co.uk");
alert(link); // Output = "google.com"
alert(newLink); // Output = "google.co.uk"
}
In your situation though, you don't need to use string.replace(...) at all, instead you can just do this:
function makeIntoLink(link) {
if (link.match(/^[a-zA-Z0-9]+(.com)/)) {
//link.replace(link, "<a href=\"http://www." + link+ "\">" + link + "<\/a>"); <-- OLD
link = "<a href=\"http://www." + link+ "\">" + link + "<\/a>"; // <-- NEW
}
return link;
}
link.replace doesn't change the text in-situ, it makes a new string. Trying changing the line from link.replace(link... to link = link.replace(link...
replace returns a version of the string with the replacement made; the string is not replaced in-situ. So link = link.replace... rather than simply link.replace.
As the others have said, replace doesn't change the variable, it just returns a new one. But in this case, you don't really want to replace something, you just want to concatenate some stuff around it.
IMO, you don't need the replace function for that:
function makeIntoLink(link) {
if (link.match(/^[a-zA-Z0-9]+(.com)/)) {
link = '' + link + '';
}
return link;
}
(I've also removed your \" escapes by using different quote characters for the JS string literal and the HTML attributes. This makes it a mite less hard to read, IMHO).

Categories

Resources