This page does not describe longwell/trunk. Do not rely on the information on this page at this time.

Longwell exposes a Web API for web pages to embed and drive Longwell. Embedding Longwell involves linking to a few Javascript and CSS files and calling a few functions when your HTML page has loaded. Driving Longwell involves calling methods on its Javascript objects. The part of Longwell that you deal with on the client-side, i.e., within your web page, will be referred to as "client-side Longwell".

Contents

Architecture

Client-side Longwell is implemented in dwell/dwell/resources/api and has 3 components:

  • the query engine component (scripts/query-engine.js, et. al.), responsible for keeping track of the current faceted query and for notifying interested parties of changes to that query
  • the history component (scripts/history.js), responsible for keeping track of user actions and responding to the Back and Forward button of the browser
  • the user interface component (scripts/ui.js, et. al.), responsible for rendering the user interface, keeping it in sync with the current faceted query, and responding to user inputs

Client-side Longwell uses the same trick as Timeline to include its various Javascript and CSS tidbits into the containing web page. Right now, see dwell/dwell/templates/commands/ui.vt for how to include Longwell.

Query Engine Component

The query engine keeps track of the current faceted query, which consists of 2 collections of facets:

  • the root facets: which encode facet refinements that are typically resulted from sliding actions. Root facets define the sub-universe of things from which the user can refine. Root facets cannot be changed except by sliding UI mechanisms, which are not yet implemented. In short, ignore root facets for the time being.
  • the current facets: which encode facet refinements that are resulted from conventional faceted browsing. The current facets are changed as the user interacts with the facets in the UI.

Facet collections are implemented in scripts/query-facet.js. A facet collection consists of zero or more query facet (implemented in the same file). The term "query facet" is used here to distinguish it from the term "facet" used in discussing the UI. There are 4 types of query facet:

  • nested facet: used for sliding, ignored for the time being
  • list facet: a facet in which refinement involves choosing distinct values
  • range facet: a facet in which refinement involves choosing ranges (date, number)
  • text facet: a facet for text searches

Each facet is identified by its type as well as the relevant RDF predicate and whether that predicate is used forward or backward in queries. (The normal direction is forward: items to refine are subjects and facet values to select are objects.) Each facet has an array of selections. For a list facet, each element of that array is a Javascript object with a single field called value storing the selected facet value encoded as a string. For a range facet, each element of that array is a Javascript object with a field called min storing the minimum value of the selected range (it can be null to refine for items missing data) and an optional field called max storing the maximum value of the selected range (if min is not null). For a text facet, each element of the selections array is a text string the user has searched for.

Query facets and facet collections can be serialized to XML and deserialized from JSON.

Modification to the faceted query in the query engine should be done by calling the method createTransaction on the query engine. This is so that notifications are sent out from the query engine in batch rather than for individual changes. Take a look at the methods on Longwell.QueryEngine._Transaction to see what changes are allowed.

The server-side counterpart of the query engine is in longwell/trunk's edu.mit.simile.longwell.dq (dq stands for dynamic query). Right now the code in that package translates the faceted query coming from client-side Longwell into the existing Longwell's query model (i.e., projector, bucketer stuff). This whole package could potentially be revamped to work on Sesame 2 alpha 4's more powerful query model while leaving Longwell's old query model undisturbed.

IMPORTANT: Note that there is nothing on the server-side to keep track of the faceted query on the client-side--the server is stateless. The so-called query engine in client-side Longwell merely keeps track of the query and notifies other parts of client-side Longwell of changes to the query. It does practically nothing else--it does not retrieve the result set for that query. The other parts of client-side Longwell make specific XmlHttp calls to server-side Longwell (with the faceted query serialized in their requests) in order to get specific data for that query (e.g., result items, available facet values). Different parts make different calls independently of one another.

History Component

The History component installs a small, hidden iframe on the web page and uses it to catch the use of the browser's Back and Forward buttons. The iframe is loaded with a dummy html whose URL carries a number pointing into the history's stack of actions. When an action is executed by client-side Longwell, the history component updates that number, causing the iframe's new URL to be pushed onto the browser's history. Thus, the browser's history grows as the user interacts with client-side Longwell. When the browser's Back or Forward button is invoked, the iframe's URL is changed by the browser and that change triggers the history component to execute actions on its own stack in the forward or backward direction. (This trick doesn't work on Safari.)

All undo-able user actions should go through the History component. Call the method addAction passing in a Javascript object with 2 fields, perform and undo. Both fields are functions that take no parameter.

User Interface Component

The UI consists of 3 panels

  • the control panel, which is sitting on top left by default and currently contains the Add View button
  • the browse panel, which is sitting on the right by default and contains the browsing controls (facets and text search)
  • the view panel, which hosts views

These 3 panels behave differently when there are some refinements and when there is none. For example, when there is no refinement, the view panel shows all types in the profile and lets the user start browsing by choosing a type (this is only one way to start off).

The user interface is the component that makes the most XmlHttp calls to the server-side Longwell. These calls are made through the method callAPI on the Longwell object and are responded by Velocity templates in dwell/dwell/templates/api/.

Browse Panel

The browse panel is implemented in scripts/browse-panel.js, scripts/list-facet.js, and scripts/range-facet.js. When a facet value is selected, the facet calls on the browse panel's queueChangeFacetSelectionAction method, passing in a function that would take a transaction and call a method on that transaction. These change-facet-selection actions are queued up until the browse panel is no longer waiting for any XmlHttp response. Then the browse panel creates a new transaction from the query engine, gets all these change-facet-selection actions to change that transaction, and then commits the transaction. Once the transaction has been committed, the query engine notifies various parties including the browse panel. The browse panel then issues an XmlHttp request to attempt to update the facets.

View Panel

The view panel is implemented in scripts/view-panel.js as well as in the various file in scripts/views/. Each view installs its own listener on the query engine and is responsible for updating itself.

Layers

The whole user interface has the concept of layers. Dialog boxes and menus, for instance, are popped up on layer 1. If something in a higher layer is not modal, then UI events in lower layers pop them off (e.g., cancelling popup menus). On the other hand, if something in a higher layer is modal, it cancels event handlers of UI elements in lower layers (e.g., when a modal dialog box is up, the facets can't be changed). Finally, when the user invokes the Back or Forward button, all layers except for layer 0 are automatically popped off. In most cases, please register your event through the UI object so that these behaviors can be enforced consistently.