The Templix syntax is based on diple sign < and >, so if you want to use them for other purpose than opening or closing a markup declaration, you have to use their html entites equivalent which are > and <.
The templix syntax is based on PHP and HTML5/XML, but like HTML5 add the shortcut attribute to XML, Templix add the shortcut value to HTML5:, (*3)
<markup "my shortcut value" />
The markup between comment will not be parsed excepting the PHP., (*4)
onCompile binder
You can bind to templix some callback to trigger when the document is almost compiled and all its DOM is accessible., (*5)
// re-compile each time
// add indentation and line feed for code readability
$templix->setDevTemplate(true); //default true
// add time suffix parameter to local css links to avoid browser caching
$templix->setDevCss(true); //default true
// add time suffix parameter to local js scripts avoid browser caching
$templix->setDevJs(true); //default true
// add time suffix parameter to local images to avoid browser caching
$templix->setDevImg(true); //default false
// add clean callback when switch from prod to dev
$templix->setCleanCallback(function(){
});
Paths
//set compile directory
$templix->setDirCompile('.tmp/templix/compile/'); //by default
//set cache directory
$templix->setDirCache('.tmp/templix/cache/'); //by default
//add mtime directory registry to use when you use "cacheSync" attribute
$templix->setDirSync('.tmp/sync/'); //by default
//set current working directories in order you want templix look for
$templix->setDirCwd(['template/','redcat/template/']); //by default
//add directories to stack of current working directories
$templix->addDirCwd(['template/','redcat/template/',]);
//the template file to display on call of $templix->display();
$templix->setPath($file);
Paths to Plugins
Paths to plugins are based on class namespace and eventually, autoloading. Each class plugin name end with the upper case of first charater of markup and start with prefix which can be a namespace (ending with \\) or simple prefix., (*6)
The following rules are valable when you use directly PHP API display or setPath as same as you use markups include, extend, incorpore or attribute applyFile., (*7)
no prefix - look in each working directories of template and each parent templates, (*8)
<include "my-template.tml">
"./" prefix - look in priority in same directory than the current template, (*9)
<include "./my-template.tml">
"/" prefix - look in priority in at root of working directories in order they are defined, (*10)
<include "/my-template.tml">
"//" prefix - look in priority for abosulte path, (*11)
The main differences between HTML5 and XML/XHTML syntax is that in XML syntax we have to close every elements, it support self closing but there is not implicit self closing unlike in HTML5. In XML there is no support for shortcut attributes, all attributes have to be composed by a key and a value. In XML we have also to convert all HTML named entities in their numeric entities equivalent. The doctype is also different but except these few variations we can switch from one to other very simply.
In Templix if you change html5 doctype declaration "" to "", the output syntax will be automaticaly changed to XHTML without any change to do in your templates !
The parser support the most flexible syntax than is HTML5 with some Templix addons pecificity like shortcut value but, by dint of DOM conversion to PHP object, the output can be changed in XML very easyly. According to W3C specification, the following elements are implicitly self-closed:, (*12)
area
base
br
col
command
embed
hr
img
input
keygen
link
meta
param
script
source
style
track
wbr, (*13)
You can found how the self-closed implemation is done by taking a look at "RedCat\Templix\MarkupHtml5" namespace in "redcat/php/RedCat/Templix/MarkupHtml5" directory., (*14)
Markup Object Methods
Markups object will be called node in following documtentation., (*15)
closest
The closest method is used to find through the node's ancestors the first matching element which are closest from the current node., (*16)
$node->closest('form');
//will find the enclosing form if there is one
searchNode
The searchNode method is used to find the index of a node in the children nodes of the node if it's there. The second parameter can be used to start search from an index., (*17)
The find method is used to find matching selector in all enclosed nodes. The second parameter can be used to specify an index of result.
If you specify an index to "true" the result will not be an array of nodes but a nodes iterator object which you'll can traverse like an array and using a foreach but which can also be used to call sub methods like to a regular node., (*19)
foreach($node->find('img') as $img){
if(!$img->alt)
$img->alt = basename($img->src);
}
$node->find('a',0); //will get the first node of results
$node->find('a',1); //will get the second node of results
$allA = $node->find('ul>li',true)->find('a');
$node->find('ul>li',true)->remove();
children
The children method is used to find matching selector in first sub-level of nodes. Like in find method, the second parameter can be used to specify an index of result.
If you specify an index to "true" the result will not be an array of nodes but a nodes iterator object which you'll can traverse like an array and using a foreach but which can also be used to call sub methods like to a regular node., (*20)
foreach($node->children('img') as $img){
if(!$img->alt)
$img->alt = basename($img->src);
}
$node->children('a',0); //will get the first node of 'a' children
$node->children('a',1); //will get the second node of 'a' children
$childrenA = $node->children('ul>li',true)->children('a');
$node->children('ul>li',true)->remove();
merge
The merge method will merge the parameter node passed to method with children nodes of the node.
If an equivalent node allready exists the node will not be added to avoid duplication. If the parameter is scalar value it will be converted to a tree of nodes.
If the element didn't allready exists, it will be added after existing ones., (*21)
The premerge method will merge the parameter node passed to method with children nodes of the node.
If an equivalent node allready exists the node will not be added to avoid duplication. If the parameter is scalar value it will be converted to a tree of nodes.
Contrary to merge if the element didn't allready exists, it will be added before and not after existing ones., (*22)
The submerge method will merge children nodes of the parameter node passed to method with children nodes of the node.
Like in merge, if an equivalent node allready exists the node will not be added to avoid duplication. If the parameter is scalar value it will be converted to a tree of nodes., (*23)
The isSameNode method will compare the node to the node parameter based on children nodes, attributes and class name and will return a boolean. It's an equivalence comparison and not a strict comparison based on object memory reference., (*24)
The getAttributes method allow you to get the attributes as an associative array., (*25)
$attributes = $node->getAttributes();
hasAttribute
The hasAttribute method allow you to know if an attribute is defined., (*26)
if($node->hasAttribute('title')){
}
getElementsByTagName
The getElementsByTagName method is like the regular javascript method, it get the elements by tag name recursively starting with the calling node itself., (*27)
$divs = $node->getElementsByTagName('div');
write
The write method will clean the inner head, inner foot and children nodes before appending parameter, head and foot will be conserved. If the parameter is scalar value it will be converted to a tree of node., (*28)
The append method will add the parameter to children nodes after the existing ones. If the parameter is scalar value it will be converted to a tree of node., (*29)
The append method will add the parameter to children nodes before the existing ones. If the parameter is scalar value it will be converted to a tree of node., (*30)
The replaceWith method allow you to replace a node with an other in parent's children nodes. If the parameter is scalar value it will be converted to a tree of node., (*32)
The remove method will remove the node from parent's children nodes., (*33)
$node->remove();
applyFile
The applyFile method will read the filename, usually a ".tpl" file, which contain applicators markup to modify the node like the first level of markups do in extend., (*34)
$node->applyFile($filename);
before
The before method will add the parameter just before the node in parent's children nodes. If the parameter is scalar value it will be converted to a tree of node., (*35)
The after method will add the parameter just after the node in parent's children nodes. If the parameter is scalar value it will be converted to a tree of node., (*36)
The getIndex method return the index of the node in parent's children nodes., (*37)
$index = $node->getIndex();
getInnerMarkups
The getInnerMarkups method return the string version of inner children nodes., (*38)
$string = $node->getInnerMarkups();
getInner
The getInner method return the string version of inner head, then inner children nodes, and finaly inner foot., (*39)
$string = $node->getInner();
__toString
The __toString method return the whole node and all enclosed node as a string. This magic method is returned when you try to cast the node as string., (*40)
The clear method erase head, inner head, children nodes, inner foot, foot, previous sibling, next sibling, detach itself from the next and previous flow and set hiddenWrap to hide markup opener and closer output., (*41)
$node->clear();
clearInner
The clearInner method erase inner head, children nodes and inner foot., (*42)
$node->clearInner();
head
The head method unshift a raw content or source code to the head of the node, before opening markup. A second parameter can be used to specify a splice index. If the splice index is true the raw content will be pushed instead of unshifted., (*43)
The foot method push a raw content or source code to the foot of the node, after closing markup. A second parameter can be used to specify a splice index. If the splice index is true the raw content will be unshifted instead of pushed., (*44)
The innerHead method unshift a raw content or source code to the inner head of the node, after opening markup. A second parameter can be used to specify a splice index. If the splice index is true the raw content will be pushed instead of unshifted., (*45)
The innerFoot method push a raw content or source code to the inner foot of the node, before closing markup. A second parameter can be used to specify a splice index. If the splice index is true the raw content will be unshifted instead of pushed., (*46)
The attr method is a getter or setter for accessing temporary attributes.
Because of extend or apply, the DOM can be re-compiled to string and re-parsed. In this processus, all unvisible meta-data you can add to your object, like with the data method, will be wiped. So, there is a convention for passing meta-data in a node with the urlencoded key-value pairs "tmp-attr" attribute. This attribute is a visible attribute working with not "hiddenWrap" nodes (visible opening and closing markup), but they will be removed automaticaly just before the end of global compilation.
It will be a getter with one argument and a setter with two arguments., (*48)
The removeAttr method remove an attribute from opening markup of node., (*49)
$node->removeAttr('class');
remapAttr
The remapAttr method is used for add a key to a shortcut attribute or shortcut value according to its order in attributes. The first argument specify the key to add and the second argument the index of shortcut, starting with zero. The index is zero by default., (*50)
class Mynode extend \\RedCat\\Templix\\Markup{
function load(){
$this->remapAttr('src');
$this->remapAttr('async',1);
$src = $this->src;
$async = $this->async;
)
}
data
The data method is a getter or setter for accessing meta-data unvisible attributes.
Because of extend or apply, the DOM can be re-compiled to string and re-parsed. In this processus, all unvisible meta-data you can add to your object, like with the data method, will be wiped. To work around this behavior use tmpAttr instead of data.
It will be a getter with one argument and a setter with two arguments., (*51)
The css method is a getter or setter for accessing css properties of style attribute. It will be a getter with one argument and a setter with two arguments., (*52)
The removeClass method allow you to work on class attribute by removing class in a regular way without to have to work on class string attribute directly., (*53)
$node->removeClass('my-class');
addClass
The addClass method allow you to work on class attribute by adding class in a regular way without to have to work on class string attribute directly and avoiding duplication., (*54)
$node->addClass('my-class');
wrap
The wrap method allow you to enclose a node or a tree of nodes in a node. If you pass it a tree of node it will use the first top encloser node as the wrapper. If the parameter is scalar value it will be converted to a tree of node., (*55)
The unwrap method allow you to remove a wrapper. You can also use a selector to specify the closest matching wrapper you want to remove from ancestors. By default, it will be the closest encloser (selector "*")., (*56)
$node->unwrap();
$node->unwrap('div.my-wrapper');
createChild
The createChild method will create a node in children node from scalar content., (*57)
$div = $node->createChild('<div />');
recursive
The recursive method allow you to execute a callback on each node recursively and also break the recursion from callback context. The callback will be executed from deepers elements to top., (*58)
$node->recurse(function($subnode,&$break){
if($subnode->attr('data-find')){
$break = true; //break the recursion
}
});
arecursive
The recursive method allow you to execute a callback on each node recursively and also break the recursion from callback context. Contrary to recursive the callback will be executed from top elements to deepers., (*59)
$node->arecurse(function($subnode,&$break){
if($subnode->attr('data-find')){
$break = true; //break the recursion
}
});
getIterator magic
The getIterator magic method allow you to work with children nodes like if they were array of nodes and iterate over them with a foreach loop., (*60)
foreach($node as $childNode){
}
offsetSet magic
The offsetSet magic method allow you to work with children nodes like if they were an array of nodes and set a child node like an offset. If the parameter is scalar value it will be converted to a tree of node., (*61)
Some attributes trigger special behaviors injections and then becomes unvisible. The way to implements an attribute trigger function to a markup is to implements a method which will be named with load prefix followed by upper case first character of attribute name. The hyphen "-" in attribute name will be replaced by underscore "_" in method name. If you want to capture all attributes which is prefixed by a name followed by hyphen "-", like "data-" for example, you can implements "loadAttr" method ending with underscore "_". Let's take some example:, (*79)
The cacheSync attribute is used with a sync path. The content of the markup will be cached and regenered only if its modified time is older than the modified time of the sync path., (*81)
<ul cacheSync="tracks">
<foreach "$model->getTracks() as $k=>$v">
<li><?=$k?>:<?=$v?></li>
</foreach>
</ul>
To update the cache, (*82)
touch('.tmp/sync/tracks.sync');
For configure the path of sync files:, (*83)
$templix->setDirSync('.tmp/sync/'); //by default
cacheStatic
The cacheStatic attribute is used as shortcut attribute to cache indefinitely the content of the markup., (*84)
<ul cacheStatic>
<foreach "$model->getTracks() as $k=>$v">
<li><?=$k?>:<?=$v?></li>
</foreach>
</ul>
Markup Plugins:
after
Markup usage of after method. The after markup have to be used at first level inside or in ".tpl" with apply. It will add its content in document just after its selector targeted node(s)., (*85)
<extend>
<after main>
<img src="img/signature.png">
</after>
<after "main>article:nth-child(2)">
<article>Bla bla bla ...</article>
</after>
</extend>
append
Markup usage of append method. The append markup have to be used at first level inside or in ".tpl" with apply. It will add its content at end inside its selector targeted node(s)., (*86)
<extend>
<append main>
<img src="img/signature.png">
</append>
<append "body>main">
<article>Bla bla bla ...</article>
</append>
</extend>
apply
Markup usage of applyFile method. It's the reversed process of : the .tpl file will be able to use selector markups for work on the content of . The .tpl file is like a kind of application patcher function., (*87)
The {{this:property}} special syntax, specific to apply, allow you to access attributes of current targeted node tu build your apply in a more flexible and dynamic way. Tpl file:, (*88)
The {{compile:callback()}} special syntax, specific to apply, allow you to pre-compile some portions of code using attributes of current targeted node tu build a faster and more consistent compiled template. Tpl file:, (*89)
Markup usage of attr method. The attr markup have to be used at first level inside or in ".tpl" with apply. It will set its selector targeted node(s) attributes to its attributes and can also use some special behaviors starting by add or remove like addClass or removeClass., (*90)
<extend>
<attr selector="main > article:eq(0) > img:eq(2)" alt="Name for my image">
<attr "img.my-logo" alt="My Logo" src="img/logo.png">
<attr main addClass="about">
</extend>
attrappend
The attrappend markup have to be used at first level inside or in ".tpl" with apply. It will append its attributes to its selector targeted node(s) attributes., (*91)
The attrprepend markup have to be used at first level inside or in ".tpl" with apply. It will prepend its attributes to its selector targeted node(s) attributes., (*92)
Markup usage of before method. The before markup have to be used at first level inside or in ".tpl" with apply. It will add its content in document just before its selector targeted node(s)., (*93)
<extend>
<before main>
<img src="img/signature.png">
</before>
<before "main>article:nth-child(2)">
<article>Bla bla bla ...</article>
</before>
</extend>
The css markup can be used everywhere in document, even inside first level, to add a stylesheet link to head of document. If a link element whiche have href to the same url is allready present in head, it will not be duplicate. If the href is absolute or start with slash "/" default the prefix path "css/" will not be added. If the url isn't absolute and doesn't end with ".css" extension, the extension will be automaticaly added., (*96)
The eval markup can be used to execute the php independently of the rest of document so that the output can be parsed after by Templix., (*100)
$templix['outsideVar'] = true;
<?$insideVar = true;?>
<eval>
<?
//$outsideVar is defined here
//$insideVar is not defined here
echo '<img src="img/logo.png">';
?>
</eval>
If the image is found, height and with will be added by the parser (see img markup)., (*101)
extend
The extend markup will refer to a wrapper template, usualy in first level is the layout.
There can be many extend inside same template and you can extend an allready extended template file recursively.
It will suffix file name with ".xtml" by default and if it was left empty the default wrapper file will be ".xtml". It will contain other specifics elements that will work on DOM like: write, append, prepend, after, before, remove, replace, merge, premerge, submerge, attr, attrprepend, attrappend, css, js., (*102)
If the markup in first level is not an expected markup planned to work on DOM, it will be converted to markup and its name and attributes to selector. Let's take an example, this:, (*106)
If src is local, height or with is not defined and the file can be found, height and with attributes will be extracted and added automaticaly for improve browser rendering performances.
If devImg options is set to true, it will add a time suffix to avoid browser caching mechanism., (*111)
include
The include markup will compile a sub-template in a way that make it included by regular include from caller compiled template. It's not possible to work on the included template DOM from caller DOM, but the included template can access to caller DOM and work on it., (*112)
<incude "path/to/my/included-template.tml">
incorpore
The incorpore markup will completely incorpore a sub-template in the current template workflow. It's possible to work on the incorpored template DOM from caller DOM and the incorpored template can access to caller DOM and work on it too., (*113)
<incude "path/to/my/incorpored-template.tml">
js
The js markup can be used everywhere in document, even inside first level, to add a $js script call to the last script of body. If a $js call which have src to the same url is allready present in , (*114)
<js script>
<js "/path/to/my/script.js">
link
Regular HTML5 markup. If Templix devCss options is set to true, it will add a time suffix to its href to avoid browser caching mechanism, (*115)
merge
Markup usage of merge method. The merge markup have to be used at first level inside or in ".tpl" with apply. It will merge its nodes with children nodes of its selector targeted node(s). If an equivalent node allready exists the node will not be added to avoid duplication., (*116)
<extend>
<merge "body>main">
<article>Bla bla bla ...</article>
</merge>
</extend>
noparse
The parser not parse the markups inside it excepting pure PHP code. The parser will be turned off until it meet the ending markup , (*117)
The pre markup allow you to put unparsed code like in , (*118)
premerge
Markup usage of premerge method. The premerge markup have to be used at first level inside or in ".tpl" with apply. It will merge its nodes with children nodes of its selector targeted node(s). If an equivalent node allready exists the node will not be added to avoid duplication. Contrary to merge if the element didn't allready exists, it will be added before and not after existing ones., (*119)
<extend>
<premerge "body>main">
<article>Bla bla bla ...</article>
</premerge>
</extend>
</p>
<h4 id="plugin-prepend">prepend</h4>
<p>
Markup usage of <a href="templix#method-prepend">prepend method</a>.
The prepend markup have to be used at first level inside <extend>
or in "*.tpl*" with apply.
It will add its content at top inside its selector
targeted node(s).
<code class="lang-xml">
<extend>
<prepend main>
<img src="img/signature.png">
</prepend>
<prepend "body>main">
<article>Bla bla bla ...</article>
</prepend>
</extend>
remove
Markup usage of remove method. The remove markup have to be used at first level inside or in ".tpl" with apply. It will remove its selector targeted node(s)., (*120)
<extend>
<remove "span.some-widget">
</extend>
replace
The replace markup will replace the content of its selector targeted node(s) by its own content., (*121)
<extend>
<replace "body>main>article:eq(0)">
<article>Bla bla bla ...</article>
</replace>
</extend>
Markup usage of submerge method. The submerge markup have to be used at first level inside or in ".tpl" with apply. It will merge its children nodes with children nodes of its selector targeted node(s). Like in merge, if an equivalent node allready exists the node will not be added to avoid duplication, (*124)
<extend>
<submerge "body>main">
<article>Bla bla bla ...</article>
<article>And Bla bla bla ...</article>
</submerge>
</extend>
The var markup can be used to assign raw content to a variable. The variable can be regenered each time or cached if static attribute is shortcut attribute is used., (*127)
The vars markup will look for a "vars.$name.php" file in the template include path(s). This file will be included as dynamic but the variables it makes can also be incorpored as static content adding it the shortcut attribute "static"., (*128)
<vars basic />
<vars "my-static-vars" static />
write
Markup usage of write method. The write markup have to be used at first level inside or in ".tpl" with apply. It will write its content inside its selector targeted node(s), overwrite its inner content., (*129)
<extend>
<write main>
<article>Bla bla bla ...</article>
</write>
</extend>
Custom Plugins
Build your own plugins
To build your own plugins you have to set plugin prefix class path and then make a corresponding prefixed class.
You have to extend this class from "\RedCat\Templix\Markup". Let's take an example:, (*130)
<markdown>
# [See Away, Be Lite, Run Fast](http://redcatphp.com) ![Logo of RedCat](http://redcatphp.com/img/redcat.png) [REDCAT](http://redcatphp.com)
[The essential framework for web developers](http://redcatphp.com)
</markdown>
From RedCat\Plugin\Templix\Markup\Markdown.php, (*131)
Class name coresponding to prefix followed by upper case first character of markup name. If the markup name contains special characters they will be replaced by underscore "_" for class lookup., (*132)
<my-markup></my-markup>
namespace RedCat\\Plugin\\Templix\\Markup; //here is the namespace prefix
class My\_markup extends \\RedCat\\Templix\\Markup {}
Methods of plugins
The load method of the class is triggered when your markup is closed, by closing markup, self closing or implicit self closed. All DOM which is loaded before is accessible.
You can also implements the loaded method which is triggered when the whole document is loaded and so accessible from the method.
From the class you can access the attributes of the markup and all DOM with the markup object methods., (*133)
class Mymarkup extends \\RedCat\\Templix\\Markup {
function load(){
var\_dump( $this->getAttributes() );
}
function loaded(){
var\_dump( $this->closest('div')->getAttributes() );
}
}
Special properties of plugins
There are some special properties of markup class that can be overloaded to add special behaviors.
The hiddenWrap property, when set to true, tell templix that this markup have no output for its opening tag, closing tag, and so its attributes. Only its head, foot, and inner content will be displayed. Examples of this implemation are t, noparse, vars and all basic php syntax structural element or markup which will rewrite its content on load.
The noParseContent tell to the parser to not parse the markups inside it excepting pure PHP code. The parser will be turned off until it meet the ending markup corresponding to opened noParseContent markup, in this example . Examples of this implemation are noparse, script, style, code, and pre., (*134)