Introducing Quick Tabs 2.0: ...and would you like some AJAX with those tabs?
When the Quick Tabs module was first conceived, it was meant as a space saving device that would replicate a feature becoming quite common on news websites: the little "Most emailed / Most popular" block, where you'd have two tabs, each showing about 5 items (node titles with links to the nodes), and that would be that. Of course I wasn't so short-sighted as to limit it to two tabs (I limited it to 10), but I didn't imagine there'd be much more people could want out of it. Well, my issue queue soon proved me very wrong. Among the many features subsequently requested by users, one kept cropping up again and again: AJAX-loaded tabs. The original offering (and what the Drupal 5 version is still unfortunately limited to) simply provided a show/hide mechanism for the tabs, so that all of the content was loaded at once, on page load, and simply shown or hidden as different tabs were clicked. As people began adding more and more views to their tabs, thereby essentially loading several views simultaneously on one page, they soon started to be concerned about performance. Once I saw how people were actually using the module, I started to realise how valuable a feature this could be: quicktabs wouldn't necessarily be confined to sidebars but could form the main content of a page, pulling in large amounts of Views data across several tabs. I honestly had never thought about it that way before.
So after dragging myself around to a bigger view of the module I finally had a go at implementing this ajax feature back in November. I completely separated the code for this new type of quicktab out from the original code for fear of breaking something in the parts that were already working fine and ended up presenting the user with two completely separate quicktabs creation forms - one for the ajax version, where you could choose either a node or a view for each tab, and one for the original type with blocks and views. Of course this proved to involve brutally unnecessary duplication of code as was pointed out to me soon enough, but it served my purposes fine for just figuring the thing out. After I got the basic functionality working - a couple of ajax callbacks for pulling the content (one for nodes and one for views) and sticking it into the quicktabs container - I felt very pleased with myself and committed it, fully expecting it to be received with rapturous appreciation by those who had been awaiting it. To my complete deflation what I got instead were bug reports. You see, I hadn't thought that people would be so demanding as to actually want things like paging and table-sorting to work in their ajax-loaded views, that just seemed like a ridiculously tall order to me. This was my initial reaction anyway, and in fact I did respond by saying something like "Oh well actually this probably won't work with paged views - sorry!" But of course it niggled and niggled at me until I finally gave in and decided to see why exactly the ajax paging in the views was not working inside my shiny new ajaxified quicktabs blocks.
That's when I started delving into the voodoo that is the Views ajax code, contained mainly (I think) in includes/ajax.inc and js/ajax_view.js. I tinkered around enough to discover the following useful facts:
1. there's no need to reinvent the wheel when it comes to loading a view via ajax: Views itself does this all the time with its exposed filters, paging links, etc
2. you can't load a view via ajax unless Drupal.settings already knows about it
3. it's one thing to wish to load multiple views to the same page (i.e. using the same instantiation of Drupal.settings) via ajax, but it's quite another to expect to load the same view twice (or three times, or four!) via ajax, passing different arguments or whatever, and have everything work swimmingly
4. when dealing with code from the likes of nedjo and merlinofchaos it's actually ok to expect things like #3
What #1 meant for me was that there was no need for my ajax view callback function at all - with the right javascript I could use the ajax callback function already built in to Views for sending back a JSON-formatted version of the requested view. Which brings us to point #2: "the right javascript" means ensuring that the Drupal.settings.views object contains the ajax_path (the path to the Views callback function) and also contains the ajaxViews object which in turn contains objects with the name, display id, arguments and path for every view that your page could conceivably want to load via ajax. Then it was simply a matter of copying the behaviour defined for the pager links and adapting it for use in my tab links. There was one snag though: if you did have a quicktabs block with two or more tabs loading the same view for whatever reason (most likely to pass different arguments each time), the pager links in the second and subsequent ones would end up returning the first version of the view. This was because it was referring to Drupal.settings.views.ajaxViews and finding the details for the first view with that name even though there were multiple objects for that particular view. But a recent change to ajax_view.js seems to have fixed this: the view object to be passed to the ajax callback gets initialised from what's in Drupal.settings but its properties are overridden with the values found in the querystring of the link - and in the pager links these will always be the correct details for that "version" of the view.
So I think it's all working nicely now - as long as you're using the Views code from HEAD. But the story of Quick Tabs' aspiration to awesomeness does not end there - not by a long shot. There have been massive improvements to the code as well as several great new features and usability improvements for which I sadly cannot take credit. No, that goes to Pasqualle, my new co-maintainer who has really transformed the module into an extremely powerful tool. He ripped out my ridiculously code-heavy "two forms for two different quicktab types" idea and replaced it with one form that allows you to choose whether your new (or existing) quicktab block should be ajax driven or not, and presents you with four (FOUR no less!) options of content for each tab: block, view, node or ... wait for it... quicktab. Yes, you can now nest a quicktab inside a quicktab. And yes, when I put this on the demo site a curious user did try the crazy idea of nesting the same quicktab within itself and yes, this did result in a giant black hole leading to the implosion of the entire site. So I have since added some validation to protect against that. Oh and you can now create quicktabs programmatically and you can have a different style for individual quicktabs blocks rather than one style for all and you can clone quicktabs and there is RTL support and there are more styles to choose from and... and... and... All thanks to Pasqualle.
There's an RC1 release up which is fairly stable, though it doesn't contain that all-important anti-black-hole protection and some other improvements (e.g. progress bar for ajax-loading content) have also been made subsequently. I'm not sure when the next ultra ultra stable release will come out but I really just wanted to get the word out there about this in the hopes that more people will give it a spin and provide some feedback. The next major feature request to be tackled is Panels integration (Panels 3 I guess, right? hmmm, I have a steep learning curve ahead of me...) Anyway, you can see Quick Tabs 2.0 in action here.