Asynchronous module: 100% AJAX Drupal

Events happening in the community are now at Drupal community events on www.drupal.org.
recidive's picture

We have seen a lot of interest in making Drupal load content dynamically. This enables many use cases not currently possible. E.g.: on a past project, we have been asked to make a video player play continuous, while the user browses the site. On a Drupal 5 site, the only way to do this was using frames, and frames sucks.

Some improvements were done in Drupal 6 to pave the way for AJAX. We got dynamic form submissions (AHAH), jQuery forms library and javascript behaviors can now be re-attached. On the server side, however, things haven't achieved such maturity.

It has been a while since I've started to code a module with the ambitious purpose of making Drupal work 100% asynchronously. This is a challenging task, and this was the main motivation I had to give it a try. The result of this effort is Asynchronous module.

Besides all the coolness Asynchronous module provides, it also serves as a indicator of how ready Drupal is to do that kind of stuff, and to detect its flaws/limitations in order to propose some enhancements to Drupal 7 to make that task easier to accomplish.

The module is somewhat stable and usable, but not feature complete yet. It's known to work on Firefox 3 and Safari 3. It currently features dynamic loading of all pages elements (sidebars, primary/secondary links, footer) as well as page main content, form submition and browser history handling (back and forward buttons work!).

For the module to work, it requires a theme that implements asynchronous functionality. Currently only Chrysalis theme does this (support for core themes is planned). We need this, since asynchronous module relies on jQuery selectors to place dynamic loaded content, and since themes structure (css classes, ids, main content) vary between themes, we can't provide a single set of rules that will make it work across all themes.

Here is a report of what I felt Drupal core could do better:

First of all it's not an easy task to make Drupal render pages in other formats than html. The rendering/template system is somewhat hardcoded to produce pages in html. To make pages render in JSON format as required by asynchronous module, I have to implement hook_render_template() on behalf of phptemplate engine, since apparently there is no way modules can do this, only themes can.

Another tricky thing was the one I've come together in order to make drupal_goto() persist the requested renderer between page redirects, e.g. when submitting a form. I did this in a hook_exit() implementation, but since this doesn't allow you to alter the query string when redirecting, I had to direct redirect from there, using header(), skipping standard drupal_goto() redirect.

Not every Drupal behavior is really re-attachable, so there are still some things broken/partially broken. Things like fixed tableheader, and a few other behaviors can't really be added to dynamic loaded content. Also, color module will not work this way.

Client side code (javascript) limitations are often easy to workaround. But server side ones are sometimes infeasible.

Luckly, I was able to workaround all (or almost all) server side limitations, and this resulted in Page Renderer module, a module which Asynchronous module depends on.

The top enabler issue is Enable loading and rendering into JSON, XML, etc.

100% AJAX Drupal is possible and with a few improvements to core we can make it work clean and seamless.

Check out Asynchronous module demo!

Comments

bravo

Veggieryan's picture

I am very impressed by the demo, and the direction you are taking.

This is whats needed to make drupal competitive.

Nice work! And a suggestion for theme support

nedjo's picture

Nice work Henrique. This is very valuable for working through problems and solutions. It would be great to see your Drupal core points translated into issues.

Re the problem of theme support, did you see the approach I sketched in in dynamicload? I used drupal_set_content() and hook_help() to add markers to all the regions and the main content area:

<?php
/**
* Implementation of hook_help().
*/
function dynamicload_help($section) {
 
$return = array();
 
// Add marker to every page.
 
if ($section == $_GET['q']) {
   
$return[] = '<div id="dynamicload-content-marker"></div>';
  }
  ...

}
?>

<?php
/**
* Set a marker div in a given set of regions.
*
* These divs can be used from Javascript to update regions with dynamically
* loaded content.
*/
function _dynamicload_set_region_markers($regions) {
  foreach (
$regions as $region) {
   
drupal_set_content($region, '<div id="dynamicload-region-'. $region .'" class="dynamicload-region"></div>');
  }
}
?>

<?php
   
// Insert dummy content that will be used to select the region container.
   
$regions = array_keys(system_region_list($theme));
   
// The left and right regions are handled separately in dynamicload_load().
   
unset($regions['left'], $regions['right']);
   
_dynamicload_set_region_markers($regions);
?>

Then in the js:

  // Add classes to region wrappers.
  $('div.dynamicload-region').each(function () {
    var regionId = $(this).attr('id');
    $(this)
      .parent()
      .addClass(regionId)
      .end()
      .remove();
  });
  // Automatically detect main content wrapper if the default setting is not available.
  if (!$(Drupal.settings.dynamicload.settings).size()) {
    Drupal.settings.dynamicload.content = $('#dynamicload-content-marker')
      .parent()
      .parent()
      .addClass('dynamicload-content').get(0).nodeName + '.dynamicload-content';
  }

I don't think it worked perfectly--users noted that my empty divs sometimes messed up their layout, I guess when certain regions were rendered only if they were not empty (and the div elements meant they were not empty). But something along these lines might be worth exploring.

Very Cool

starbow's picture

This is very cool.
I was wondering how you have dealt with the Form API -> drupal_goto problem. I keep running into this with the Popups API (which has a lot of overlap with what you are doing here). I put together a D7 patch that made the drupal_goto overwritable, but it was part of the huge (and stalled) popup patch. I have been thinking of breaking it out, but wonder if you have a better solution.

Set $_REQUEST['destination']

nedjo's picture

In ajaxsubmit I've handled this by explicitly setting $_REQUEST['destination'] to an ajax responder callback.

great job

fabrizioprocopio's picture

great job

Demo site is not working

vojnar's picture

I tried to acces your demo site but it is not working!

Thank you,
Gabor Vojnar
Weboldal.biz Weboldal Készítés

I'd love to check out the

Nick Robillard's picture

I'd love to check out the demo too. I need to achieve something similar and this looks the most promising so far...

Asynchronous paging problem

mahyarsbt's picture

hi

very thank you for your cool module

i used drupal 6.19, installed latest page_renderer and Asynchronous module

its work but in my story content paging not work

when i click "next" or "page 2" display error:

page can't find
The requested page could not be found.

http://localhost/mystorysite/#category/textcontent/shortstory?page=1&pag...

please help me

Javascript

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds:

Hot content this week