Replace url with link but with an added difficult - javascript

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/

Related

Linking users in the comment

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

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 + '';
}
}
};
}
})();

find text in string and replace it

I have a variable which contains a string expression. This expression have the pattern:
propery_expression operator value
proeprty_expression can look like:
World
World/Name
City/Name
I want to find text after /, and If it exists, and replace with custom text. How can I do this?
With a regex, for example this one :
yourString.replace(/\/\S+/, '/the new stuff...');
In the console :
> var cityName = 'Djakarta';
> var line = 'World/Name Something SomethingElse';
> line.replace(/\/\S+/, '/' + cityName);
"World/Djakarta Something SomethingElse"
You can use this to do complex search and replace operations. Details on Mozilla's documentation
You could try this
var the_string = "City/Name";
var word = "New";
var result = the_string.substring(0, the_string.lastIndexOf('/') + 1);
alert(result + word);
You can try this:
var str = 'World';
alert(rep(str));
function rep(str)
{
if(str.indexOf('/')>-1)//present
{
alert(str.substring(str.lastIndexOf('/') + 1,str.length));
var res = str.replace(str.substring(str.lastIndexOf('/') + 1,str.length),'custom_word');
return res;
}
else{
alert(' / not present');
return str;
}
}
DEMO
Note: If text present after / then it replace it with "custom_word".
In addition to Mathias's answer, you could use RegEx together with a function, like so:
var myString;
.
.
.
myString.replace(/\/(\S+)/g, function (found, value) {
// found == "City/NewYork"
// value == "NewYork"
return found + "Altered";
}
This, for example, will change every "x/y" with "x/yAltered"

Matching escaped spaces using JavaScript indexOf

I have the following JavaScript code:
var matchArray = [];
var passedUrl = '/' + url;
var tabLink;
$('.uiAjaxTabs li a').each(function () {
if (passedUrl.indexOf($(this).attr('href')) == 0) {
boverlap_penalty = passedUrl.replace($(this).attr('href'), '').length;
matchArray.push({ 'score': boverlap_penalty, 'dom_obj': this });
}
});
if (matchArray.length) {
tabLink = matchArray.sort(function (a, b) {
return (a.score < b.score) ? -1 : 1
}).shift().dom_obj;
}
$(tabLink).parents('li').addClass('loading');
Which takes a passedUrl and then matches it up with a set of links to see which most closely matches the url, and then adds a class of loading to it.
This works fine EXCEPT if the link has a space in it e.g. domain.com/People?Name=John Doe because the browser sees it as domain.com/People?Name=John%20Doe and therefore doesn't match it correctly when the passedUrl has the escaped spaces and the link does not.
Any ideas on how to fix this?
Any ideas on how to fix this?
Use
var passedUrl = decodeURI('/' + url);
See MDN docs.
Try JavaScript's unescape function, it seem to decode URL-encoded strings.

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

Categories

Resources