[UP] Reference |
Templates Templates are well-formed HTML fragments containing placeholders (parameters). They are defined outside the dialogs, but can be instantiated within the page definitions of the dialogs. When the template is instantiated, the (formal) parameters are replaced by the passed values, resulting in a complete HTML subterm. Of course, a template can be instantiated several times with different instance values. Scope of templates Templates are always globally known. For example, in the following application every page can refer to every defined template: <ui:application start-object="..."> <ui:template name="t1"> ... </ui:template> <ui:dialog name="o1" ...> ... <ui:page name="p1"> ... <!-- Instantiations of t1 and t2 are allowed here --> ... </ui:page> ... </ui:dialog> <ui:template name="t2"> ... </ui:template> </ui:application>Templates can be instantiated from within ui:page definitions, and applying a template has the same effect as if the expanded HTML fragment had been written in place of the application. It is also possible to instantiate templates from within templates; however, recursive instantiation is not allowed. Definition and instantiation of templates without
parameters A template is defined by the ui:template element, and the simplest way to apply it is the ui:use element. For example, the template t is defined as: <ui:template name="t"> This is text from template t. </ui:template>The following page applies this template twice, resulting in a page displaying "This is text from template t. This is text from template t.": <ui:page name="p"> <html> <body> <ui:use template="t"/> <ui:use template="t"/> </body> </html> </ui:page>There are some special whitespace rules for template definitions. The template t could be read as "\nThis is text from template t.\n" because there are newline characters before "This" and after the period. However, WDialog ignores whitespace at the beginning and at the end of template definitions, so you can nicely format your definition. (See below for techniques that force the inclusion of spaces at these special locations.) Templates with parameters The placeholders of templates are called parameters, and they may occur either within character data, or within attributes. They are denoted by a dollar followed by the identifier, or by a brace containing the identifier (as in shell expressions). Example: <ui:template name="three_columns" from-caller="col1 col2 col3"> <table> <tr> <td>$col1</td> <td>$col2</td> <td>$col3</td> </tr> </table> </ui:template>This template expands to a table with one row and three columns, and the contents of all cells are passed by parameters to the template. The parameters are called col1, col2, and col3, and they must be declared by the from-caller attribute. The replacement texts of the parameters are inserted where the parameters are referred to by the dollar notation; here as $col1, $col2, $col3 within the td element. Note that it is also possible to put the names into curly braces such as ${col1} - this is especially necessary if the parameter names consist of characters other than a-z, A-Z, 0-9, and _. Note that the dollar character must be either written as $$ in template definitions, in order to denote the dollar character as such. The from-caller declaration is needed for every parameter which is referred to using the dollar notation. One reason for this rule is to make it more likely that typos in parameter names are recognized as errors and that such templates are rejected by the system. Furthermore, from-caller also indicates that the parameters have so-called lexical scope. Alternatively, parameter may also declared by an from-context attribute with a different scoping rule (see below). The actual values for the parameters are passed by ui:param elements which may be included into ui:use applications: <ui:use template="three_columns"> <ui:param name="col1">This is the left column!</ui:param> <ui:param name="col2"><b>This is the middle column!</b></ui:param> <ui:param name="col3">The right edge.</ui:param> </ui:use>Note that it is possible to pass whole XML subterms (as in col2), and not only plain texts. Rule to process inner elements when expanding parameters in character data context:
The consequences of this rule are discussed later. The dollar notation can be used where normal text is allowed as in the example above, or within attributes. For instance, the example can be extended by passing the alignment attributes of the td cells: <ui:template name="three_columns" from-caller="col1 col2 col3 align1 align2 align3 valign1 valign2 valign3"> <table> <tr> <td align="$align1" valign="$valign1">$col1</td> <td align="$align2" valign="$valign2">$col2</td> <td align="$align3" valign="$valign3">$col3</td> </tr> </table> </ui:template>For simple, unstructured texts the dollar notation behaves in the same way when used within attributes as when applied in the body of elements. However, there are differences regarding real subtrees. Attributes cannot represent inner elements; for example, it is not reasonable to pass the element <b>top</b> as parameter valign1. Because of this, the following rules are applied to remove/process inner elements: Rules to process inner elements when expanding parameters in attribute context:
Parameters with default values The above definition of three_columns is a bit impractical because whenever the template is instantiated all nine parameters must be passed. This can be avoided by providing defaults for parameters. The default values are simply specified as inner text of the ui:default declaration. Continuing our example: <ui:template name="three_columns" from-caller="col1 col2 col3 align1 align2 align3 valign1 valign2 valign3"> <ui:default name="align1">left</ui:default> <ui:default name="align2">left</ui:default> <ui:default name="align3">left</ui:default> <ui:default name="valign1">middle</ui:default> <ui:default name="valign2">middle</ui:default> <ui:default name="valign3">middle</ui:default> <table> <tr> <td align="$align1" valign="$valign1">$col1</td> <td align="$align2" valign="$valign2">$col2</td> <td align="$align3" valign="$valign3">$col3</td> </tr> </table> </ui:template>Now, only col1, col2, and col3 must be passed, and the other parameters may be passed or omitted. The ui:default declarations must be written at the beginning of the template; between two such declarations only white space and comments are allowed. The following rule helps avoiding extra white space in the expansion of templates. White space at the beginning of templates:
For our three_columns example, this rule means that the first relevant member of the template is the table start tag, all white space before this tag is ignored. There is a corresponding rule for white space at the end of templates: White space before the end tag of ui:template is ignored. However, what to do if I want whitespace? For example, can I define a template only containing a single white space character? Yes, it is possible, but only with a trick. Note that the following trials do not work: <ui:template name="space"> </ui:template> <ui:template name="space"> </ui:template> <ui:template name="space"><!-- --> <!-- --></ui:template> <ui:template name="space"><![CDATA[ ]]></ui:template>They do not work because the used XML parser normalizes white space before the WDialog transformation engine gets the XML tree. So these definitions look all the same for WDialog. The solution is to include a reference to an empty template in the definition. The standard library for templates defines the empty template as wd-null: <ui:template name="space"> <ui:use name="wd-null"></ui:use> <ui:use name="wd-null"></ui:use> </ui:template> Templates calling templates Of course, it is possible that a template instantiates another template. Example: <ui:template name="mk_hyperlink" from-caller="href"> <a href="$href">$href</a> </ui:template> <ui:template name="caml_homepage"> <ui:use template="mk_hyperlink"> <ui:param name="href">http://caml.inria.fr/</ui:param> </ui:use> </ui:template>The rules for passing parameters may become inconvenient when parameters must be passed from one template to the next template. For instance, if we also want to be able to specify the target frame of the hyperlink, we must write: <ui:template name="mk_hyperlink" from-caller="href target"> <a href="$href" target="$target">$href</a> </ui:template> <ui:template name="caml_homepage" from-caller="target"> <ui:use template="mk_hyperlink"> <ui:param name="href">http://caml.inria.fr/</ui:param> <ui:param name="target">$target</ui:param> </ui:use> </ui:template>The parameter target is simply passed through from caml_homepage to mk_hyperlink. It is possible to avoid such stupid forwarding of values by using parameters with dynamic scope; see below. Note that it is not allowed that a template instantiates itself recursively. Another way of interaction between templates is that the passed parameter value contains another ui:use statement. For example, we can put the hyperlink to the Caml homepage into the middle cell of the three column scheme: <ui:use template="three_columns"> <ui:param name="col1"> </ui:param> <ui:param name="col2"> <ui:use template="caml_homepage"> <ui:param name="target">_blank</ui:param> </ui:use> </ui:param> <ui:param name="col3"> </ui:param> </ui:use>This seems to be straight-forward; however it is important to mention that ui:use is resolved lazily. This means that first the template three_columns is expanded, leading to this intermediate result:
In contrast to this, a direct evaluation scheme would first expand caml_homepage and pass the result of this first step to three_columns. However, this scheme has not been implemented. (I do not want to argue that the lazy scheme is better, it was only simpler to implement. Evaluation depends on whether the parameter occurs in character data or attribute context; for a direct scheme additional analysis would be necessary to find out which context applies (or the replacement text is always computed for both cases which is time-consuming); it might be worth-while to switch to a direct scheme in order to reduce the total number of expansions, however.) The further expansion steps are:
Calling templates indirectly The following technique demonstrates how to call a template by passing the name of the template: <ui:template name="for_caml" from-caller="templname"> <ui:use template="$templname"> <ui:param name="href">http://caml.inria.fr/</ui:param> <ui:param name="target">_blank</ui:param> </ui:use> </ui:template>This template calls the template $templname, and passes the fixed set of parameters href and target with a fixed set of values to the invoked template. A possible way to use it: <ui:use name="for_caml"> <ui:param name="templname">mk_hyperlink</ui:param> </ui:use>This code creates again the Caml hyperlink. One possible application for indirect calls is to dynamically select the template to use: <ui:use name="for_caml"> <ui:param name="templname"><ui:dynamic variable="templname"/></ui:param> </ui:use>We could have another template, no_hyperlink, which simply displays the $href parameter without making the hyperlink; the variable templname selects the template. We could set this variable in the prepare_page method of the dialog object, and make the selection of the particular template dependent on an arbitrary condition. A better notation to reference dialog variables In the last example, we replaced the parameter templname by the contents of the dialog variable templname. There is a better notation than using ui:dynamic: <ui:use name="for_caml"> <ui:param name="templname">$[templname]</ui:param> </ui:use>This means exactly the same. Moreover, the square brackets notation can be used inside of attributes (where ui:dynamic cannot be applied). Example: The following template is a variant of mk_hyperlink that extracts the values for the URL and the target from dialog variables: <ui:template name="mk_hyperlink"> <a href="$[href]" target="$[target]">$[href]</a> </ui:template> In recent versions of WDialog, the bracket notation has been generalized, and it is now allowed to write more complex expressions inside the brackets. See the chapter about $[expr]. Lexical and dynamic scope When templates call templates, it is often necessary to pass parameters through from one template to the next one. Until now, we only have the solution to do this parameter forwarding explicitly: <ui:template name="t1" from-caller="p"> ... <ui:use template="t2"> ... <ui:param name="p">$p</ui:param> ... </ui:use> ... </ui:template>The parameter p is introduced at the beginning of t1, and p gets a value at this moment (either because a value has been passed, or because there is a default value). p is visible everywhere within the definition text of t1, but it is not automatically visible in called templates such as t2, even if there is a parameter with the same name. We must explicitly pass p to subsequent templates to extend its scope. This way of handling the visibility of parameters is called the lexical scoping rule. This rule has the advantage that it can be exactly controlled which parameter is passed to which template, and it works in most cases fine. However, if many parameters must be simply forwarded to inner templates, a dynamic scope will better fit to the situation. To explain it, we need the concept of a dynamic parameter context. Such a context is a binding of some parameter names to values, and it is automatically passed to inner templates. We can add a particular binding of a name to a value to the context for a certain period of time, and the new binding will hide any previous binding of the same name while it is in effect. The improved definitions of mk_hyperlink and caml_homepage are: <ui:template name="mk_hyperlink" from-caller="href" from-context="target"> <a href="$href" target="$target">$href</a> </ui:template> <ui:template name="caml_homepage"> <ui:use template="mk_hyperlink"> <ui:param name="href">http://caml.inria.fr/</ui:param> </ui:use> </ui:template>mk_hyperlink now gets the parameter target from the current context. caml_homepage no longer passes this parameter. This template should now be called as follows: <ui:context> <ui:param name="target">_blank</ui:param> <ui:use template="caml_homepage"></ui:use> </ui:context>The ui:context element extends the context by the parameters denoted by ui:param and expands its body, here the ui:use application. The context parameters are a like a set of background definitions that are in effect for the time of the ui:context expansion. Every template called from within ui:context can access these parameters by importing them with from-context. The rules of parameter passing When a template is expanded, the definition text of the template must only consist of declared parameters, i.e. there must be only a dollar notation for a parameter that has been declared by from-caller or from-context at the beginning of the template. A parameter is either lexical or dynamic. It is not allowed that the same name appears in both from-caller and from-context. For lexical parameters (from-caller), only the ui:param elements of the calling ui:use are searched for instance values. For dynamic parameters (from-context), only the context is searched for instance values. If several ui:context elements are in effect for same parameter, the most recent definition wins and is used. After the values have been collected, all dollar notations are replaced by their corresponding values. Encodings It is sometimes useful to encode the current value of a parameter. For example, imagine you have a template print-as-html that prints the HTML code of the parameter body: <ui:template name="print-as-html" from-caller="body"> The HTML code is as follows: <pre> ${body/html} </pre> </ui:template>This has the effect that the encoding "html" is applied to the value of body. "html" replaces < by < etc. There are a number of other encodings (see the chapter on Output encodings). The t and p namespaces Because ui:use is a quite long notation, there are two ways to abbreviate it. Instead of <ui:use template="x"> <ui:param name="p1">t1</ui:param> ... <ui:param name="pN">tN</ui:param> </ui:use>you can also write <t:x> <p:p1>t1</p:p1> ... <p:pN>tN</p:pN> </t:x>Furthermore, the parameters can also be passed as attributes if they only consist of unstructured text: <t:x p1="t1" ... pK="tK"> <p:pJ>tJ</p:pJ> ... <p:pN>tN</p:pN> </t:x> The q namespace The other way to abbreviate ui:use is the q namespace. Instead of writing <ui:use template="x"> <ui:param name="p1">t1</ui:param> ... <ui:param name="pN">tN</ui:param> <ui:param name="body">tBODY</ui:param> </ui:use>(note the fixed name body) it is also possible to call the template by: <q:x p1="t1" ... pK="tK"> tBODY </q:x> Elements related to templates The following elements have a relationship to templates:
|