Fork me on GitHub

Desligado

simple web application supporting
disconnection and deferred updates

Desligado is a proof-of-concept application made by junior developers.

It's a simple CRUD web app that runs both online and offline. Since it is meant to work when the client is disconnected from the web, and/or when the server is unavailable, it is heavily javascript based. Despite having a view for each one of the common actions (show, index, new and edit), it's a single-page application, since all necessary code (HTML, Javascript, and CSS) is retrieved with a single page load. Further communication is made using Ajax and HTML5 Web Sockets with JSON.

The resources are cached thanks to a HTML5 Cache Manifest file and the client keeps a synced local version of the data on a HTML5 WebSQL database (or, if not supported by his browser, on his Local Storage).

Demo

This video shows some of the features (check the specification chapter) and bugs (check the issues list). Music by B Fachada.

Index

  1. Specification
  2. Dependencies
  3. Downloads
  4. Supported Browsers and Caveats
  5. The Application
    1. Core technologies
    2. Javascript MVC framework
    3. Data synchronization
    4. Server Pushing
    5. Directory structure
  6. Initialization
  7. Usage
  8. Issues
  9. Change Log
  10. Contribute
  11. Authors

Specification

Desligado is a simple item management application. Those are the functional requirements:


Dependencies


Downloads


Supported Browsers and Caveats

Should work with, at least:

It doesn't seem to work on Safari 5 (not fully tested), and Firefox will use local storage instead of WebSQL. Beware that, if the HTML layout file contains the reference to the application manifest, server pushing will not work. Comment out the reference <... manifest="application.manifest"> or just remove the public/application.manifest file to try it. This is a known issue.


The Application

The goal for this project was to create a multi-client simple web application with some basic functionalities (the creation, manipulation and deletion of shared items) that worked both online and offline.

Core technologies

T

o achieve the behaviour of keeping functionality in offline mode, we used several techniques introduced in HTML5 — Cache Manifest, WebSQL, Local Storage and Web Sockets.

Starting with the cache manifest, since we used Ruby on Rails for our back-end, to dynamically generate this manifest file we used the rack-offline gem, as suggested by Ryan Bates on his interesting railscast. Every time the user opens the website, all files required by the application are downloaded and saved for offline browsing. This solves the problem of accessing the static content in offline mode.

Another important aspect is that only one HTML page is fetched from the server. This page contains the necessary components to generate four views — index, show, edit and new. We used backbone.js and underscore templates to build them. Backbone.js let us implement a well-structured client-side application, but is not so rigid opinionated as Rails. To organize our client-side code, we followed the approach designed by James Yu on his article about backbone.js.

Javascript MVC framework

B

ackbone is composed by several modules. It contains one module called Backbone.sync which lets us persist data through RESTful JSON requests to the server. Since we want it to work offline too, we need it to persist the data locally, using the HTML5 WebSQL technology (if supported by the browser) or the Local Storage. This would be synced to the server, if possible, when both client and server are online. This is tougher than it may look, since we are talking about a multi-client app, with desynchronized clocks, etc..

Data synchronization

I

n what concerns persistence, we used persistence.js, and specifically the persistence.sync.js plugin, to keep the databases synced together. We created an adapter, a new Backbone.sync module, which maps the CRUD actions with the persistence.sync.js library's API.

Another problem is that persistence.sync was primarly made to communicate with node.js servers. Since we are using Rails, we coded the necessary mechanisms to make it work with RoR.

Server pushing

A

t last, we wanted the server to broadcast to all connected clients when one of them modifies the server's database. We integrated Faye for the server->client communication, which uses WebSockets, XMLHttpRequest (if WebSockets not supported) or JSON-P (if no other alternative is supported). We are still having some crazy issues regarding having both Faye and the application.manifest) which are listed on the bottom of this document.

Directory structure

app/
    controllers/
        application_controller.rb
        home_controller.rb
        items_controller.rb
    models/
        item.rb
    views/
        home/
            index.html.erb
        items/
            edit.jst
            index.jst
            show.jst
public/
    javascripts/
        app/
            collections/
                items.js
            controllers/
                items.js
            models/
                item.js
            views/
                edit.js
                index.js
                notice.js
                show.js
            application.js
            server.push.js
            sync.js

Initialization

To initialize the application, run:

mv config/database.yml.sample config/database.yml
mv public/application.manifest.sample public/application.manifest
bundle install
rake db:migrate

Usage

Run Faye:

rackup script/faye.ru -s thin -E production

Run the Rails sever:

rails server

Issues

A list of the current issues will be added soon.


Change log

For now, you may check our github page to keep track of all the undergoing changes.


Contribute

Feel free to use the code for your own projects. Improvements are very welcome (keep in mind that we are junior developers, with no background on Javascript, asynchronous programming and all the like). Pull requests to our git repository would be greatly appreciated!


Authors


This template was inspired by the work of DocumentCloud. Background image is from SubtlePatterns. Drop Caps from ReusableArt.