Implementing the admin interface prototype and using Pushstate Assisted Navigating (PAN) in Drupal

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
JurriaanRoelofs's picture

I've been following Lewis' developments with the prototype and talked to some people about how to implement it and I think it's possible but to do it right will take a lot of work.

I would like to share my notes on this and make a suggestion to discuss pushstate-ajax (pjax) in Drupal, because as browser support is improving I think this will be the technology that allows websites (webapps) to catch up with native apps in terms of speed, responsiveness and scalability.

Background

In the prototype lewis made, when you click a link new content is ajax-loaded into the current window, meaning that assets and layout (or peripheral content) do not have to be downloaded every time you navigate. As opposed to old AJAX apps this prototype uses clean urls instead of fragments. The url fragment is the mess you get after the # sign when you navigate an old-school AJAX interface like the Drupal overlay module. Fragments are a temporary solution to reflect the application state in the address bar of the browser and they are much less attractive than regular urls. Regular urls are more permanent, more consistent, more SEO friendly and from a developers perspective just more awesome.

That's why (I think) w3c has given us the History API, if you're not familiar you can read up on it here: http://diveintohtml5.info/history.html

The Admin interface prototype

The prototype uses Pushstate Assisted Navigation and it has a sliding UX pattern that reminds of a camera panning motion so we can extend the PAN abbreviation and call it PANNING.

Currently the prototype works by AJAX-requesting full HTML documents and then extracting relevant content and merging that content into the current window:

Zepto.fn.loadInPage = function() {
  var o = $(this[0]) // It's your element
  var href = o.attr('href');
  var url = href + '/ #wrapper';
  var currentPage = $('.slider > li.current');
  $('body').addClass('ui-loading');
  currentPage.load(url, function() {
    $('body').removeClass('ui-loading');
    removeFutureSteps();
  });
}

Improvements

What would be better is to have the server return only the contents of #wrapper so that we get a very small datastream and consequently a superfast interface. If Drupal could do this, this would give significant speed benefits to the admin interface, but super-awesome speed and scalability benefits to sites that also implement it in the frontend.

The nicest showcase of this technology is github, github uses PANNING navigation in the code browser: https://github.com/jjroelofs/jQuery-SooperFish. Notice how there is no url fragment used when AJAX-loading in the themes folder.

When done right, this also makes the backend work less hard, because it doesn't have to generate and theme all the peripheral content, layout HTML etc. To get the full backend benefits, you need a system that does a lazy-loading bootstrap and only loads the includes/modules that are relevant to generating the content inside the #wrapper div. Luckily, this is already on the roadmap of the Symfony integration and I think the WSCCI initiative.

To pull it all together the backend and frontend (javascript) in Drupal must be able to do the following:

  • Send an HTTP header to indicate a pjax request. When this header is not present (e.g. because internet explorer is used) the interface falls back to non-AJAX navigation with full page requests.
  • Menu router must process request differently based on presence of pjax HTTP header contents, is menu router even going to be in Drupal 8?
  • Decide if new assets need to be loaded (e.g. css files) and load them
  • In the browser window: Update the page title, address bar, show a throbber
  • Report a pageload to Google Analytics or whatever tracking software is used

Luckily most of the above, even Google Analytics support is already done by this library called pjax: https://github.com/defunkt/jquery-pjax/blob/master/jquery.pjax.js
If we implement PAN in Drupal code we may choose to include pjax in core or write a similar interface to support HTML5 History API in the menu router, or whatever router we will have in Drupal 8.

I would like to hear from people involved in these initiatives if they think the above is feasible to get ready in time for us to use it in the admin interface.

Some points to consider

  • Browser support is good but not perfect. However, by the time Drupal 8 goes live I'm sure it will be fixed. Especially now that Chrome is available in ios and android. (The Android browser has buggy support for pjax).
  • Django and rails already implemented pjax, let's do it and do a better job at it.
  • Some patterns in Drupal could immediately benefit from pjax in core, book module, paged views, "in-line" editing of content blocks and nodes would be possible this way etc.

