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.