version 1.6.0; platforms: PHP, Python, JavaScript (Node.js, Browser, XPCOM)
- Template Separators
- Template Variables
- Literal Template Data
- Dynamic Template Inheritance
- Dynamic Contexts
- Template Directives
- Template Functions and Plugins
- Contemplate API
IMPORTANT As of version 0.6+
, template separators for Contemplate
templates are defined inside the template itself
in the first non-empty line, separated by a space (see examples and tests). Optionally (for a single template) they can also be passed as part of parse options when calling the Contemplate.tpl(tplID [, data, {separators: seps}])
method
Variables in a template are referenced using PHP
-style Notation with $
sign.
Note Object properties are referenced using (php
-style) arrow notation (->
)
example:
// single variable
$x, $v, $foo, $bar
// etc..
// numeric/associative array access notation, equivalent notations
//================================================================
$obj["key"]
$obj.key
$obj[0]["key"]
$obj[0].key
$obj["key"][0]
$obj.key[0]
$obj["key"].key2
$obj.key["key2"]
$obj.key.key2
// access associative array property, property name is dynamic and given in variable $prop
$obj[$prop]
// object access notation
//=======================
$obj->prop
$obj->method(..args)
$obj->prop->prop2
$obj->prop->method(..args)
$obj->method1(..args)->method2(..args)
$obj->method(..args)->prop
// arbitrary expressions in brackets
//=======================
$var[1+n($index)][cc("foo","bar")]
// any valid combination of the above..
// alternatively to access variable (nested) properties based on arbitrary expressions use built-in `get` directive e.g:
get($var, [1+n($index), urlencode("foo")])
// equivalent to:
$var[1+n($index)][ urlencode("foo") ]
// also `get` directive can access properties which have associated dynamic getter methods,
// i.e access computed property `computed` which is dynamicaly computed by an associated `getComputed` method
get($var, ["computed","otherProp"])
// will try to access $var->getComputed()->otherProp
// etc..
Literal object
/array
data are constructed in a template using JavaScript
Literal Object-style Notation (similar to JSON
)
example:
// eg. a literal object having various string values, numeric values and arrays:
{
"stringVar" : "stringValue",
"numericVar" : 123,
"variableVar" : $foo123,
"arrayVar" : [
0, 1, "astring", 3,
{ "prop": 1 }
]
} // etc
Templates can extend another template. This is accomplished using extends
directive, inside the template.
This means that the super-template (id) is hardcoded inside the cached template (once compiled).
Right now there are 2 ways to have dynamic template extension according to a condition based on input data.
1st is to assign the super-template id (i.e as used in extends(id)
) to another template.
In this way the template id used in extends directive will refer to a different template.
This will change the referenced super-template for all other templates that extend the same super-template as well.
2nd way is on a template-by-template basis. Example:
// fetch/parse the template
tpl = Contemplate.tpl(tplID);
// tpl may already have a super-template assigned, but one can change this
if ('json' == data.view) tpl.extend(newSuperTemplateID);
tpl.render(data);
The engine can use multiple dynanic contexts to have contextual settings, like templates
, caching
, plugins
so that different modules of an application can use the engine independantly.
A dynamic context is created with Contemplate.createCtx('my-context');
A dynamic context is disposed with Contemplate.disposeCtx('my-context');
If a context already exists, it is not re-created in createCtx
method. If a context does not already exist, disposeCtx
method does nothing.
All other API
methods of Contemplate
can accept a context id
(so operations take place in that context) either via options
(in methods that accept an options
parameter) or via an additional ctx
string parameter (see examples).
If no context is given, API operations take place in the global
context "global"
.
TEMPLATE operations take place in the current
context (which defaults to global
if no other context specified)
IMPORTANT As of version 1.0.0+
, template directives
, functions
and plugins
no longer use the %
prefix i.e %for
, %if
, .. but for
, if
, ..
local($var)
DEFINE a local variable with literal name "var". Some variable names are reserved and an error will be thrownset($var, expression_or_value)
SET / UPDATE a tpl or local variable$var
to given value or expressionlocal_set($var, expression_or_value)
SET / UPDATE a local tpl variable$var
to given value or expressionget($var, keys [, default_value=null])
GET arbirtary (nested) variable property (given inkeys
array) based on arbitrary expressions, else returndefault_value
if not foundunset($var)
UNSET / DELETE tpl variable$var
isset($var)
CHECK whether a tpl variable$var
is setiif(cond, then_value, else_value)
inline (ternary)IF
constructempty(val)
php-likeempty
constructif(expression_or_value)
IF constructelseif(expression_or_value)
/elif(expression_or_value)
ELSEIF constructelse
ELSE constructendif
/fi
ENDIF construct, end the IF constructfor(expression_or_obj as $key => $val)
associative FOR loop (php
-style)for(expression_or_obj as $val)
non-associative FOR loop (php
-style)for($key, $val in expression_or_obj)
associative FOR loop (python
-style)for($val in expression_or_obj)
non-associative FOR loop (python
-style)elsefor
ELSEFOR, alternative code block when loop is emptyendfor
ENDFOR , end the FOR loop constructcontinue
CONTINUE , continue the FOR loop constructbreak
BREAK , break from the FOR loop constructextends(base_tpl_id_string)
Current template extends the template referenced bybase_tpl_id_string
, this means thatbase_tpl
layout will be used and any blocks will be overriden as definedblock(block_id_string, echoed=true)
Define / Overrideblock
of code identified byblock_id
endblock
End ofblock
definition / overridesuper(block_id_string)
Reference a superblock
directly if needed in OO manner (mostly useful insideblock
definitions overriden by current template)getblock(block_id_string)
Getblock
output directly via function call (can be useful whenblock
content is needed as a parameter)include(tpl_id_string)
INCLUDE (inline) the template referenced bytpl_id
As of version 1.5.0+, literal PHP or JS or PY code can be included in template.
Assuming template separators as <%
, %>
one can include programming code directly in the template, which will include it only if the language is the language of the engine (ie php will include only php code, js only js code ad py ony py code, rest will simply be ignored).
Example:
<% for ($v in $list) %>
<% $v %> <%php:= "php" %><%js:= "js" %><%py:= "py" %>
<% endfor %>
The above will output in PHP (assuming list = ['a', 'b', 'c']
):
a php b php c php
The above will output in JS (assuming list = ['a', 'b', 'c']
):
a js b js c js
The above will output in PY (assuming list = ['a', 'b', 'c']
):
a py b py c py
One can include block code as well (leaving out the =
mark)
<%php:postdent(1):
foreach ($data['list'] as $v)
{
%>
<%js:postdent(1):
for (var i=0; i<data['list'].length; ++i)
{
var v = data['list'][i];
%>
<%py:postdent(1):
for v in data['list']:
%>
<%php:= $v . " php" %><%js:= v + " js" %><%py:= v + " py" %>
<%php:predent(-1):
}
%>
<%js:predent(-1):
}
%>
<%py:predent(-1):
%>
The above will output exactly the same as previous example in each engine (assuming list = ['a', 'b', 'c']
).
:predent()/:postdent()
option specifies the indentation of the block of code (before/after) in the compiled output. It is optional for PHP/JS (only for visual purposes) but mandatory for Python since Python depends on valid indentation.
IMPORTANT As of version 1.0.0+
, template directives
, functions
and plugins
no longer use the %
prefix i.e %for
, %if
, .. but for
, if
, ..
n(val)
convertval
to integers(val)
convertval
to stringf(val)
convertval
to floatq(val)
wrapval
in single-quotesqq(val)
/dq(val)
wrapval
in double-quotesconcat(val1, val2, val3, ..)
/cc(val1, val2, val3, ..)
concatenate the values as stringsjoin(sep, [val2, val3, ..], skip_empty=false)
/j(sep, [val2, val3, ..], skip_empty=false)
(flatly) string-concatenate withsep
separator the passed array (of arrays)is_array(val [, strict=false])
(php
-like) function test whetherval
isarray
(strict
) orobject
in_array(val, array)
(php
-like) function test whetherval
is contained inarray
keys(obj)
(php
-like) forarray_keys
values(obj)
(php
-like) forarray_values
count(array_or_object)
return number of items inarray_or_object
argumenthaskey( array_or_object, key1 [,key2, ..] )
check whetherarray_or_object
argument has the given (nested) keystime()
/now()
return current timestamp in seconds (php
-like function)date(format [, timestamp=now])
return timestamp formatted according to formatstriptags(string)
striphtml tags
from stringe(val)
custom fast html escapejson_encode(val)
(php
-like) function to json-encodeval
json_decode(val)
(php
-like) function to json-decodeval
urlencode(str)
urlencode (php
-like) functionurldecode(str)
urldecode (php
-like) functionbuildquery(data)
php
-like functionhttp_build_query
to make a query string from structured dataparsequery(str)
php
-like functionparse_str
to parse a query string to structured dataqueryvar(url, add_keys, remove_keys=null)
add/removeurl query
keys, given inadd_keys
andremove_keys
respectively, from givenurl
lowercase(val)
convertval
tolowercase
uppercase(val)
convertval
toUPPERCASE
ltrim(val [, delim])
left trimval
of delim (default to spaces)rtrim(val [, delim])
right trimval
of delim (default to spaces)trim(val [, delim])
left/right trimval
of delim (default to spaces)sprintf(format, val1, val2, ..)
return a formatted string usingval1
,val2
, etc.. as argumentsvsprintf(format, values)
return a formatted string usingvalues
array as argumentsuuid(namespace)
generate auuid
(universal unique identifier), with optional given namespaceinline(tpl, [reps|data])
create or render aninline
template referenced in 'tpl'tpl(tpl_id_string, {"var1" : val1, "var2" : val2, ..})
/template(tpl_id_string, {"var1" : val1, "var2" : val2, ..})
CALL a subtemplate referenced by 'tpl_id', passing the necessary datapluginName([val1, val2, ..])
call a custom (user-defined)plugin
as a template function (see examples)
The main difference is that include
will actually copy the subtemplate contents inside the calling template (thus only one final template is generated). This is similar to PHP's include
directive.
On the contrary tpl
directive will call and parse a subtemplate on its own (so the data need to be passed also). In this case each subtemplate will be compiled on its own and exist in the cache.
When the templates are already cached, the relative performance of these directives is similar. include
tends to be slightly faster since it generates only a single template, while template
will generate all needed templates. However if a subtemplate has been changed and is embedded in another template using include
, the calling template will NOT be refreshed. While if template
is used, the calling template WILL be refreshed (since the subtemplate is called as a subroutine and not copied literally inside the calling template)
The syntax for include
is this: include(subtemplateId)
The syntax for tpl
/ template
is this: tpl(subtemplateId, {"var1":$value1, "var2":$value2, ..})
where the {"var1":$value1, "var2":$value2, ..}
are the data to be passed to the called template
this is exactly how the Contemplate.tpl(id, data)
method is called.
(javascript)
// create a custom dynamic context for modular use
Contemplate.createCtx('my-context');
// dispose a custom dynamic context (created earlier)
Contemplate.disposeCtx('my-context');
// Add templates
Contemplate.add({
'tpl1': './path/to/template1',
'tpl2': './path/to/template2',
'inline_tpl': ['<% $var %>'], // inline template
'dom_tpl': '#dom_tpl_id' // DOM template (for browser)
} [, ctx="global"]);
// set a custom template finder per context
// for javascript engine it should support both sync and async operation if callback 2nd argument is given
Contemplate.setTemplateFinder(function(tplId [,cb]){
} [, ctx="global"]);
// set an array of possible paths where contemplate may find templates per context (and custom templatefinder is not defined)
Contemplate.setTemplateDirs(templateDirs [, ctx="global"]);
// get the array of possible paths where contemplate may find templates per context (if set, else empty array)
Contemplate.getTemplateDirs([ctx="global"]);
// add plugins
Contemplate.addPlugin('print', function(v) {
return '<pre>' + JSON.stringify(v, null, 4) + '</pre>';
} [, ctx="global"]);
// set cache directory for Node, make sure it exists
Contemplate.setCacheDir(path.join(__dirname, '/_tplcache') [, ctx="global"]);
// set caching mode for Node
// Contemplate.CACHE_TO_DISK_AUTOUPDATE, Contemplate.CACHE_TO_DISK_NOUPDATE, Contemplate.CACHE_TO_DISK_NONE
Contemplate.setCacheMode(Contemplate.CACHE_TO_DISK_AUTOUPDATE [, ctx="global"]);
// get a template by id, load it and cache it if needed
var tpl = Contemplate.tpl('tpl_id' [, null, options={}]);
// render template
tpl.render(data);
// render a template by id, using data, load it and cache it if needed (sync operation all engines)
Contemplate.tpl('tpl_id', data [, options]);
// Javascript-only: get or render a template by id async (promise-based), load it and cache it if needed
Contemplate.tplPromise('tpl_id', data [, options])
.then(function(tpl){
// do something with tpl
})
.catch(function(err){
setImeout(function() {
throw err;
}, 0);
});