DotNetPanel templates are based on well-known open-source Ader Template Engine library (http://www.adersoftware.com/index.cfm?page=templateEngine2) written by AderSoftware company.
In DNP this template engine is used for creating account/space summary and password reminder letters and others. What template variables are available for each type of letter you can find in "DNP Administrators Guide" document. If you need additional variables to be added, please send us a letter with the request.
Below is the extract from the original library documentation explaining basic template syntax.
Here is a very simple template:
Thank You for your order #order.billFirstName# #order.billLastName#.
<br>
Your Order Total is: #format(order.total, "C")#
<br>
<ad:if test="#order.shipcountry isnot "US"#">
Your order will arrive in 2-3 weeks
<ad:else>
Your order will arrive in 5-7 days
</ad:if>
The templates can have expressions, if/elseif/else statement, foreach statement, for statement, set statement and other templates.
- Expressions Expressions are enclosed with # (hash or pound) characters:
ex.
#firstName#
This example will output value of first name. If you need to output # character, just escape it with another #.
ex.
Your SS## is #ssnumber#
Inside of expression block you can output any variable:
#somevar#
access property or field of a variable:
#somestring.Length#
property name is not case senstivie. So you can call: #string.length# or #string.LENGTH#
or call a function:
#trim(somename)#
You can nest property accesses:
#customer.firstname.length#
You can also call methods on any objects:
#firstname.substring(0, 5)#
or
#customer.isValid()#
You can use array access from indexed variables:
#somearray[3]# - gets 3rd element of array
#hastable["somekey"]# - gets value of "somekey" from hashtable.
You can use array access with any object that has indexer property.
There are several built in functions and additional functions can be easily added. The built in functions are:
equals(obj1, obj2) - invokes equals method on obj1 with obj2 as parameter. Returns boolean value.
notequals(obj1, obj2) - Returns !equals(obj1, obj2). Is equavilant to calling: not(equals(obj1, obj2))
iseven(num) - tests whether number is an even number
isodd(num) - tests whether number is an odd number
isempty(string) - test whether string has 0 characters. Same as equals(string.Length, 0)
isnotempty(string) - tests whether string has at least 1 character.
isnumber(num) - tests whether num is of numeric type
toupper(string) - converts string to upper case
tolower(string) - converts string to lower case
isdefined(varname) - tests whether variable named varname is defined
ifdefined(varname, value) - returns value if varname is defined. Especiall useful: #ifdefined("name", name)# - will output value of name if it's defined, otherwise will output nothing
len(string) - returns length of string
tolist(collection, property, delim) - will convert collection to string with delim as seperator. If you pass property, the value of the property will be evaluated on each element of collection. If you omit property, then the object itself will be used.
Ex:
suppose you have list as:
ArrayList list = new ArrayList();
list.Add("one");
list.Add("two");
list.Add("three");
template.SetValue("mylist", list);
then in your template:
#toList(mylist, " & ")#
the output will be: one & two & three
suppose you have list as:
list.Add(new Customer("Tom", "Whatever"));
list.Add(new Customer("Henry", "III"));
list.Add(new Customer("Tom", "Jackson"));
template.SetValue("mylist", list);
then in template:
#toList(mylist, "firstName", ",")#
the output will be: Tom,Henry,Tom
isnull(obj) - tests whether obj is null
not(boolvalue) - returns not (!) of boolean value
iif(booleanExpression, iftruevalue, iffalsevalue) - same as booleanExpression ? iftruevalue : iffalsevalue in C#
Ex:
#iif(isodd(i), "bgcolor=yellow", "bgcolor=red")#
will output bgcolor=yellow if i is odd number and bgcolor=red if i is not odd number
format(object, formatstring) - will call ToString(formatstring) on object. Object has to implement IFormattable interface, otherwise ToString() will be called.
Ex:
(suppose total is decimal with value 1208.45)
#format(total, "C")#
will output: $1,208.45
trim(string) - will trim string object
filter(collection, booleanproperty) - will return new List from collection for those objects whose booleanproperty property evaluates to true
gt(obj1, obj2) - will return true if obj1 > obj2 (obj1 and obj2 must implement IComparable. All numeric types do)
lt(obj1, obj2) - will return true if obj1 < obj2 (obj1 and obj2 must implement IComparable. All numeric types do)
compare(obj1, obj2) - will return -1 if obj1 < obj2, 0 is obj1 == obj2, and 1 if obj1 > obj2 (obj1 and obj2 must implement IComparable. All numeric types do)
or(bool1, bool2) - will return true if either bool1 or bool2 are true
ex:
#or(equals(state, "IL"), equals(state, "NY"))# - returns true if state is either IL or NY
and(bool1, bool2) - will return true if both bool1 and bool2 are true
comparenocase(string1, string2) - will do case insenstive comparison of string1 and string2 and return true if they are equal
stripnewlines(string) - will return all \r\n instances and replace them with space
typeof(object) - will return string representation of the type of object. Ex: typeof("hello") return "string". typeof(3) returns int
cint(value) - converts value to integer (internally used Convert.ToInt32 from .net library)
cdouble(value) - converts value to double
cdate(value) - converts value to DateTime type. You can use this function if you want to create datetime objects. Ex: #cdate("2005-5-1")#
Some operators for common expressions:
is - same as calling function equals. Ex: #obj1 is obj2# will return true if obj1 is equal to obj2.
isnot - same as calling function notequals. Ex: #obj1 isnot obj2#
and - used in if expressions tests (same as && in C#)
or - same as || in c#
lt,
lte,
gt,
gte - less than ("<" in C#), less than or equal ("<="), greater than (">") and greater than or equal (">="). Both operands have to implement IComparable interface. When using numeric types, they have to be of the same type. If you want to compare int to double, you have to convert int to double first using cdbl function.
#varOne lt 3#
#varTwo lte cdbl(3)#
#varThree gt varFour and varFive gte 5.0#
Built In Tags: IF You can also conditionally output text based on some expression using special if tag:
<ad:if test="#booleanexpression#">
<ad:elseif test="#bool#">
<ad:else>
</ad:if>
elseif and else are optional. If test of "if" evaluates to true, then block inside of "if" will be output, otherwise elseif will be tested (if exists) and then else.
Ex:
<ad:if test="#cust.country is "US"#">
You are US customer.
<ad:else>
You are from: #cust.country# country.
</ad:if>
If cust.country is "US" then the output will be: You are US customer.
FOREACH You can loop through collection of elements (any object that implements IEnumerable interface) using FOREACH tag.
<ad:foreach collection="#collection#" var="cust" index="i">
#i#: #cust.lastname#, #cust.firstname#
</ad:foreach>
Suppose customers is array of customer objects: customers = Customer("Tom", "Jackson"), Customer("Mary", "Foo")
The output will be:
1. Jackson, Tom
2. Foo, Mary
During execution, variable name that is passed as var attribute will be assigned with element from the collection. Index attribute can be omitted, and is used to represent index variable for the loop. It starts with 1 and gets increments with each iteration.
FOR You can use FOR tab to loop through integer values by one.
<ad:for from="1" to="10" index="i">
#i#: #customers
.name#
</ad:for>
SET Set tag allows you to set values based on other expressions:
<ad:set name="var" value="#someexpression#" />
After set statement is executed you can use var as if it was a local variable.
It might be useful when accessing complex object values.
Instead of writing:
#customers
![Idea [I]](/emoticons/emotion-55.gif)
.address.firstname# #customers
![Idea [I]](/emoticons/emotion-55.gif)
.address.lastname# #customers
![Idea [I]](/emoticons/emotion-55.gif)
.address.address1#
You can do: lt;ad:set name="add" value="#customers
![Idea [I]](/emoticons/emotion-55.gif)
.address#" /> #add.firstname# #add.lastname# #add.address1#
It's especially useful with createtypereference function (see above)
Custom Templates: You can also create your own templates inside of template file that you can call. You do that using template tag:
<ad:template name="ShowCustomer">
#customer.lastname#, #customer.firstname#
</ad:template>
<ad:showcustomer customer="#cust#" />
You can pass any attributes to the template, and you can use those inside of the template. The template can also access all variables that are defined outside of the template. When calling template you have to put trailing slash at the end, or put closing tag:
<ad:showcustomer />
or
<ad:showcustomer></ad:showcustomer>
The template also received special variable: innerText that is the content of executing the inner elements of calling template.
<ad:template name="bold">
<b>#innerText#</b>
</ad:template>
<ad:bold>#cust.lastname#, #cust.firstname#</ad:bold>
the output will be: <b>Jackson, Tom</b> (if customer is Tom Jackson)
You can also nest those:
<ad:template name="italic">#innerText#</ad:template>
<ad:bold><ad:italic>This will be bold and italic</ad:italic></ad:bold>
You can also invoke templates based on the name using apply tag:
<ad:apply template="#usetemplate#">this is content</ad:apply>
If usetemplate is "bold" then "bold" template will be called.
Templates can be nested inside other template:
<ad:template name="doit">
<ad:template name="colorme">
<font color=#color#>#innerText#</font>
</ad:template>
<ad:colorme color="blue">colorize me</ad:colorme>
</ad:template>
colorme template can only be used within doit template.
Sample template:
-------------------------------------------
order-confirmation.st
-------------------------------------------
<ad:showitem>
#item.sku# - #item.name#<br>
<ad:if test="#equals(item.qty, 1)#">
Price: #format(item.price, "C")#<br>
<ad:else>
You bought #item.qty# items for #format(item.price, "C")#
(total: #format(item.total, "C")#)
</ad:if>
</ad:showitem>
#order.firstname# #order.lastname#<br>
#order.address1#<br>
<ad:if test="#isnotempty(order.address2)#">#order.address2#<br></ad:if>
#order.city#, #order.zip# #order.state#
<br>
<table>
<ad:foreach collection="#order.orderitems#" var="orderitem" index="i">
<tr>
<td>#i#.</td>
<td bgcolor="#iif(isodd(i), "##DEDEDE", "white")#">
<ad:showitem item="#orderitem#" />
</td>
</tr>
</ad:foreach>
</table>
Shipping: #format(order.shipping, "C")#<br>
Taxes: #format(order.tax, "C")#<br>
Order Total: #format(order.total, "C")#<br>
--------------------------------------------
Description of order-confirmation.st
First showitem template is defined which shows a single line item of the order. item is passed as attribute to showitem.
Then address is shown. Note how if is used to conditionally display second line of address with ending <br> tag.
Then each line item of order is looped through using ad:forech tag. iif function is used to color everyother line with #DEDEDE color.