History.js integration for Drupal

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

Hey everybody, I wanted to let you know about some exciting projects I'm working on - The first of which is already live here on d.o (History.js for Drupal), and adds the History.js library to Drupal 7.x via the Libraries API. The second (and more exciting) project that I'm working on is called StateHandler and is detailed below.

History.js for Drupal
History.js creates an "almost native" implementation of html5 pushState and popState that enables back and forward button support for ajax applications, and unifies the behavior across all browsers, falling back to location.hash (or hashbangs #!) where popStates are not fully supported. Please check out the History.js library on Benjamin Lupton's github.

StateHandler
Is a concept that works with History.js for Drupal to provide an easy to use plugin interface for Drupal to the History.js Library. When combined with the Services module's Rest Server (3.x branch), the results are quite powerful. The Statehandler Project doesn't live on drupal.org yet (it will after some more testing), but you can find it on QorvisDigital's github. The idea is that through implementing a simple javascript class (StateHandlerPlugin) with only 3 simple methods (Hooks) and some click handlers, you can build a full featured, friendly-url'd ajax application that supports forward and back buttons out of any Drupal site.

The idea is that any site can run multiple StateHandler plugins to take care of various functionalities of a complex ajax application. Each plugin will extend/modify the global state object in order of it's defined weight, and will know how to act on the data it generates (for example one plugin might define a process for calling the views service with specific arguments, and then render the results in #main .content).

Today, a coworker of mine with no previous experience with the projects installed them, and was able to create his own plugin that queried the views service within about 5 minutes.

I'd like to see what ideas this community might have for making the StateHandler interface as strong as it can be, and what you think some goals to meet before releasing this project as a full d.o project might be. Thanks, I look forward to hearing everybody's ideas!

Comments

Escaping the page

ransomweaver's picture

I think this is a very important effort at tackling a difficult problem; overcoming the arbitrary division of the application into finite states, with the page load as the transition between states. Coupled with D8's focus on REST in the webservices and context core initiative (http://www.garfieldtech.com/blog/web-services-initiative) I can see that Drupal is headed towards a place where the page can be more of a stage.

As a developer I've been pondering these last few months how best to execute in Drupal the kind of project that brought me a lot of business in 2010 and so far nada in 2011: Flash portfolio sites with deep linking and backbutton navigation. The rise of the iPad has completely killed this for me, and I had done some really nice work, including winning an FWA.

My preferred mode of working in Flash is to use the Gaia Flash framework: http://gaiaflashframework

  • comes tightly integrated with swfaddress to provide deep linking into the flash app
  • is composed of layered/nested swfs ("pages") that are managed by an xml file that defines the site structure, with each state of the app represented as a "branch"
  • has an api for asset loading and management
  • has a "flow" that governs the transitions between pages: http://www.gaiaflashframework.com/wiki/index.php?title=The_Gaia_Flow e.g.
    transitionOut: Transitions out all current pages that do not belong to the new branch.
    preload: Loads all the files needed for the new branch.
    transitionIn: Transitions in the pages of the new branch. Obviously, preload must complete before this can occur.
    complete: Occurs once the flow is complete.

  • has events to hook into the flow, and a means to "Hijack" the flow (interrupt the flow while you do something, then release the flow when completed)
    e.g.
    beforeTransitionOut(target:Function, hijack:Boolean = false, onlyOnce:Boolean = false):Function
    afterTransitionOut(target:Function, hijack:Boolean = false, onlyOnce:Boolean = false):Function

where these functions live in a class that controls one of the parts of the branch that makes up the page being transitioned out. (example branch: site/index/nav/landing/gallery)

In practice this means that the app has a button to cause some change in the app state, and pressing it does not directly call the functions that cause the state change, but instead calls e.g. Gaia.goto('sites/index/nav/landing'); and this kicks off the "Gaia Flow".

I'm not suggesting this should be the Drupal Way, but something like this could be implemented in order to make accessible to the developer the underlying Drupal datastructures in a coherent way that does not depend on page loads. Without it, every attempt at this is a major project from scratch, ala the Overlay module in D7. With an api, transition hooks and events, the developer can focus on the behavior of the app and be in full control of how the app moves from one state to another.

I'm a big fan of defining a

rypit's picture

I'm a big fan of defining a js class to interface with drupal in a meaningul way. It seems like ajax.inc could provide some useful tools for things like dependencies handling too.

I agree that each 'plugin' should be responsible for building application data specific to it's own functionality from a URL, which is the premise of the buildstate method I've built into the statehandler system, but I also like the idea of providing defaults for things like transitions, and I'm especially fond of the 'hijack' functionality in Gaia.

I've recently started toying around with the idea of a 'region' resource for the services module. the idea is that we should be able to do something like:
Link clicked -> build state data from URL -> request data from specific region at the new URL -> cache/render results using specified presets or a custom animation.

I think that at the end of the day, working this way with regions and blocks (comtexts?) is ultimately the most 'drupaly' way to do this. Imagine configuring all your application states using the same configuration you define in a typical build. This would allow webmasters and site builders to define what happens where without any code. I have a very rough prototype I'm workin on for this service now, that mirrors almost verbatim drupal_render_page, instead returning a keyed array of page elements passed through drupal_render. It's still under testing, but please let me know what you think: https://github.com/QorvisDigital/services_regions

Javascript

Group notifications

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