-
Notifications
You must be signed in to change notification settings - Fork 46
Developer Scripted API
This documents APIs developers can use when writing new components for Exhibit 3.0 Scripted.
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
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();
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.
-
containsItem(id)
returns boolean if the database contains the item identified byid
-
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 byid
or null if none -
getAllProperties()
returns all properties as an array -
getProperty(id)
returns an Exhibit.Database.Property identified byid
or null if none
-
getObjects(subject, predicate, set, filter)
fills the Exhibit.Setset
with all objects of statements that match thesubject
andpredicate
, filtering out results using thefilter
Exhibit.Set -
getObjectsUnion(subjects, predicate, set, filter)
same as above, exceptsubjects
is an Exhibit.Set of several subjects to query against -
getSubjects(object, predicate, set, filter)
fills the Exhibit.Setset
with all subjects of statements that match thepredicate
andobject
, filtering out results using thefilter
Exhibit.Set -
getSubjectsUnion(objects, predicate, set, filter)
same as above, exceptobjects
is an Exhibit.Set of several objects to query against -
getObject(subject, predicate)
returns one (and only one) object of a statement matching thesubject
andpredicate
-
getSubject(object, predicate)
returns one (and only one) subject of a statement matching theobject
andpredicate
-
getForwardProperties(subject)
returns an array of properties for statements that share thesubject
-
getBackwardProperties(object)
returns an array of properties for statements that share theobject
-
getSubjectsInRange(predicate, min, max, inclusive, set, filter)
fills or returns the Exhibit.Setset
with all resources with propertypredicate
values that fall in themin
tomax
range (inclusive
a boolean for whether the extremes count as part of the range), filtering out results using thefilter
Exhibit.Set -
getTypeIDs(subjects)
return an Exhibit.Set of all types associated with the Exhibit.Setset
resources
needs writing
needs writing
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).
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.
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);
An Exhibit Importer processes data and passes back an object appropriate for loading into the database.
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.
// 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 };
});
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.
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.
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.
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.
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()