jQuery: selecting external links is not that easy if you choose the wrong approach

jQuery: selecting external links is not that easy if you choose the wrong approach

Selecting external links with jQuery can actually lead to unexpected results if you choose the wrong approach.

This morning my friend Giuseppina, an Italian web developer, was visiting my main website when she noticed some mysterious popups in my resumé page. She informed me about this strange behavior on Facebook. My first thought was that my site was broken or perhaps hacked but later I realized that the multiple popups, all pointing to the current page, were due to an incorrect use of the indexOf() method with jQuery.

The code was the following:


if ($('a', '#content').length) {
	$('a', '#content').each(function() {
		var $a = $(this),
			href = $a.attr('href'),
			$img = $('img', $a);
		if (!$a.hasClass('more-link')) {
			if (!$img.length && href.indexOf(BASEURL) == -1 && href.indexOf('twitter') == -1 && href.indexOf('facebook') == -1 && href.indexOf('mailto') == -1) {
				$a.addClass('external');
				$a.click(function() {
					$a.attr('target', '_blank');
					window.open($a.attr('href'));
					return false;
				});
			}
		}
	});
}

I was trying to add a special class to all my external links by also allowing a visitor to open them in a new window. The problem is that the above if clause with indexOf() also matches hashes and anchors which are present in my resumé page.

My main URL is stored in the BASEURL variable which is http://gabrieleromanato.com/. Of course I had to take care of mailto links plus the URIs generated by the social media buttons.

The problem with my method is that is not exclusive but inclusive. A URL like http://gabrieleromanato.com/page/#section will be also considered as an external link.

indexOf() scans the entire string searching for a substring that matches the argument passed to it. Here we need regular expressions:


var urlRegExp = /^#|(https?:\/\/(www)?(gabrieleromanato|twitter|facebook))|(mailto:)/;
if(!urlRegExp.test(href)) {
	$a.addClass('external');
}

Simple enough. And thanks Giuseppina!