Skip to content

Developer Scripted API

zepheiryan edited this page Jan 21, 2012 · 13 revisions

Developer Scripted API

This documents APIs developers can use when writing new components for Exhibit 3.0 Scripted.

Registry

The Exhibit Registry keeps track of all loaded components in a centralized place. There are two main instances, one for static components that do not depend on Exhibit initializing, and one for initialized components that do depend on Exhibit initializing.

Static:

  • Exporters
  • Importers
  • Localizations

Initialized:

  • Views
  • View Panels
  • Facets
  • Control Panels
  • Coders

A registry is comprised of registered components with a hash of instances of each component. Exporters and importers are hashed according to their MIME-type, others by a unique identifying key.

The registry supplies the following methods:

  • isStatic() returns boolean
  • createRegistry(component) where component is a string key returns boolean for success
  • components() returns an array of component keys
  • hasRegistry(component) returns boolean if the registry for the component exists
  • generateIdentifier(component) returns a repeatably unique numeral based on the size of the component registry
  • isRegistered(component, id) returns boolean if the instance of the component is registered
  • register(component, id, handler) takes the component key, the instance identifier, and the actual instance, returning boolean for success
  • componentHandlers(component) returns an associative array of instance identifiers and instances
  • getKeys(component) returns just the keys of instances for a component
  • get(component, id) returns the instance requested, or null if non-existent
  • getID(id) only applies to the static registry, returning the instance associated with the ID regardless of component
  • unregister(component, id) removes the instance from the registry, returning boolean for success

Example

The following shows how to register a static component and an instance of the static component.

var ExampleComponent = {
    _registryKey: "examplecomponent";
};

$(document).bind("registerStaticComponents.exhibit", function(evt, staticRegistry) {
    if (!staticRegistry.hasRegistry(ExampleComponent._registryKey)) {
        staticRegistry.createRegistry(ExampleComponent._registryKey);
        $(document).trigger("registerExampleComponents", staticRegistry);
    }
});

var GreatExample = function() {
    var self = this;
    this._type = "great";
    $(document).bind("registerExampleComponents", function(evt, staticRegistry) {
        staticRegistry.register(ExampleComponet._registryKey, self._type, this);
    });
};

var great = new GreatExample();

Database

Interacting with data is through the database API. Details around database creation and modification are elided here; working with data selection mechanisms is primarily how developers will interact with the database. Not all methods are described here, see the generated documentation or code for less commonly used methods.

General

  • containsItem(id) returns boolean if the database contains the item identified by id
  • getAllItems() returns all items as an Exhibit.Set()
  • getAllItemsCount() returns the number of items in the database
  • getType(id) returns an Exhibit.Database.Type identified by id or null if none
  • getAllProperties() returns all properties as an array
  • getProperty(id) returns an Exhibit.Database.Property identified by id or null if none

Selection

  • getObjects(subject, predicate, set, filter) fills the Exhibit.Set set with all objects of statements that match the subject and predicate, filtering out results using the filter Exhibit.Set
  • getObjectsUnion(subjects, predicate, set, filter) same as above, except subjects is an Exhibit.Set of several subjects to query against
  • getSubjects(object, predicate, set, filter) fills the Exhibit.Set set with all subjects of statements that match the predicate and object, filtering out results using the filter Exhibit.Set
  • getSubjectsUnion(objects, predicate, set, filter) same as above, except objects is an Exhibit.Set of several objects to query against
  • getObject(subject, predicate) returns one (and only one) object of a statement matching the subject and predicate
  • getSubject(object, predicate) returns one (and only one) subject of a statement matching the object and predicate
  • getForwardProperties(subject) returns an array of properties for statements that share the subject
  • getBackwardProperties(object) returns an array of properties for statements that share the object
  • getSubjectsInRange(predicate, min, max, inclusive, set, filter) fills or returns the Exhibit.Set set with all resources with property predicate values that fall in the min to max range (inclusive a boolean for whether the extremes count as part of the range), filtering out results using the filter Exhibit.Set
  • getTypeIDs(subjects) return an Exhibit.Set of all types associated with the Exhibit.Set set resources

