Permalink
Fetching contributors…
Cannot retrieve contributors at this time
125 lines (89 sloc) 7.16 KB

Understanding and using the eRegulations Backbone Application

How is content identified?

Regulations are very large and structured documents. The application loads regulations section by section. Sections and paragraphs can also have different applications outside of the flow of reg text. For example, a paragraph will define a term, and so we sometimes display this data outside of the content area (in the sidebar) in its other context - as a definition.

The id of a piece of content is a dash-delimited string containing the section, part and paragraphs that identify the content in the regulation. To learn about this structure, see pages 5 and 6 of this PDF.

For example, section 1005.2(a)(3)(iii) would have the id 1005-2-a-3-iii.

How does eRegulations’ Backbone layer receive data?

The Backbone application does not consume an API. Everything that makes eRegulations unique relies on layers of transformations to the plain regulation text. These transformations happen server side. The application pulls in rendered partial templates from Django. The application is agnostic about the content itself but relies on ids and certain data attributes in the markup for context.

How is Backbone used?

eRegulations uses Backbone in a non-standard fashion. It uses the following Backbone components:

Models

eRegulations’ Backbone Models do not sync data in a standard Backbone way. Because data only needs to travel one direction, from the server to the client, we do not use built-in events to trigger standard data sync processes.

The model caches data in a key-value pair. The key is the id of the section and the value is a string of HTML containing the content. Example:

{
    '1005-2-a': '<li id="1005-2-a">Paragraph content</li>'
}

All models inherit from meta-model. The cycle of a model is as follows:

  • A view is created for a piece of content. The view calls get() on its model.
  • The model checks to see if it has the content cached in memory.

If not:

  • The model constructs a URL to request data from the server and makes the AJAX request and creates a Promise object
  • When the Promise resolves:
  • A callback passed from the view is called
  • The newly-fetched data is cached

If it is:

  • The model retrieves the relevant value from its key-value store by the id passed in and returns the value

Views

There are two levels of views: content area views and content views.

Content area views

There is one of these for each area of the UI:

These views are responsible for creating and removing subchildren that hold content. It also handles loading states as applicable (ex: translucent overlays over loading content).

It builds the configuration object that is passed into the child view’s constructor. In Backbone, this is this.options in the child view’s constructor. This object is used for many things, including context to events that occur during the creation of a new child view.

Content area views are, by convention, singletons. They are initialized on app initialization.

Content views (child views)

All main content area child views inherit from ChildView. Content views are responsible for reacting to user input on the data. A content view is created to display a particular piece of content and is removed once a user navigates away from that content.

View Document Structure

eRegs Views

  • /header Contains top header banner and sub header that is in line with drawer/navigation

    • header-view.js
      • sub-head-view.js (Subpart "X")
  • /drawer This is the left-hand navigation listing of regulations.

    • drawer-view.js
      • drawer-tabs-view.js (top tab icons)
      • toc-view.js (default drawer view, table of contents)
      • history-view.js (regulation timeline)
      • search-view.js (search)
  • /main This presents the main content area (right of drawer/navigation)

    • main-view.js
      • reg-view.js (regulation page)
      • diff-view.js (diff version of regulation)
      • search-results-view.js ("Searching for 'foo'")
      • child-view.js (base class for main-view.js child views)
  • /sidebar This is the sidebar on the right hand side

    • sidebar-view.js
      • definition-view.js
      • sxs-list-view.js (section by section analysis)
  • /breakaway

    • breakaway-view.js
      • sxs-view.js

Events

None of the events built into Backbone are used. As the flow of the eRegulations application is different from a vanilla Backbone application, we use custom events.

Each content area view has an associated events router. By convention, each view - both content area and child views - know its associated event router as this.externalEvents. It is intended that all communication cross-content area happen through these event routers.

To understand the cycle of any view, look at the methods bound to events in the view’s constructor. Event handlers are bound with Backbone’s on(). Events are triggered using Backbone’s trigger(). Event names follow the Backbone convention.

There are five distinct modules, one for each content area. They are all clones of Backbone.Events with no modifications.

How should I add a new feature?

The intention for this JS application is that, as new ways to parse, glean context and display the data become possible, it can easily flex to meet these needs.

To develop along the grain, so to speak, you should consider the following:

  • Can I employ the existing pattern of content area and content views to my new feature?
  • Can I develop the new feature without adding an explicit state to the application? Can my new feature simply respond to events w/o other modules knowing about it?
  • Can the way this feature is developed neatly fit into the existing event stream?
  • Can I create this without making any transformations to content client side?