Joomla’s Email Protection Script in an AJAX Response

jQuery is great. In previous posts, I have written at length about my admiration for jQuery and how it helped lay the foundation for modern Javascript with it’s intuitive API. I was using jQuery for my AZDirectory module for things like event handlers and AJAX calls. I wanted to remove the jQuery dependency, and replacing that functionality with vanilla Javascript was pretty straightforward. I ran into a huge roadblock, however.

Joomla has a built-in plugin called Email Cloaking. It’s a nifty plugin that obfuscates email addresses to make them harder for bots to detect. It works by replacing email addresses in HTML with inline Javascript.

For the AZDirectory, clicking on a letter invokes an AJAX call to replace the contacts with those matching the selected letter. Using jQuery, replacing the contacts was a one-liner:

jQuery( '#modazdirectory' ).replaceWith( msg );

jQuery’s replaceWith had the magic built-in, properly parsing the inline Javascript to respect the email cloaking even though W3C’s Specification for XMLHttpRequest states:

Scripts in the resulting document tree will not be executed, resources referenced will not be loaded and no associated XSLT will be applied.

W3C XMLHttpRequest Specification

It worked. And I thought nothing more of it.

Until I had to replicate this functionality with vanilla Javascript. The common workaround is to use eval, but after continued research, I started buying into the notion that “eval is evil” from a security and performance perspective. Mozilla has a nice write-up on this subject.

In the write-up, Mozilla posits a more secure, more performant alternative — Function.

After a good bit of hair-pulling and hand-wringing, I settled on the following code for my AJAX response:

azXhr.onload = function(){
if( azXhr.status === 200 ){
var azDirectory = document.getElementById( 'modazdirectory' );
// replace with the DOM with the results of the AJAX call
azDirectory.innerHTML = azXhr.responseText;
// look for embedded scripts within the HTML
var azEmailCloak = azDirectory.querySelectorAll( 'script' );
for( var i = 0; i < azEmailCloak.length; i++ ){
// execute the scripts using the safer Function method as opposed to eval
var azParsed = new Function( azEmailCloak[i].innerHTML );
return azParsed();
}
// re-bind event handlers
} else {
// request failed
}
}

With the email cloaking working, I am happy to remove jQuery as a dependency for using the AZDirectory module.