Collections

needs writing

History

needs writing

Exporters

An Exhibit Exporter can take the existing selection of items and write in the desired output format. New exporters should register with a particular MIME-type and provide a label for the exporter, along with at least three methods: wrap, to wrap the entire output (e.g., RDF/XML needs the entire graph to be wrapped in an RDF tag), wrapOne, to wrap one item in the output (e.g., comma-separated values should end with a newline \n), and exportOne, to reformulate data associated with one item out of the database and format it (e.g., tab-separated values being queried and placed in the correct tab-separated order).

Constructor

Exhibit.Exporter(key, label, wrap, wrapOne, exportOne, [exportMany])

type can be any identifier; the MIME-type, when available, is a good choice.

exportMany is by default composed of wrap, wrapOne, and exportOne but can be overridden if the method of doing so should not rely on those three methods.

wrap should be a function(string, database, [extra]) where the content, database, and any extra arguments in an array returning a properly formatted string.

wrapOne should be a function(string, isFirst, isLast) taking one item's content and two booleans for whether it's the first or last item in the set returning a properly formatted string.

exportOne should be a function(itemID, database, [extra]) taking one item's identifier and its containing database, and any extra arguments in an array returning a properly formatted string.

exportMany, if provided, should be a function(set, database, [extra]) taking an Exhibit.Set of identifiers, their containing database, and any extra arguments in an array returning the entire properly formatted content.

The constructor automatically registers the exporter with the Exhibit static registry.

Example

var tsvWrap = function(contents, database) {
    return contents;
};
var tsvWrapOne = function(contents, first, last) {
    return contents + "\n";
};
var tsvExportOne = function(itemID, database) {
    // query database into item
    var vals = [];
    for (prop in item) {
        if (item.hasOwnProperty(prop)) {
            vals.push(item[prop]);
        }
    }
    return vals.join("\t");
};
My.Exporters.TSV = Exhibit.Exporter('text/tab-separated-values', 'Tab Separated Values Exporter',
    tsvWrap, tsvWrapOne, tsvExportOne);

Importers

An Exhibit Importer processes data and passes back an object appropriate for loading into the database.

Constructor

Exhibit.Importer(mimeType, loadType, process)

mimeType is the type or types of file the importer can handle. Use an array if more than one type. When using the JSONP framework, MIME-type is a bit of a misnomer; JSONP is generally handled by specifying a handler for the site as opposed to the type of data, so any unique identifier, not a MIME-type, should be used.

loadType is one of get, jsonp, or babel. The get option will perform a basic XHR GET for a plain text document. The jsonp option will use the JSONP framework and the handler specified in the page. The babel option uses the Exhibit babel option to request a translation from the given MIME-type to Exhibit JSON.

process should be a function(string) returning an object appropriate for the Exhibit.Database.loadData method.

The constructor automatically registers the exporter with the Exhibit Registry.

Example

// Dummy implementation ignores quotation mark considerations; do not actually use this
My.Importers.TSV = Exhibit.Exporter('text/tab-separated-values', 'get', function(str) {
    var props, items, lines, line, item, vals, i;
    items = [];
    lines = str.split("\n");
    props = lines.shift().split("\t");
    for (line in lines) {
        item = {};
        vals = line.split("\t");
        for (i = 0; i < props.length; i++) {
             item[props[i]] = vals[i];
        }
        items.push(item);
    }
    return { "items": items };
});

Views

