HORN jQuery Reference Implementation 1.0
This is a reference implementation of a parser and UI populator for the HORN Specification 1.0. You must markup your HTML with “indicators” according to the HORN Specification in order for this library to function.
The jQuery reference implementation provides you with tools to parse HORN data from your DOM and repopulate DOM nodes using that data, along with support for type conversions when moving data between model and DOM, and cloning DOM templates and populating them with data.
The horn-jquery.js file defines the Horn class which you instantiate and call methods on. By default a single instance is created and automatically parses your data.
You need to include a second JS file depending on whether you want to use CSS or HTML5 indicators:
horn-jquery-1.0-css.js
or
horn-jquery-1.0-html5.js
For example you may include the CSS indicators and core HORN implementations like this:
<html>
<head>
<script src="js/horn-jquery-1.0.js" type="text/javascript"/>
<script src="js/horn-jquery-1.0-css.js" type="text/javascript"/>
</head>
</html>
The data will be automatically parsed out by the default “horn” instance and accessible via:
var yourModel = horn.model();
By default HORN jQuery reference implementation will parse the data and bind to the DOM elements so that you can update the content of DOM nodes when you change your model data so that the user sees changes. If your UI is read-only then you can set the readOnly option before the code runs to extract the data. Simply add this code to the <head> section of your page after including the horn jquery JS file:
horn.option('readOnly', true);
Methods of the Horn class
load(args) and bind(args)
The load and bind methods pull the data out of your DOM and into the model.
You do not need to call either of these methods if you are using the default single-instance Horn. If you create new explicit Horn instances, you will need to call one of these as appropriate.
The only difference between the two is that load does not bind the data to the DOM nodes, so you cannot later call updateDOM. The bind call extracts the data and also maintains a link to all the DOM nodes that stored the data, so that you can update their display values when the model changes.
The methods take a single object parameter with two optional arguments:
- nodes (Optional) - A list of jQuery nodes or a selector string to identify the nodes that are to be scanned for data
- pathStem (Optional) - A string property path to be prepended to the property paths before values are copied into the model
Neither of these arguments is necessary, as by default the CSS/HTML5 implementations will determine which are the relevant nodes to scan. In some applications however you may wish to control this if you encounter performance problems or have niche requirements.
Example:
var secondHorn = new Horn();
secondHorn.bind('#data-area');
You can call load or bind as many times as you like, and the data extracted will be merged into the existing model, unless you call reset before.
The return value of load and bind is your data model object.
updateDOM(rootNode)
Call this method to update your DOM with the data that is currently in your model.
This will look at the HORN-marked up nodes and resolve them to the data in the model, and update their text or values as appropriate.
There is a single optional parameter you can pass in:
- rootNode (Optional) - The jQuery object representing the DOM node to update. Used to limit the scope of DOM traversal if performance is an issue.
The return value is a list of DOM nodes that were affected by the update. You may for example wish to highlight the nodes that were updated as the result of a user action.
Example:
var model = horn.model();
// Update our data model
model.books[selectedBook].authors[authorIndex].firstName = newAuthorName;
// Tell HORN to update any DOM nodes that relate to model
// values that have changed
horn.updateDOM();
unbind(args)
This method allows you to remove bindings from the model to DOM elements for a given property path within the model.
For example if a user deletes an entry in your UI, you will want to remove the bindings for it so that Horn does not keep references to invalid DOM nodes.
The arguments supported are:
- path (Optional) - A property path to unbind
- pattern (Optional) - A regular expression to match against property paths to unbind
If no arguments are passed, all the DOM elements will be unbound from the model.
Example:
publisherDOMNode.remove();
horn.unbind({path:'books[3].publishers[1]'});
horn.model().books[3].publishers.splice(1, 1);
model()
Returns the Horn data model that was extracted. You change values in this model and can later call updateDOM to have these propagated back to the UI.
Example:
$( function() {
var ourModel = horn.model();
if (ourModel.userHasRegistered != true) {
window.alert('You must register first!');
}
});
bindTo(args)
This method will populate a DOM node and its descendants using this information, pulling values in from the model and binding from the model to the DOM nodes so that calls to updateDOM can re-populate the DOM when data is changed.
It will also optionally clone a DOM node template first, and bind into that.
This is useful for UIs where the user can create new “entries” that follow a DOM template. You update your model with the data, and then call this function to create the on-screen representation.
Arguments:
- template (Optional) - A jQuery object or selector string, indicating DOM node to clone and use as the target for binding
- node (Optional) - A jQuery object or selector to use as the target for binding, without cloning first
- pathStem (Optional) - The property path to which the DOM node should be bound. The data at this path in the model will be used to populate the target DOM node. Alternatively use data to pass in data.
- id (Optional) - The “id” attribute to set on a cloned template DOM node after cloning. Any id from the template is necessarily stripped out after cloning as duplicate ids are invalid in the DOM.
Example:
$( function() {
$('.addButton').click( function() {
var ourModel = horn.model();
var newIdx = ourModel.books.length;
ourModel.books[newIdx] = { saved: false };
var domNode = horn.bindTo( {
template:'#bookEntryTemplate',
pathStem:'books['+newIdx+']'
});
$(domNode).appendTo($('#bookList')).show();
});
});
option(optionName) and option(optionName, value)
Call this to get/set an option on the HORN parser instance. Valid options are:
- readOnly - Setting this to true prevents the auto-loader for the single “horn” instance from binding to DOM nodes, causing it to call load() instead of bind()
- defaultModel - A default model object to apply before parsing. Any data from the page will be merged with this.
- converter - An object that implements the convert() function to perform mapping to and from DOM and model. See horn-converters JS file for an example.
reset()
This method will reset the Horn internal model and state, ready for re-parsing.
Defining Type Conversions
Conversion of the text found in the page to and from native JS types is possible using the converters mechanism. This is performed when the data is first loaded from the page, and also when updating the DOM to contain modified values from the model.
You can register your own named converter functions, and specify property path patterns in your model that should have a given converter applied.
By default, Integer and Boolean converters are supplied.
The Integer converter will map to/from text and native JavaScript integers.
The Boolean converter maps “true” to boolean true, and anything else to false and vice versa.
Implementing a custom converter
To implement a custom converter you must pass a function to hornConverter.add:
hornConverter.add( "Date", function( args ) {
return args.type === 'fromText' ?
$.datepicker.parseDate( DATE_FORMAT, args.value) :
($.datepicker.formatDate( DATE_FORMAT, args.value));
}});
This example registers a Date converter that uses jQuery UI functions to parse or format a date value.
The converter functions are passed a map of arguments containing:
- value - the value to convert from
- path - the property path of the value within the model
- type - the operation type, either ‘fromText’, ‘fromJSON’ or ‘toText’
- node - the DOM node that is bound to the property path
When the fromJSON type is invoked, the value is the JSON object parsed out of the HTML.
Telling HORN which model values should be converted
Once you have added your custom converter, you can tell HORN which property paths should have the converter applied.
To do this you just call pattern or RegexPattern:
hornConverter.pattern( "*.*Date", "Date");
hornConverter.pattern( "*.*Count", "Integer");
hornConverter.pattern( "books*.authors.total", "Integer");
hornConverter.pattern( "books*.publicDomain", "Boolean");
hornConverter.regexPattern( "books\[\d+\].public", "Boolean");
The first argument is a simple wildcard expression (* = any number of chars) or full regular expression matching the property paths you want to have the converter applied to, and the second argument is the name of the converter.
