-
Notifications
You must be signed in to change notification settings - Fork 12
Cht api
Please note that this page describes high-level and low-level facilities alike. In order to better understand the efficient ways of building your Web applications with CHT, refer to the Concepts section of this Wiki.
dojo.require( 'dojox.jtlc.compile' );
var evaluator = dojox.jtlc.compile( input, language, compile_time_options );
Invokes the jtlc compiler, producing a Javascript function object evaluator
from the abstract syntax tree described by the input
.
Due to the distributed nature of jtlc language definitions, the output is determined primarily by the types of the AST nodes while the language
argument affects the interpretation of untyped nodes of the tree (values, objects that don’t define a compile()
method, arrays) as well as provides a set of global options available to all node types. At present, jtlc language objects can be constructed by instantiating one of the following classes: dojox.jtlc.JXL
, dojox.jtlc.qplus
and dojox.jtlc.CHT
.
Additionally, the optional argument compile_time_options
may serve to pass in a dictionary of options to the specific compilation. These options are dependent on the nature of the language and node types used; for examle, CHT uses this mechanism to provide localization dictionaries to templates.
dojo.require( 'dojox.jtlc.JXL' );
Class encapsulating the global options for the Javascript Transformation Language. Note that JXL itself is mostly defined by the AST node types in the module dojox.jtlc.tags
that are described in the JXL primitives section of this Wiki.
var jxl = new dojox.jtlc.JXL( options );
Instantiates language description for JXL that can be customized by specifying the following settings:
-
elideNulls
: when true,null
values are not placed into array or dictionary sinks but are thrown away instead (with their corresponding keys in case of a dictionary); -
failOnDuplicateKeys
: when true, an attempt to insert a duplicate key into the dictionary sink results in an exception; -
queryLanguage
: by default this option is set todojox.json.query
. You may substitute another query language compiler with a compatible API; -
replaceLanguage
: by default this option is set todojo.replace
. You may substitute a formatting function of your own with compatible API.
dojo.require( 'dojox.jtlc.qplus' );
Class implementing the parser and encapsulting the global options for the Q+ query language. Normally Q+ queries are used from within CHT templates, but dojox.jtlc.qplus
can also be used on its own as a streamlined notation for JXL. Note however that Q+ can represent only a subset of all possible JXL trees and is not intended to be a functionally complete data transformation language.
var qplus = new dojox.jtlc.qplus( options );
Argument options
is a bag of properties customizing the interpretation of the data query language. At the moment the only user-accessible option property is filters
that can be used to pass in a dictionary containing user-defined functions or expressions encoded as strings:
var qplus = new dojox.jtlc.qplus( {
filters: {
fromHex: function(str){ parseInt(str,16); },
toHex: "$.toString(16)"
}
} );
More details regarding the custom filters are available within the Q+ query language reference.
var ast = qplus.parse( query, is_a_query_list );
Parses a single Q+ query into an abstract syntax tree that can be accepted as input by dojox.jtlc.compile()
. If a truthy value is passed for the optional argument is_a_query_list
, the query
is expected to contain a comma-separated list of Q+ queries and the method will return an array of JXL trees.
dojo.require( 'dojox.jtlc.CHT' );
Class implementing the parser and encapsulting the global options for the Comprehensive HTML Template language.
var cht = new dojox.jtlc.CHT( options );
Argument options
is a bag of properties customizing the interpretation of the CHT and Q+ languages: an embedded instance of dojox.jtlc.qplus
is constructed together with the instance of dojox.jtlc.CHT
and shares the options
argument the user has passed in.
In addition to the filters
option used by Q+, CHT also accepts a hook function for resolving cross-module dependencies via the loadTemplates
property of the options
object:
var cht = new dojox.jtlc.CHT( {
loadTemplates: function( unresolved_references ){ ... }
} );
The function receives a single argument: a dictionary of qualified template identifiers. The CHT parser assumes that any template name of the form Prefix_.
_Name is defined in a different input file and can only be resolved via loadTemplates()
, so all of these names will end up in this dictionary as properties with values of false
. The loadTemplates()
function is expected to populate these properties with references to actual parsed template bodies, received from CHT.parse()
applied to the definitions of the respective modules. The function should then return the resulting dictionary, or, as a more likely scenario, an instance of dojo.Deferred that will resolve to such a dictionary once the asynchronous loading and parsing operations have completed. The argument may be modified in place or copied at implementor’s option.
Note that dojox.jtlc.CHT.loader
already implements a set of high-level facilities to support template modules, making direct use of the loadTemplates
hook by the application code highly unlikely.
var ns = cht.parse( input_text, url );
or
dojo.when( cht.parse( input_text, url ), function(ns){ ... } );
The second argument is optional: it groups the evaluator scripts generated from the template file under the specified URL in the script selection dropdowns of Firebug and WebKit developer tools. If the url
argument is omitted, all evaluator scripts will appear under [CHT-Templates]
.
The parse()
method executes synchronously unless it encounters an asynchronously executing call to loadTemplates()
. In either case, it returns — directly or via a dojo.Deferred promise — a namespace object (dictionary) populated with templates defined within the input_text
, or throws an exception if a syntax error occurs. The names of properties in the namespace object are always simple identifiers (without dots) and their values are syntax trees that may serve as input to dojox.jtlc.compile()
.
It is also possible to populate a single namespace with templates from multiple input fragments by passing in the namespace object as an extra argument inserted between input_text
and url
. The “partial override” feature of the CHT loader should obviate the need for this low-level capability.
dojo.require( 'dojox.jtlc.CHT.loader' );
Singleton dojox.jtlc.CHT.loader
provides a higher-level facility for automatic loading, parsing and compiling the template files and localization dictionaries (NLS bundles) associated with them. It also implements the logic necessary to resolve cross-module references in CHT, opening the way to reusable template libraries.
Loader consults a global dictionary, preloadedCHT
, to check for template files that have already been preloaded. The keys in this dictionary should be resource URLs identical to what the module names resolve to, and the values are either file content (as a string) or a promise object resolving to it. Here’s an example of how the template files may be preloaded:
preloadedCHT = {
'CHT/app.cht': dojo.xhrGet({ url: 'CHT/app.cht' }).then(
function( text ) {
preloadedCHT['CHT/app.cht'] = text;
}
)
};
var template_evaluator = dojox.jtlc.CHT.loader.get( 'module.Template' );
Returns the evaluator function for the specified template, identified by a fully qualified name.
-
Synchronous evaluation: if the template module that contains the requested template has already been loaded (with a call to
require()
or a previous call toget()
referring to a template from the same module),get()
is guaranteed to evaluate synchronously. If the template has already been compiled the cached evaluator is returned, otherwise the template is compiled and the resulting function cached. -
Asynchronous evaluation: if the template module had to be loaded and parsed as part of
get()
, the latter returns a forwarder function that can also act as a promise object that resolves to the actual evaluator. If the forwarder function is called immediately it returns a proxy object for the template instance that provides a single method,render()
, that also acts as a forwarder with asynchronous evaluation returning a promise that resolves to the actual result ofrender()
as obtained from the template instance when it is finally available. If the latter is a promise itself, the promise returned from the forwarder will resolve only after all asynchronous operations have been completed.
var template_evaluator = dojox.jtlc.CHT.loader.getSync( 'module.Template' );
A variant of get()
that returns a compiled template only if it could be obtained synchronously. This requires the template module to be already loaded and parsed (compilation is synchronous). If the template could not be found, this method throws an exception.
dojo.when(
dojox.jtlc.CHT.loader.require( module_name_1, ..., module_name_N ),
function() {
// Actions dependent on the requested modules
}
);
Ensures that all of the requested CHT modules are loaded and parsed. Returns a promise that resolves after all asynchronous operations have completed.
-
Partial overrides: the
require()
method supports an extension mechanism that lets the application replace some of the templates present in a library module with templates from one or more overriding modules of its own:
dojox.jtlc.CHT.loader.require( 'library.module+my.module' );
The above call loads and parses templates from library.module
and then loads and parses templates from my.module
placing them into the namespace of the library.module
replacing any templates with identical names that may already exist there. Multiple overriding modules (with names separated by +
characters) may be applied to a library module in the same call to require()
.
Note that in this scenario my.module
does not become a separate CHT module: my.module.Template
gets loaded as library.module.Template
and can only be referenced as such afterwards, whether from another CHT file or from the Javascript code. The NLS bundles of the overriding modules also get merged with the bundle of the base module yet they do not override original localizations but only supply the missing ones.
It is technically unfeasible to apply overrides to a module that’s already been loaded, therefore it is paramount to specify all desired overrides with the very first require()
referencing this CHT module that will be encountered during the execution!
dojox.jtlc.CHT.loader.initCompiler( cht_options );
This method provides a way to customize the single global instance of dojox.jtlc.CHT
used by the loader to parse and compile templates. It is advisable to call this method as early as possible in the lifecycle of the application to avoid confusion: templates compiled before a call to initCompiler()
will use default-configured instance of CHT without any user-defined filters. There is no need to call initCompiler()
if no customization is required.
Template instances are produced by the CHT evaluators. Conceptually, a template instance encapsulates an HTML fragment about to be inserted into DOM and its lifetime ends after such an insertion has occurred. Instances of templates rendered asynchronously and/or containing animated transitions continue their lifetimes until all asynchronous processes associated with them have completed. It is not recommended to preserve references to template instance objects indefinitely as this may cause exhaustion of browser resources.
Returns the HTML fragment encapsulated by the instance as a text string that can be assigned to innerHTML
.
Returns an HTML document fragment object that can be inspected using DOM methods or inserted into an HTML document with a call to dojo.place().
var instances = [],
dom = compiled_template(parameters).toParsedDom( { instances: instances } );
Returns an HTML document fragment after applying dojo.parser.parse() to its content in order to process dojoType
attributes and instantiate codebehind objects and widgets. This method has an optional argument (property bag) that may contain any options of dojo.parser.parse()
as well as an additional option instances
used to return back an array with all object instances created by the parser. This array may be useful in cases when some of the objects do not automatically connect event handlers to themselves and may therefore be garbage-collected prematurely.
var instances = [],
dom = compiled_template(parameters).place( ref_node, 'replace', { instances: instances } );
Generates the HTML fragment, places it into the specified location within the document, instantiates the codebehind objects and cleans up the widget instances associated with the HTML content being overwritten (if any). This methods is essentially a shortcut for toParsedDom()
followed by a call to dojo.place() with two important advantages:
- It executes the
startup()
method on the instantiated widgets (if any) after the HTML content has been placed into its destination in the document, making it possible for the widget code to inspect the actual positions and sizes of the elements after layout; - If the second argument is
"replace"
or"only"
, this methods finds all widget instances within the overwritten part of the DOM and executes their destroy() methods allowing the cleanup to take place. Please note that while all kinds of codebehind objects can be instantiated via thedojoType
attribute, only those inheriting from dijit._Widget can benefit from the automatic cleanup sequence.
The first two arguments of this method correspond to the second and third arguments of dojo.place(). The third argument is the same as the only argument of toParsedDom()
. Second and/or third argument may be omitted.
For instances of templates with associated transitions, place()
returns a promise resolving to the same value as the promise returned by the transition.
The instances of templates without associated transitions will return the context object from place
if returnContext: true
is passed as part of the third argument (options
).
compiled_template( args ).render( ref_node, pos, options );
or
dojo.when( compiled_template( args ).render( ref_node, pos, options ), on_rendering_complete );
This is a high-level method that encapsulates all details of asynchronous and incremental template rendering. It takes the same parameters as the place()
method and does indeed pass them through to place()
; it may, however, call place()
repeatedly for the entire template and/or call it on the instance objects produced by the nested templates. It returns a promise that will resolve once the rendering is fully completed.
It is expected that render()
will be used in most cases for evaluating and displaying the CHT templates. The synchronous version of render()
is simply a synonym of place()
.
var tpl_instance = compiled_template( args );
if( tpl_instance.isDeferred() ) {
// Execute if instance may yet change
}
Returns true
if the result of template evaluation still depends on one or more unresolved promises. Note that even an asynchronous template may produce its final expansion on first evaluation. The synchronous version always returns false
.
dojo.when(
compiled_template( args ),
function( instance ) {
instance.update();
instance.place( ref_node, pos, options );
}
);
Re-evaluates the template and updates the template instance. The example above will render only the final expansion of the template. Note that this code will be suboptimal if the very first evaluation produces the final expansion since it will evaluate the template twice. Synchronous version of this method does nothing.
Returns true
if the template instance can update its DOM representation in place. The updateDom()
method should never be called if canUpdateDom()
returned false
. The synchronous version always returns false
.
var tpl_instance = compiled_template( args );
tpl_instance.place( ref_node, 'only', options );
if( tpl_instance.isDeferred() ) {
function refresh( instance ) {
if( instance.canUpdateDom() ) instance.updateDom( ref_node, options );
else {
instance.update();
instance.place( ref_node, 'only', options );
}
}
dojo.when( tpl_instance, refresh, on_error, refresh );
}
Method updateDom()
updates the DOM representation of a template in place, using the marker elements that it and/or its children have injected into their expansions. If the template expansion has reached its final state (no more promises are pending), the marker elements are removed. This method should not be called unless canUpdateDom()
returned true
therefore no synchronous version is provided.
The example above is a simplified version of the algorithm implemented by the render()
method. The ref_node
argument is used by updateDom()
only to reduce the area in which to conduct the search for marker elements. The options
argument is passed through to place()
.
For instances of templates with associated transitions, updateDom()
returns a promise which will resolve (to an unspecified value that should be ignored) upon completion of all transitions initiated as a result of the call. If no transitions were initiated, or all that were initiated have completed synchronously, updateDom()
returns a truthy value if it made any changes to DOM and a falsy value if it didn’t.
Animated transitions are callback functions accepting up to three arguments and returning a promise:
function anAnimatedTransition( context, new_content, instance )
{
var result = new dojo.Deferred();
// 1. Set up the animation.
// 2. Ensure that 'new_content' has replaced DOM nodes within 'context'
// by the time animation completes.
// 3. Call result.resolve() when animation completes.
return result;
}
First argument, context
, is an object describing the location within DOM where the template expansion should be placed as well as the (potentially empty) sequence of DOM nodes it will be replacing. Second argument is a detached DOM node or fragment generated by template expansion. Third argument is the template instance object.
The transition is invoked as step 4 of the sequence of actions implemented by the place()
method on template instances:
- Render the template into HTML.
- Parse resulting DOM to instantiate new widgets.
- Clean up widgets associated with parts of DOM being replaced.
- Replace old DOM with new.
- Start up new widget instances.
As a result, the place()
method does not complete synchronously in presence of an animated transition and the latter is responsible for signaling its completion via the promise object it returns.
Note that in absence of asynchronous/incremental template rendering, the transition does not have to ensure that the new content has indeed replaced the old at the specified location. This requirement becomes more stringent with asynchronous templates because the incremental updates in this and other templates may interfere with the DOM changes asynchronously performed by transition (see the detailed discussion below).
The transition can complete its operation synchronously in which case it should return a non-promise value.
The context objects are passed into the animated transition callbacks and describe the location within DOM where the template expansion should be placed as well as the (potentially empty) sequence of DOM nodes it will be replacing.
The parent element of all nodes within the context.
The node just before the sequence of nodes to be replaced or null
if it begins from parent.firstChild
.
The node just after the sequence of nodes to be replaced or null
if it ends on parent.lastChild
.
Returns true
if the sequence of nodes to be replaced is empty. The context object still describes a valid place in DOM to place the new content.
Returns a dojo.NodeList containing the nodes to be replaced.
ctx.place( new_content, pos );
Places new content into the document at the position specified by the context object. The argument is optional; if omitted or equal to "replace"
the old content is removed from the document and returned by this method as a dojo.NodeList. Passing in "before"
or "after"
in place of pos
inserts the new_content
between ctx.first
and the sequence or between the sequence and ctx.last
, respectively.
Returns the corresponding “inner context”: an object with a similar interface that stored first and last nodes of the sequence as its first
and last
properties. Inner contexts can be preserved across asynchronous operations; outer contexts cannot be since their first
and last
may point to DOM nodes generated by other templates and subject to replacement at any time.
Same as the context objects, except for:
- The interpretations of
first
andlast
; empty inner contexts have both these properties equal tonull
; - The
place()
andinner()
methods are not provided; - An additional method
outer()
returns the corresponding outer context (as described above). This method cannot be called on an empty inner context.