An Exhibit View visualizes the available data. As a component, views cover a lot of territory, from collections to database to lenses and other UI-related matters. This documentation does not cover everything; your best guide is the existing code for views. A new type of view should extend the Exhibit.View class, using $.extend(this, new Exhibit.View("newtype", element, uiContext)); Review the Exhibit.View class to see what methods it provides, and note the following conventions:

  • this.addSettingSpecs(NewView._settingSpecs); should be called in the NewView constructor
  • this.register() should also be called in the NewView constructor
  • this._initializeViewUI() should be called in the NewView UI initialization routine
  • this._dispose() should be called in NewFacet.dispose
  • A listener on the view's collection should be added to listen for and respond to the onItemsChanged.exhibit signal. Remember to unbind the listener when disposing of the view.

If the view relies on some sort of list format where order matters, consider using the Exhibit.OrderedViewFrame helper class to supply ordering and paging.

Views are disposed of the most often as the view panel switching method disposes of the previous view. Views are not retained in the DOM at all when disposed of from a view panel. They are re-created when they regain focus.

If the view has any user modifiable options, it should provide state management methods and respond to moving through historical states. The view should not respond directly to UI modifications of view state; instead, they should pass the new state to the history system, which will then broadcast to all components that a change has occurred, including the view that just instigated the broadcast. Registration takes care of making sure the view is tapped into such broadcasts.

  • exportState(state) will take an object and return a state object that the history system can save and that the view can re-process later if imported
  • importState(state) will take an object and parse it, informing its internals of new options to set
  • stateDiffers(state) measures if an imported state differs from the current state

Once again, the best place to see how to write a view is to examine the code of existing views.

We are very interested in making the view development process more simple for other developers. Please let us know if there's something in the form of an API that we can do to improve the picture.

Facets

An Exhibit Facet restricts the viewable data set to only those items matching the facet expression and those viable values. A new type of facet should extend the Exhibit.Facet class, using $.extend(this, new Exhibit.Facet("newtype", element, uiContext)); Review the Exhibit.Facet class to see what methods it provides, and note the following conventions:

  • this.addSettingSpecs(NewFacet._settingSpecs); should be called in the NewFacet constructor
  • facet.register() should be called in the NewFacet.create / NewFacet.createFromDOM factory methods
  • this._dispose() should be called in NewFacet.dispose

Facets should then be duck-typed and should provide the following methods:

  • create(configuration, containerElmt, uiContext) returns Exhibit.Facet
  • createFromDOM(configElmt, containerElmt, uiContext) returns Exhibit.Facet
  • configure(facet, configuration)
  • dispose()
  • hasRestrictions() returns boolean
  • clearAllRestrictions() returns Object
  • applyRestrictions(restrictions)
  • setSelection(value, selected)
  • setSelectMissing(selected)
  • restrict(items) returns Exhibit.Set
  • update(items)
  • filter(value, label, selectOnly)

We are very interested in making the facet development process more simple for other developers. Please let us know if there's something in the form of an API that we can do to improve the picture.

Formatters

A formatter takes in a specific type of value and converts it to a string form appropriate for user viewing.

  • format(value, appender) - The value is formatted and passed to appender, which manages coercing the formatted string into an output form.
  • formatText(value) returning string

or

  • formatList(values, count, valueType, appender) - Takes an Exhibit.Set of values and, depending on the valueType, passes them to the appender.

Coders

An Exhibit Coder takes values and assigns them representations in a view (e.g., a color in a map).

  • create(configuration, uiContext)
  • createFromDOM(configElmt, uiContext)
  • dispose()
  • translate(key, flags) returns - Whatever the mapping, the coder returns the appropriate one for the value.
  • translateSet(keys, flags) returns - Whatever the mapping, the coder returns the appropriate one given all the values are colocated (e.g., several items at one point on a map).
  • getOthersLabel() returning a string
  • getMissingLabel() returning a string
  • getMixedLabel() returning a string

Additionally, depending on what the coder codes for, there are get{Others,Missing,Mixed}[Coding] methods.

Widgets

An Exhibit Widget is a UI element on the page that is run off of the Exhibit templating language. There is little that widgets share in common.

  • create(configuration, containerElmt, uiContext)
  • initializeUI()
  • dispose()