diff options
Diffstat (limited to 'management-interface/lib/template.php')
-rw-r--r-- | management-interface/lib/template.php | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/management-interface/lib/template.php b/management-interface/lib/template.php new file mode 100644 index 0000000..59ccb97 --- /dev/null +++ b/management-interface/lib/template.php @@ -0,0 +1,335 @@ +<?php + +/* + Copyright (c) 2009-2014 F3::Factory/Bong Cosca, All rights reserved. + + This file is part of the Fat-Free Framework (http://fatfree.sf.net). + + THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF + ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + Please see the license.txt file for more information. +*/ + +//! XML-style template engine +class Template extends Preview { + + //@{ Error messages + const + E_Method='Call to undefined method %s()'; + //@} + + protected + //! Template tags + $tags, + //! Custom tag handlers + $custom=array(); + + /** + * Template -set- tag handler + * @return string + * @param $node array + **/ + protected function _set(array $node) { + $out=''; + foreach ($node['@attrib'] as $key=>$val) + $out.='$'.$key.'='. + (preg_match('/\{\{(.+?)\}\}/',$val)? + $this->token($val): + Base::instance()->stringify($val)).'; '; + return '<?php '.$out.'?>'; + } + + /** + * Template -include- tag handler + * @return string + * @param $node array + **/ + protected function _include(array $node) { + $attrib=$node['@attrib']; + return + '<?php '.(isset($attrib['if'])? + ('if ('.$this->token($attrib['if']).') '):''). + ('echo $this->render('. + (preg_match('/\{\{(.+?)\}\}/',$attrib['href'])? + $this->token($attrib['href']): + Base::instance()->stringify($attrib['href'])).','. + '$this->mime,get_defined_vars()); ?>'); + } + + /** + * Template -exclude- tag handler + * @return string + **/ + protected function _exclude() { + return ''; + } + + /** + * Template -ignore- tag handler + * @return string + * @param $node array + **/ + protected function _ignore(array $node) { + return $node[0]; + } + + /** + * Template -loop- tag handler + * @return string + * @param $node array + **/ + protected function _loop(array $node) { + $attrib=$node['@attrib']; + unset($node['@attrib']); + return + '<?php for ('. + $this->token($attrib['from']).';'. + $this->token($attrib['to']).';'. + $this->token($attrib['step']).'): ?>'. + $this->build($node). + '<?php endfor; ?>'; + } + + /** + * Template -repeat- tag handler + * @return string + * @param $node array + **/ + protected function _repeat(array $node) { + $attrib=$node['@attrib']; + unset($node['@attrib']); + return + '<?php '. + (isset($attrib['counter'])? + (($ctr=$this->token($attrib['counter'])).'=0; '):''). + 'foreach (('. + $this->token($attrib['group']).'?:array()) as '. + (isset($attrib['key'])? + ($this->token($attrib['key']).'=>'):''). + $this->token($attrib['value']).'):'. + (isset($ctr)?(' '.$ctr.'++;'):'').' ?>'. + $this->build($node). + '<?php endforeach; ?>'; + } + + /** + * Template -check- tag handler + * @return string + * @param $node array + **/ + protected function _check(array $node) { + $attrib=$node['@attrib']; + unset($node['@attrib']); + // Grab <true> and <false> blocks + foreach ($node as $pos=>$block) + if (isset($block['true'])) + $true=array($pos,$block); + elseif (isset($block['false'])) + $false=array($pos,$block); + if (isset($true,$false) && $true[0]>$false[0]) + // Reverse <true> and <false> blocks + list($node[$true[0]],$node[$false[0]])=array($false[1],$true[1]); + return + '<?php if ('.$this->token($attrib['if']).'): ?>'. + $this->build($node). + '<?php endif; ?>'; + } + + /** + * Template -true- tag handler + * @return string + * @param $node array + **/ + protected function _true(array $node) { + return $this->build($node); + } + + /** + * Template -false- tag handler + * @return string + * @param $node array + **/ + protected function _false(array $node) { + return '<?php else: ?>'.$this->build($node); + } + + /** + * Template -switch- tag handler + * @return string + * @param $node array + **/ + protected function _switch(array $node) { + $attrib=$node['@attrib']; + unset($node['@attrib']); + foreach ($node as $pos=>$block) + if (is_string($block) && !preg_replace('/\s+/','',$block)) + unset($node[$pos]); + return + '<?php switch ('.$this->token($attrib['expr']).'): ?>'. + $this->build($node). + '<?php endswitch; ?>'; + } + + /** + * Template -case- tag handler + * @return string + * @param $node array + **/ + protected function _case(array $node) { + $attrib=$node['@attrib']; + unset($node['@attrib']); + return + '<?php case '.(preg_match('/\{\{(.+?)\}\}/',$attrib['value'])? + $this->token($attrib['value']): + Base::instance()->stringify($attrib['value'])).': ?>'. + $this->build($node). + '<?php '.(isset($attrib['break'])? + 'if ('.$this->token($attrib['break']).') ':''). + 'break; ?>'; + } + + /** + * Template -default- tag handler + * @return string + * @param $node array + **/ + protected function _default(array $node) { + return + '<?php default: ?>'. + $this->build($node). + '<?php break; ?>'; + } + + /** + * Assemble markup + * @return string + * @param $node array|string + **/ + protected function build($node) { + if (is_string($node)) + return parent::build($node); + $out=''; + foreach ($node as $key=>$val) + $out.=is_int($key)?$this->build($val):$this->{'_'.$key}($val); + return $out; + } + + /** + * Extend template with custom tag + * @return NULL + * @param $tag string + * @param $func callback + **/ + function extend($tag,$func) { + $this->tags.='|'.$tag; + $this->custom['_'.$tag]=$func; + } + + /** + * Call custom tag handler + * @return string|FALSE + * @param $func callback + * @param $args array + **/ + function __call($func,array $args) { + if ($func[0]=='_') + return call_user_func_array($this->custom[$func],$args); + if (method_exists($this,$func)) + return call_user_func_array(array($this,$func),$args); + user_error(sprintf(self::E_Method,$func)); + } + + /** + * Parse string for template directives and tokens + * @return string|array + * @param $text string + **/ + function parse($text) { + // Build tree structure + for ($ptr=0,$len=strlen($text),$tree=array(),$node=&$tree, + $stack=array(),$depth=0,$tmp='';$ptr<$len;) + if (preg_match('/^<(\/?)(?:F3:)?'. + '('.$this->tags.')\b((?:\h+[\w-]+'. + '(?:\h*=\h*(?:"(?:.+?)"|\'(?:.+?)\'))?|'. + '\h*\{\{.+?\}\})*)\h*(\/?)>/is', + substr($text,$ptr),$match)) { + if (strlen($tmp)) + $node[]=$tmp; + // Element node + if ($match[1]) { + // Find matching start tag + $save=$depth; + $found=FALSE; + while ($depth>0) { + $depth--; + foreach ($stack[$depth] as $item) + if (is_array($item) && isset($item[$match[2]])) { + // Start tag found + $found=TRUE; + break 2; + } + } + if (!$found) + // Unbalanced tag + $depth=$save; + $node=&$stack[$depth]; + } + else { + // Start tag + $stack[$depth]=&$node; + $node=&$node[][$match[2]]; + if ($match[3]) { + // Process attributes + preg_match_all( + '/(?:\b([\w-]+)\h*'. + '(?:=\h*(?:"(.+?)"|\'(.+?)\'))?|'. + '(\{\{.+?\}\}))/s', + $match[3],$attr,PREG_SET_ORDER); + foreach ($attr as $kv) + if (isset($kv[4])) + $node['@attrib'][]=$kv[4]; + else + $node['@attrib'][$kv[1]]= + (empty($kv[2])? + (empty($kv[3])?NULL:$kv[3]):$kv[2]); + } + if ($match[4]) + // Empty tag + $node=&$stack[$depth]; + else + $depth++; + } + $tmp=''; + $ptr+=strlen($match[0]); + } + else { + // Text node + $tmp.=substr($text,$ptr,1); + $ptr++; + } + if (strlen($tmp)) + // Append trailing text + $node[]=$tmp; + // Break references + unset($node); + unset($stack); + return $tree; + } + + /** + * Class constructor + * return object + **/ + function __construct() { + $ref=new ReflectionClass(__CLASS__); + $this->tags=''; + foreach ($ref->getmethods() as $method) + if (preg_match('/^_(?=[[:alpha:]])/',$method->name)) + $this->tags.=(strlen($this->tags)?'|':''). + substr($method->name,1); + } + +} |