summaryrefslogtreecommitdiffstats
path: root/management-interface/lib/template.php
diff options
context:
space:
mode:
Diffstat (limited to 'management-interface/lib/template.php')
-rw-r--r--management-interface/lib/template.php335
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);
+ }
+
+}