Posts Tagged ‘javascript’

jQuery in Joomla: I was wrong

For quite some time now, it’s been no secret that I’m a fan of jQuery and prefer it to MooTools for JavaScript development. However, Joomla ships with MooTools as the preferred JavaScript framework. Both jQuery and MooTools like using $ as a shortcut method name, which can cause conflicts. Fortunately, both frameworks have ways of disabling this shortcut so that you can use them side by side.

Unfortunately, if you’re not paying attention to the ordering of the JavaScripts, you can end up loading both before you have a chance of sending one into “no conflicts” mode. For quite some time now, I’ve advised fellow Joomla developers to always load MooTools first. It turns out that this advice is not correct, and can cause you to load up MooTools when you’re not even going to use it.

So I’d like to explain why I came to this conclusion in the first place, the correct way of avoiding the problem, and a call to solve this centrally so that people don’t have six copies of jQuery loading on their websites.

The real issue

The core issue has to do with the way JDocument adds JavaScript to the HTML document. As you call JDocument::addScript(), JDocument makes an internal list of all the JavaScript files it needs to load. Also, calling JHTML::_(‘behavior.mootools’) adds the MooTools framework to this list. You can also pass JavaScript in a string to be added directly in <script> tags through the JDocument::addScriptDeclaration() method. With these methods in mind, you would assume that you could add jQuery via JDocument::addScript() and the JavaScript snippet ‘jQuery.noConflict()’ through JDocument::addScriptDeclaration(), like this:

$document = JFactory::getDocument();
$document->addScript('path/to/jquery.js');
$document->addScriptDeclaration('jQuery.noConflict()');

This sometimes works. However, if (for instance) your module used jQuery and the next one used MooTools, you’d run into a conflict even though you had $document->addScriptDeclaration(‘jQuery.noConflict()’) in your code. The advice passed around by myself and the Joomla community was to do this in your code:

JHTML::_('behavior.mootools');
$document = JFactory::getDocument();
$document->addScript('path/to/jquery.js');
$document->addScriptDeclaration('jQuery.noConflict()');

This ensured that MooTools got loaded first and that the conflict would not happen. This also forced MooTools onto the page regardless of whether or not it was being used. It turns out this approach doesn’t really address the real problem: Joomla loads all of your external scripts first, then loads all of your script declarations. So for instance, the following code snippets result in the same script ordering as the previous sample:

$document = JFactory::getDocument();
$document->addScriptDeclaration('jQuery.noConflict()');
JHTML::_('behavior.mootools');
$document->addScript('path/to/jquery.js');

$document = JFactory::getDocument();
JHTML::_('behavior.mootools');
$document->addScriptDeclaration('jQuery.noConflict()');
$document->addScript('path/to/jquery.js');

The fix

To genuinely solve the problem and not worry about MooTools, you need to first create a JavaScript file with the code jQuery.noConflict();. Then you need to load jQuery, then load the file containing the jQuery.noConflict(); code. Your code in Joomla would look like this:

$document = JFactory::getDocument();
$document->addScript('path/to/jquery.js');
$document->addScript('path/to/jquery.noconflict.js');

In this example, jquery.noconflict.js contains the following code:

jQuery.noConflict();

By doing this, it’s guaranteed that jQuery.noConflict() will get called immediately after jQuery is loaded by the browser. To recap, the ordering of MooTools and jQuery does not matter if you make sure jQuery.noConflict() is called immediately after jQuery is loaded. After you send jQuery into noConflict mode, you still must either use jQuery() instead of $(), or use one of the referencing methods described here in your jQuery-powered code.

But wait, I still have a thousand extensions all loading jQuery!

Ideally, each Joomla site should be loading either zero or one copies of jQuery. Having multiple copies of jQuery sitting around Joomla puts site owners in the position of having to manage conflicts. Also, distributing multiple copies of jQuery discourages the use of Google’s JavaScript library CDN. We don’t want to foist this problem onto site administrators; they just want all of their extensions to work.

Fortunately, there’s an effort underway to standardize and document the use of jQuery in Joomla. If you’re willing to help out, join our Joomla People Group jump into the discussion. We should be able to document a way for extension developers to bundle a jQuery plugin with their extensions, as well as avoid version conflicts. Ultimately, a copy of jQuery should be installed and updated as necessary without the intervention of site administrators.

The way NOT to do JavaScript in Joomla!

While doing a little Sunday afternoon browsing of Twitter, I noticed Amy Stephen warning about a bad technique for using Joomla! with AJAX-style requests. I followed the link (WARNING: don’t use this code!) and found security vulnerabilities right away. Since the blog in question doesn’t support comments, I’m forced to respond here.

First, as Amy pointed out, the technique creates another entry point into Joomla. While this can be used effectively if you know what you’re doing, it’s totally unnecessary for a casual application of asynchronous JavaScript. Next, class, who can tell me what’s wrong with this piece of code?