Comments

subscribing

marcrobinsone's picture

Now reading reference materials ... Subscribing

@Marc - FYI, thats not the

moshe weitzman's picture

@Marc - FYI, thats not the preferred way to subscribe to posts on GDO. Please use the subscribe links at bottom of the post. In the future, subscribing will be even better

Re: subscribing, participating

marcrobinsone's picture

@Moshe, Thanks for the reminder. I'm particularly aware of the process :)

However in this case, I'm merely stating my state of mind -- that is I'm subscribing to the whole thing ... like watching the GitHub code/project | following the topic on gPlus/twitter

Which reminds me: @Jurriaan - are we able to build an environment or setup to test this on our own?

Not right now all there is,

JurriaanRoelofs's picture

Not right now all there is, is this motion/discussion

This sounds exciting,

Bojhan's picture

This sounds exciting, wondering what the impact is on accessibility. I would really love to see us improving our speed.

Very positive

LewisNyman's picture

This sounds like a very positive proposal. I'd love to see a well thought out implementation of this. Seeing as the worst case support scenario is we just degrade back to how it is now I don't think we need to worry about wide spread support.

@Bojhan, AJAX loading requires some active work to ensure accessibility but it is possible.

Here is a list of some javascript touch libraries that could help us implement gestures system wide:
https://github.com/bebraw/jswiki/wiki/Touch

View from WSCCI

Crell's picture

Moshe asked me to weigh in here. Two points:

1) Let's also bear in mind that PJAX should be an option, not the default setup. There are plenty of use cases where you do want the secondary stuff to change, or what qualifies as "secondary" may be unconventional. It should not be difficult to fall back to "traditional".

2) This is exactly the sort of hotness that we want to enable with the WSCCI/SCOTCH/Symfony architecture. :-)

We already have part of this implemented via the Ajax replacement system. It's just a fugly implementation. That already needs to get cleaned up. See: http://drupal.org/node/1533366#comment-6218406

(And someone please go work on that!)

I think this system could be reasonably built on top of that. Something to the effect of:

1) Link gets intercepted in Javascript when clicked on.
2) A request is sent to the server:

GET /node/5
Accept: application/vnd.drupal-ajax

That gets picked up by the server and routed to a controller that creates a Response object that contains a series of commands, much as the current ajax system does. Those commands include a blob of HTML to drop into the #content area (or something like that), any JS or CSS to add to the page... and any push-state commands to issue. So if you sent back something along the lines of:

HTTP 200 OK
Content-Type: application/vnd.drupal-ajax

{
  'replace': {'#content': '<some html here>'},
  'history': 'node/5'
}

Then #content gets replaced with new stuff and the history gets updated, if the browser supports it. I'm not sure what sort of munging we want to do on the URLs; that's still being debated, but you get the idea.

We're trying to enable that on the server side. It still needs work to get there, and at this rate I expect PJAX will have to be a contrib tool. For now, we need to focus on the plumbing. Most important for that are:

The new routing system: http://drupal.org/node/1606794 (reviews needed, coders needed)
Rewriting Ajax to make use of Request/Response: http://drupal.org/node/1533366

And moving more things over to the DIC, so that they can lazy-initialize and lazy-load, which gets us a lower bootstrap cost.

If you want PJAX to be viable in Drupal 8 (and I do), those are the places to focus right now.

Thanks for your feedback

JurriaanRoelofs's picture

Thanks for your feedback Crell. I was afraid the answer would be something along the lines of "Drupal first needs to work with Symfony before it can work at all". I say afraid because I'm afraid I haven't got the Symfony/OOP skills to be very useful in those issues.

The best course of action for D8MUX will be to implement the full-page loading version of the prototype and then see if we can make it faster with partial page-loading PJAX before code freeze comes up.

In the mean while I'll keep an eye on the menu_router and Symfony-Ajax issues and I'll jump in once the system starts taking enough form for me to see how it works.

Mobile

Group organizers

Group categories

Mobile

Group notifications

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