redcatphp / templix
Templix - HTML5 based Template Engine with Recursive Extends and CSS3 Selectors to work on DOM like with Jquery
Requires
- php: >=5.4.0
README
No longer actively maintained. I work now with NodeJS and I recommand you to take a look at ReactJS, Next.JS and EJS
Templix
Templix is a powerfull markup syntax based template engine.
Features
- recursive extend
- CSS3 Selectors (jQuery/sizzle like) to work on DOM at compilation time
- PHP compliant
- onCompile binder
- PHP short-open-tag syntax support even if not enable in php.ini
- PHP syntax elements ported to HTML5
- HTML5/XML syntax
- extended Templix syntax
- As fast as simple include when compiled
- Possibility to build your own markup based logic language
- Markup Object Methods- closest
- searchNode
- match
- find
- children
- merge
- premerge
- submerge
- isSameNode
- getAttributes
- hasAttribute
- getElementsByTagName
- write
- append
- prepend
- each
- replaceWith
- remove
- applyFile
- before
- after
- getIndex
- getInnerMarkups
- getInner
- __toString
- clear
- clearInner
- head
- foot
- innerHead
- innerFoot
- attr
- tmpAttr
- removeAttr
- remapAttr
- data
- css
- removeClass
- addClass
- wrap
- unwrap
- createChild
- recursive
- arecursive
- getIterator magic
- offsetGet magic
- offsetSet magic
- offsetUnset magic
- offsetExists magic
- __get magic
- __set magic
- __isset magic
- __unset magic
- __invoke magic
- Attribute Plugins- vars
- cacheSync
- cacheStatic
- Markup Plugins- after
- append
- apply
- attr
- attrappend
- attrprepend
- before
- case
- code
- css
- else
- elseif
- end
- eval
- extend
- for
- foreach
- if
- img
- include
- incorpore
- js
- link
- merge
- premerge
- submerge
- noparse
- pre
- prepend
- remove
- replace
- return
- script
- switch
- t
- var
- vars
- write
Templix syntax
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:
<markup "my shortcut value" />
The markup between comment will not be parsed excepting the PHP.
onCompile binder
You can bind to templix some callback to trigger when the document is almost compiled and all its DOM is accessible.
$templix->onCompile(function($templix){ $templix->find('footer a')->addClass('footer-link'); });
Options
Dev
// 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.
$prefixDefault = Templix::getPluginPrefixDefault(); // Templix\\MarkupX\\ , Templix\\MarkupHtml5\\ , Templix\\ $templix->setPluginPrefix($prefixDefault); //by default $templix->addPluginPrefix($prefix,$prepend=true); //equivalent to prependPluginPrefix $templix->appendPluginPrefix($prefix); $templix->prependPluginPrefix($prefix);
Path relativity
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.
no prefix - look in each working directories of template and each parent templates
<include "my-template.tml">
"./" prefix - look in priority in same directory than the current template
<include "./my-template.tml">
"/" prefix - look in priority in at root of working directories in order they are defined
<include "/my-template.tml">
"//" prefix - look in priority for abosulte path
<include "//var/www/my-project.dev/templates/my-template.tml">
HTML5 Plugins
XHTML
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:
- area
- base
- br
- col
- command
- embed
- hr
- img
- input
- keygen
- link
- meta
- param
- script
- source
- style
- track
- wbr
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.
Markup Object Methods
Markups object will be called node in following documtentation.
closest
The closest method is used to find through the node's ancestors the first matching element which are closest from the current node.
$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.
$index = $node->searchNode($searchingNode); $index = $node->searchNode($searchingNode,2);
match
The match method is used to determine if a node is corresponding to a selector.
$node->match('#node-id'); $node->match('a.my-class'); $node->match('a[href="templix"]');
find
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.
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.
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.
$node->merge($otherNode); $node->merge('</li>unique element</li>');
premerge
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.
$node->premerge($otherNode); $node->premerge('</li>unique element</li>');
submerge
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.
$node->submerge($otherNode); $node->submerge('<ul></li>unique element</li></ul>');
isSameNode
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.
var\_dump( $node===$node ); //true var\_dump( $node->isSameNode($node) ); //true var\_dump( $node===$otherNode ); //false var\_dump( $node->isSameNode($otherNode) ); //true
getAttributes
The getAttributes method allow you to get the attributes as an associative array.
$attributes = $node->getAttributes();
hasAttribute
The hasAttribute method allow you to know if an attribute is defined.
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.
$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.
$node->write($nodes); $node->write('<span>New inner content</span>'); $node->write('New inner content');
append
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.
$node->append($nodes); $node->append('<span>New appending content</span>'); $node->append('New appending content');
prepend
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.
$node->prepend($nodes); $node->prepend('<span>New prepending content</span>'); $node->prepend('New prepending content');
each
The each method receive a callback as argument. It will apply on the node or iterate through an iterator node and apply on each node.
$node->find('a',true)->each(function($a){ echo $a->href."<br>"; });
replaceWith
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.
$node->replaceWith($otherNode); $node->replaceWith('<div>replaced</div>');
remove
The remove method will remove the node from parent's children nodes.
$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.
$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.
$node->before($nodes); $node->before('<span>Before content</span>'); $node->before('Before content');
after
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.
$node->after($nodes); $node->after('<span>After content</span>'); $node->after('After content');
getIndex
The getIndex method return the index of the node in parent's children nodes.
$index = $node->getIndex();
getInnerMarkups
The getInnerMarkups method return the string version of inner children nodes.
$string = $node->getInnerMarkups();
getInner
The getInner method return the string version of inner head, then inner children nodes, and finaly inner foot.
$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.
$string = $node->\_\_toString(); $string = (string)$node; $string = $node.'';
clear
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.
$node->clear();
clearInner
The clearInner method erase inner head, children nodes and inner foot.
$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.
$node->head('<?php echo time();?>'); $node->head($raw,2); $node->head($raw,true);
foot
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.
$node->head('<?php echo time();?>'); $node->head($raw,2); $node->head($raw,true);
innerHead
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.
$node->innerHead('<?php echo time();?>'); $node->innerHead($raw,2); $node->innerHead($raw,true);
innerFoot
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.
$node->innerFoot('<?php echo time();?>'); $node->innerFoot($raw,2); $node->innerFoot($raw,true);
attr
The attr method is a getter or setter for accessing attributes. It will be a getter with one argument and a setter with two arguments.
$node->attr('src','images/logo.png'); $src = $node->attr('src');
tmpAttr
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.
$node->tmpAttr('meta-data',$data); $meta = $node->tmpAttr('meta-data');
removeAttr
The removeAttr method remove an attribute from opening markup of node.
$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.
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.
$node->data('meta-data',$data); $meta = $node->data('meta-data');
css
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.
$height = $node->css('height'); if(substr($height,-2)=='px') $height = substr($height,0,-2); $node->css('height',($height+120).'px');
removeClass
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.
$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.
$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.
$node->wrap($wrapperNode); $node->wrap('<div class="my-wrapper" />');
unwrap
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 "*").
$node->unwrap(); $node->unwrap('div.my-wrapper');
createChild
The createChild method will create a node in children node from scalar content.
$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.
$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.
$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.
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.
$node[] = $appendNode; $node[] = '<a href="http://redcatphp.com">RedCat Framework</a>'; $node[5] = $indexedNode;
This is equivalent to:
$node->append($appendNode); $node->append('<a href="http://redcatphp.com">RedCat Framework</a>'); $node->append($indexedNode,5);
offsetGet magic
The offsetGet magic method allow you to work with children nodes like if they were an array of nodes and get a child node like an offset.
$childNode4 = $node[4];
This is equivalent to:
$childNode4 = $node->children('\*',4);
offsetExists magic
The offsetGet magic method allow you check if a child node exists.
if(isset($node[0])){ }
This is equivalent to:
if(!is\_null($node->children('\*',0))){ }
offsetUnset magic
The offsetGet magic method allow you to remove a child node.
unset($node[1]);
This is equivalent to:
$node[1]->remove();
__get magic
The __get magic method allow you to directly get an attribute.
$src = $node->src;
This is equivalent to:
$src = $node->attr('src');
set magic
The __set magic method allow you to directly set an attribute.
$node->src = $src;
This is equivalent to:
$node->attr('src',$src);
__isset magic
The __isset magic method allow you to directly check if node has an attribute.
if(isset($node->src)){ }
This is equivalent to:
if($node->hasAttribute('src')){ }
__unset magic
The __unset magic method allow you to directly remove an attribute.
unset($node->src);
This is equivalent to:
$node->removeAttr('src');
__invoke magic
The __invoke magic method allow you to directly work with a collection iterator.
$node('ul>li>a')->addClass('my-class');
This is equivalent to:
$node->find('ul>li>a',true)->addClass('my-class');
Native Plugins
Attribute Plugins
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:
<mymarkup src="path.ext" data-meta="Some metadata" data-other="Other metadata" />
class Mymarkup{ function loadSrc($v){ var\_dump( $v ); //will output 'path.ext' } function loadData\_meta($v){ var\_dump( $v ); //will output 'Some metadata' } function loadData\_($v,$k){ var\_dump( $v ); //will output 'Some metadata' and 'Other metadata' var\_dump( $k ); //will output 'meta' and 'other' } }
Universal Attribute Plugins:
vars
The vars attribute is used to wrap inner content with sprintf interpolation function.
<?$name = 'Jo';?> <?$lastname = 'Surikat';?> <span vars="'Jo','Surikat'">Hi %s !</span> <span vars="$name,$lastname">Hi %s %s !</span>
cacheSync
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.
<ul cacheSync="tracks"> <foreach "$model->getTracks() as $k=>$v"> <li><?=$k?>:<?=$v?></li> </foreach> </ul>
To update the cache
touch('.tmp/sync/tracks.sync');
For configure the path of sync files:
$templix->setDirSync('.tmp/sync/'); //by default
cacheStatic
The cacheStatic attribute is used as shortcut attribute to cache indefinitely the content of the markup.
<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).
<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).
<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.
<apply "form-validation.tpl"> <form> <!-- ... --> </form> </apply>
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:
<write selector="textarea[name]"> <?=isset($\_POST['{{this:name}}'])?$\_POST['{{this:name}}']:'{{this:value}}'?> </write>
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:
<after selector="input[name][type!=checkbox][type!=hidden], select[name], textarea[name]"> <? if(isset($formErrors)&&isset($formErrors["{{compile: rtrim(str\_replace(array('[',']'),array('.',''),'{{this:name}}'),'.') }}"])){ ?><small class="help-block"><?=$formErrors["{{compile: rtrim(str\_replace(array('[',']'),array('.',''),'{{this:name}}'),'.') }}"]?></small><? } ?> </after>
attr
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.
<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.
<extend> <attrappend "img.my-logo" alt=" - Me"> </extend>
attrprepend
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.
<extend> <attrprepend "img.my-logo" alt="Me -"> </extend>
before
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).
<extend> <before main> <img src="img/signature.png"> </before> <before "main>article:nth-child(2)"> <article>Bla bla bla ...</article> </before> </extend>
case
Case is a basic php syntax structural element.
<switch "$switcher"> <case hello> Hello </case> <case "bye" /> Bye <break> </switch>
code
The code markup allow you to put unparsed code like in <script> , <style> or . It's content will be converted to html entities. The following content will display like this without interpretation.
<code class="lang-xml"> <switch "$switcher"> <case hello> Hello </case> <case "bye" /> Bye <break> </switch> </code>
css
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.
<css style> <css "/path/to/my/stylesheet.css">
else
elseif is a basic php syntax structural element.
<if "$cond"> <else> </if> <if "$cond" /> <else> <end>
elseif
elseif is a basic php syntax structural element.
<if "$cond"> <elseif "$cond"> </if> <if "$cond" /> <elseif "$cond"> <end>
end
end is a basic php syntax structural element corresponding to "}".
<if "$cond" /> <end> <switch "$switcher" /> <end> <foreach "$var as $v" /> <end>
eval
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.
$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).
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.
<extend> <main> <h1>Hi</h1> </main> </extend>
<extend "header.xtml"> <append "title"> - RedCat</append> </extend> <extend "footer.xtml"> <prepend "footer">RedCat -</prepend> </extend>
The first level markups will be applied in order. In the following example the
content "Hi" will be overwrited by "Hello"
<extend> <main> <h1>Hi</h1> </main> <write "main>h1:eq(0)"> Hello </write> </extend>
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:
<extend> <article id="something" class="interesting"> <h2>Something interesting</h2> </article> </extend>
is equivalent to this:
<extend> <write "article[class='interesting'][id='something']"> <h2>Something interesting</h2> </write> </extend>
for
for is a basic php syntax structural element.
<for "$i=0;$i<10;$++"> </for> <for i="10"> </for> <for from="0" to="10"> </for>
foreach
foreach is a basic php syntax structural element.
<foreach "$var as $k=>$v"> <?php echo $k;?>:<?php echo $v;?></foreach> <foreach "$var" key="k" val="v"> <?php echo $k;?>:<?php echo $v;?></foreach>
if
if is a basic php syntax structural element.
<if "$cond"> </if> <if "$cond" /> <end>
img
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.
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.
<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.
<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 <script>, it will not be duplicate.
<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
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.
<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 <script>. There is a same implemation for the style and script markup.
class Noparse extends \\RedCat\\Templix\\Markup{ protected $hiddenWrap = true; protected $noParseContent = true; }
pre
The pre markup allow you to put unparsed code like in <script> , <style> or . It's content will be converted to html entities.
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.
<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).
<extend> <remove "span.some-widget"> </extend>
replace
The replace markup will replace the content of its selector targeted node(s) by its own content.
<extend> <replace "body>main>article:eq(0)"> <article>Bla bla bla ...</article> </replace> </extend>
return
Return is a basic php syntax structural element.
<return "$result">
script
Regular HTML5 <script> markup, with implicit type="text/javascript" if not defined. If he have src attribute and Templix devJs options is set to true, it will add a time suffix to its src to avoid browser caching mechanism.
submerge
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
<extend> <submerge "body>main"> <article>Bla bla bla ...</article> <article>And Bla bla bla ...</article> </submerge> </extend>
switch
Switch is a basic php syntax structural element.
<switch "$switcher"> <case hello> Hello </case> <case "bye" /> Bye <break> </switch> <switch "$switcher" /> <end>
t
The t markup can be used like vars attribute, is transparent and can be used to work with gettext translation and sprintf.
<?$name = 'Jo';?> <?$lastname = 'Surikat';?> <t "'Jo','Surikat'">Hi %s %s !</t> <t "$name,$lastname">Hi %s %s !</t>
var
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.
<var compilation static> <span>Timestamp at compilation: <?=time()?>.</span> </var> <var execution> <span>Timestamp execution: <?=time()?>.</span> </var> <?=$compilation?> <?=$execution?>
vars
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".
<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.
<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:
$templix->addPluginPrefix('RedCat\\Plugin\\Templix\\Markup\\');
<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
namespace RedCat\\Plugin\\Templix\\Markup; class Markdown extends \\RedCat\\Templix\\Markup { protected $hiddenWrap = true; protected $noParseContent = true; function load(){ $this->remapAttr('file'); if($this->file) $text = file\_get\_contents($this->file); else{ $text = $this->getInnerMarkups(); $x = explode("\\n",$text); foreach($x as &$v) $v = ltrim($v); $text = implode("\\n",$x); } $this->clearInner(); $md = new Parsedown(); $this->innerHead[] = $md->text($text); } }
Class name of plugins
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.
<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.
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.
class Mymarkup extends \\RedCat\\Templix\\Markup { protected $hiddenWrap = true; protected $noParseContent = true; }