cExt( $_POST['func'] );

That’s right, we’re passing data straight from our HTTP request (which can come from anywhere in the WORLD) into our application’s logic. Once we get into the the cExt function, the variable is used to execute code with no filtering whatsoever:

function cExt($func = ”){
$cext = null;
if(!empty($GLOBALS['cExt']))
$cext = $GLOBALS['cExt'];
else{
$GLOBALS['cExt'] = new plgCommunityExt();
$cext = $GLOBALS['cExt'];
}
if(empty($func))
return $cext;
else{
if($GLOBALS['ajax'] == true)
$cext->$func();
else
return $cext->$func();
}
}
function cExt($func = ''){

    $cext = null;

    if(!empty($GLOBALS['cExt']))

        $cext = $GLOBALS['cExt'];

    else{

        $GLOBALS['cExt'] = new plgCommunityExt();

        $cext = $GLOBALS['cExt'];

    }

    if(empty($func))

        return $cext;

    else{

        if($GLOBALS['ajax'] == true)

            $cext->$func();

        else

            return $cext->$func();

    }

}

Please, regardless of whether or not you use Joomla, don’t do this! It is a totally insecure way of writing code. Instead, if you are using Joomla, you can at least filter this variable using the following code:

$func = JRequest::getCmd('func', '');

This code will filter the func variable from the request and make sure it only includes numbers, letters, or underscores. Additionally, you should filter $func to make sure a corresponding public function in the plgCommunityExt class exists before attempting to use it to actually execute that function.

As a side note, $GLOBALS is being used an awful lot here. While this isn’t a security risk in and of itself, it is a bad practice that can lead to insecure coding. If the register_globals setting in PHP (going away in PHP 6) is turned on, this becomes a huge security risk as anyone in the world can set the value of cExt to anything.

The post ends with this quick jibe:

That was pretty easy wasn’t it, in order to get quick results you just have to find these shortcuts which will spare you the time and pain of having to read some Joomla-, or pick your favorite, CMS book.

I’d argue that the author of this blog post would not only benefit from reading a book about CMS development, but one on basic PHP security. The technique he describes is insecure in any PHP-based framework or CMS.

Fortunately, you don’t even have to run to the bookstore to find examples of the correct way of doing these things. Louis Landry has a quick example of how to return JSON formatted data simply and securely on this thread, without having to create a special component view. If you do want to use a view, this blog post will show you how to do it.

Finally, if you do want to learn how to add AJAX-style requests to Joomla (without necessarily using JSON), I’ll shamelessly plug my own book. But you don’t even have to buy it, because the sample chapter is indeed the one on JavaScript and Joomla (start on page 168 if you already know Joomla! MVC).

Using MooTools and jQuery Together in Joomla!

Framework conflicts are a common problem people run into when using jQuery. While jQuery provides some tricks you can use to get around this, you may still run into issues when Joomla! generates MooTools effects. While writing the second edition of Learning Joomla! Extension Development, I decided to do a chapter on JavaScript and look into this problem a little bit more closely. It turns out you have to make sure MooTools loads before jQuery, then use one of the tricks detailed on jquery.com.

Fortunately, this can be done in Joomla! consistenly, so I documented it. Packt decided to release the entire JavaScript chapter as the sample PDF for my book, so you can read everything you need to know about implementing this technique for free!

Some software I’ve been using recently

Flot – Want to build dynamic graphs without using Flash? Flot is ready. It’s lightweight and pretty quick to pick up. I’m using it for a project where people can add and remove as many data series as they wish. Throw in some JSON calls and the results are pretty impressive. Although I can’t show off that project here, take a look at some of the posted examples. It’s based on jQuery and produced by a Danish firm.

MacFUSE and SSHFS – One of the biggest problems I’ve run into with using Macs is that Finder cannot mount FTP and SFTP sites as writable volumes. While you can get clients like CyberDuck that will allow you to do transfers, editing the files for an entire website this way can be tedious. Using MacFUSE and SSHFS together can get around this limitation. SSHFS is still in a very early release and I did run into some stability issues when mounted all day long, but the core functionality is there.

Selenium IDE – Testing and debugging web interfaces has always been a bit of a pain, but Selenium IDE can make the process much, much faster. Open up the IDE, click record, then start filling out forms and clicking on elements. Then you can save your test and reopen it later to run it whenever you wish. I did run into a few issues where Javascript generated DOM elements confused the debugger (might be a timing issue), but overall it is a very powerful and easy to use Firefox extension. You can also use Selenium Core on other browsers. I haven’t tried this, but it appears that you can record the test using the IDE in Firefox, then use that same test with Core with the other browsers. Thanks to Laura Thomson for mentioning this one at the DC PHP Conference this past fall.