A Witty template consists of text (which can be regular text, HTML, XML, etc) and Witty instructions. Witty instructions can delineate a block (forevery, if, component) or be a standalone instruction. Comments can be inserted between '[!' and '!]' (exclamation points inside the square brackets). As comments can span multiple lines and do not stop at the first close bracket without an exclamation point, comments can also be used to disable sections of Witty code.
A simple example of Witty code follows:
Cell name lookups
Witty instructions that expect a cell name follow specific lookup rules to find a record containing that cell. This is done using a system of scopes - every time your code 'opens' a record by using a forevery or if block, this record is added as a new level of scope during the execution of that block. Whenever you specify a cell name, the Witty engine first looks for that cell in the most recently opened record. If it cannot find the cell there, it will look in the parent block, until it reaches the record originally passed to the Witty execution command (RunWitty or RunWittyComponent)
You can specify cells from a record contained in a cell by using the dot syntax, as shown below:
This allows you to directly access data inside a record, without having to open the record using an if or forevery statement. The cell name lookup rules only apply to the first cellname specified - as soon as a cell with a matching name was found, the Witty engine will look for the sub cell names inside this record (just like normal HareScript would)
HareScript code invoked using a function pointer in a Witty variable can use the GetWittyVariable function to lookup a cell in the Witty data, using the above lookup rules. Additionally, any record passed to CallWittyComponent is also added as a new scope level.
Embedding external data
Most Witty instructions will only embed external data. There are two syntaxes to embed external data: one that automatically selects the proper encoding based on the Witty encoding (see Data encoding), or by explicitly specifying the encoding:
What exactly is printed depends on the type of the cell to which cellname refers:
The value of the integer is printed
The string is printed, using the specified encoding
The function pointer is executed, and any Print statements done by the function are included in the Witty output. Output from a function pointer is never encoded!
The following encodings are supported for strings:
No encoding (prints the string unmodified)
Base-16 encoding (hexadecimal)
Base-64 encoding (MIME)
Value encoding: escape all quotes, <, >, & and linefeeds as HTML entities (>....)
XML encoding: a synonym for value encoding
HTML encoding: like value encoding, but remove carriage returns and encode linefeeds as '<br />' tags
A synonym for HTML encoding
URL parameter encoding: encode data for use as parameter in a URL
An if-block conditionally enters the following block, if the cell evaluates to true. An if-block can optionally contain an else-block, which is executed when the specified cell evaluates to false:
The text inside both the if-blocks and else-blocks may also contain other Witty instructions.
An if instruction supports cells of the following types - note that it supports more types directly than a plain if statement would in HareScript, but that you cannot build any expressions:
Evaluates to true if the cell itself contains a true value
Evaluates to true if the cell contains a non-zero value
Evaluates to true if the cell contains a non-empty string
Evaluates to true if the record is not a non-existing record (does not contain a default value). Additionally, the record is added as a new scope for cell name lookup
Evaluates to true if the cell contains a function or macro
Evaluates to true if the array is not empty
A forevery instruction repeats the containing block for every record contained in the record array that is specified as its argument. A forevery-block does not support any other type and does not allow an [else] block:
A forevery instruction processes its array sequentially, and adds the current record as a new scope level for cell name lookups inside the forevery block. You can thus directly access the cells inside the current record, and should not access those cells using the original cellname passed to the forevery instruction.
Inside a forevery-block, you can use a [seqnr] instruction to print the current (zero-based) element number. You can also use the following cell names to an if statement inside a forevery-block - they are automatically generated for every record array passed to a forevery instruction:
Evaluates to true if this is the first element in the record array
Evaluates to true if this is the last element in the record array
Evaluates to true if seqnr would give an odd value (ie: it iterates false, true, false, true,... in a forevery-block)
As an example, the following code formats a record array of hyperlinks with alternating background colors:
[! links is our record array of links, containing a 'link' and 'title' cell !]
Components and embed
Components allow you to mark blocks as reusable, similar to HareScript macros. Code inside a component is never directly executed when it is encountered by a Witty engine, and can be placed anywhere you want in the Witty template. This allows you to put all components together at the beginning or end, or to put them at the position they would normally be embedded so you can see the context of the component.
Components are executed using the Witty embed instruction.The syntax of a component is just like that of any other block statement, except that the parameter passed to the component instruction is not that of a cell, but a name which can be used later to refer to the component:
Components have access to the record scopes as they were at the location where the embed or HareScript component commands were invoked. Placing a component block inside an if or forevery block does not give a component access to the records opened by these statements, nor will they be repeated or influenced by the evaluation result of the if statement.