<?php
/**
* manage the HTML output.
* block_template is a template parser/renderer see the template sample for more info on the way the template work
* @changelog 2005-12-07 - bugfixes _templatize didn't correctly send content parameter to _emit_signal method
* 2005-09-30 - remove no more used footer property
* - reset_ method now reset _sections property too
* - clean the box method
* 2005-09-28 - new parameter include_vars for method get_section_vars
* 2005-07-13 - new predefined tag parameter 'require' for required vars in section includes
* 2005-06-18 - new reset_ method
* 2005-06-17 - new predefined tag parameter 'tagcontent' for open/close tags
* - new predefined tag parameter 'preparse' to enable preparsing of parameter value
* 2005-06-07 - now register_callback() will return a pointer
* - add new method unregister_callback()
* - new methods highlight_str() & highlight_template_file()
* 2005-06-01 - add callback support on 'on-output' signal
* - output can return var or file
* - new set_safe_output method to protect block_template tags
* - bugfixes no more problem on file finishing on a sectioname (@#sectioname)
* 2005-05-24 - add new get_sections_select() method
* 2005-05-18 - add comment line support (with #)
* - new method choose_section
* - bugfix to avoid infinite loop problem when including section into themselves
* 2005-04-29 - removed some unused properties and method regarding sitename and page_title
* clean some error notice
* 2005-04-12 - add_css now support alternate stylesheets and direct css rules inputs, idem for js
* 2005-03-14 - remove some deprecated methods (no more menu related methods)
* - replace some deprecated method by some more logical ones
* 2005-03-10 - *NEW callback support
* - tags can now be closed with a / or by a closing tag and %= are replaced with @=
* 2005-02-27 - add the content-type meta tag support and betterify the meta management
* - add support for parameters in template tags ie: %=tagname param='value'=%
* - menu entrys can now be passed as a full html by setting the URL to null
*/
class block_template{
/** where all the body content will go */
var $content;
var $header;
/** string favicon link tag */
var $favicon;
/** array of css link tags */
var $css = array();
/** array of js link tags */
var $js = array();
/** string css definition that will go in the <style></style> tags inside the header */
var $_css;
/** string javascript code that will go in the <script></script> tags inside the header */
var $_js;
/** @private metas tags parameters */
var $metas = array();
/**
* @param str $page_title
* @param str $template_name (the directory containing the template must have the same name (case sensitive))
* @param str $template_dir directory containing templates subdirs
*/
function block_template($page_title,$template_name='default',$template_dir='template'){
$this->template_dir = $template_dir.(substr($template_dir,-1)=='/'?'':'/');
$this->template = $template_name?$template_name:'default';
$this->set_title($page_title);
# essaie de charger le fichier de template
$this->parse_template();
# ajoute les css par defaut
if(is_file($css = $this->template_dir.$this->template.'/css.css'))
$this->add_css($css);
elseif(is_file($css = $this->template_dir.$this->template.'/'.$this->template.'.css'))
$this->add_css($css);
}
/**
* send the rendered html code to STD-OUT (browser)
* cette fonction emetra le signal on-output voici prototype de rappelle callback(&$block_template,$vars,$return)
* si la fonction de rapelle renvoie autrechose que FALSE alors la sortie sera remplacé
* par la valeur retourné par la fonction de rappelle
*@param array $vars same as setcionvars in *templatize* methods
*@param mixed $return FALSE as default it will print the output to STDOUT as always
* you can set it to true to get the output page return as a function returned value
* and at last but not least you can pass a filename to save the document to.
*@return void (if $return=FALSE)| string HTML code of the page (if $return=TRUE) | bool (if $return='/path/to/filesave');
*/
function output($vars=null,$return=FALSE){
$out = $this->_emit_signal('on-output',$vars,$return); # return callback value if any
if(! $return){ # DEFAULT CASE PRINT ON STDOUT
if($out){
print($out);
}else{
print("<html>\n");
print($this->_header());
print($this->_body($vars));
print('</html>');
}
}elseif(is_string($return)){
if(! $fout = fopen($return,'w'))
return FALSE;
fwrite($fout,$out?$out:"<html>\n".$this->_header().$this->_body($vars).'</html>');
fclose($fout);
return TRUE;
}else{
return $out?$out:"<html>\n".$this->_header().$this->_body($vars).'</html>';
}
}
/*
* You will probably never use this one but if you need to display block_template tags (@=tagname/=@) in the output
* you can use this method to set the output safe.
* WARNING: this method won't work when the output mode is value (block_template::output(null,TRUE)).
* other way to say the same: it will only work in STDOUT and file output mode.
* @param bool $set set it either true or false
* @return handler | bool
*/
function set_safe_output($set=TRUE){
static $handle;
if($set){ # renvoie le pointeur de callback
if(isset($handle))
return $handle;
else
return $handle = $this->register_callback('on-output',array($this,'_safe_output')); # no need to work with reference as the emit_signal will send only a reference
}elseif($handle){ # libere le pointeur de callback si existant
$ret = $this->unregister_callback($handle);
unset($handle);
return TRUE;
}
return FALSE;
}
/**
* internally used as callback to protect eventual block_template tags in the output
* @see set_safe_output
* @private
*/
function _safe_output($block_template,$vars,$return){
if($return && !is_string($return) )
return FALSE; # avoid inifnite loop so kill if not in stdout or file output mode
# protect tags
$block_template->content = str_replace('@=','@=__SAFE__',$block_template->content);
if(! substr_count($block_template->content,'@=__SAFE__')) # no replacement so continue as always
return FALSE;
# some vars have been protected so we clean them
return str_replace("@=__SAFE__","@=",$block_template->output($vars,1));
}
/**
*
*/
/**
* parse a template file
* @param string $template_file filepath to the template file
* @param bool $overwrite will overwrite any previously loaded sections if a new one have the same name
* @param bool $halt_on_error will stop the script execution on error else will return FALSE
* @return bool
* @todo add dynamic include support
*/
function parse_template($template_file=null,$overwrite=TRUE,$halt_on_error=TRUE){
if(! $template_file)
$template_file = $this->template_dir.$this->template.'/template.php';
elseif( (! file_exists($template_file)) && file_exists($this->template_dir.$this->template.'/'.$template_file) )
$template_file = $this->template_dir.$this->template.'/'.$template_file;
if(! ($template = @file_get_contents($template_file)) ){
if(! $halt_on_error){
return FALSE;
}else{
echo "<b style='color:red;'>[TEMPLATE ERROR] can't open '$this->template' template files</b>";
exit();
}
}
# suppression des lignes de commentaires
$template = preg_replace("!^\s*#[^\n]*$!m",'',$template);
if(! preg_match_all("!(?:@#(\w+)\s*((?:[^@]+|@[^#])+)+)!",$template."\n",$m,PREG_SET_ORDER)) # add \n to correct a bug on last empty section loading
return FALSE;
foreach($m as $v){
if( (!$overwrite) && $this->section_exists($v[1]))
continue;
$this->_sections[$v[1]] = trim($v[2]);
}
return TRUE;
}
/**
* clean all read template sections,all css rules and the template name.
* @param string $template_name if passed then will load the new template files;
* @param bool $full if set to true then will also clean page_title, favicon, content, js, metas, _header
*/
function reset_($template_name=null,$full=FALSE){
$this->_css = null;
$this->css = array();
$this->template = null;
$this->_sections = array();
if($full){ # reset others vars
$this->_js = $this->favicon = $this->page_title = $this->content = $this->_header = null;
$this->js = $this->metas = array();
}
if(is_string($template_name))
$this->block_template($this->page_title,$template_name);
}
##### SETTINGS METHODS#####
/**
* set the page title
* @param string $title
*/
function set_title($title){
$this->page_title = strip_tags($title);
}
###### ADD HEAD CONTENT METHODS #####
/**
* add a favicon to the page
*/
function add_favicon($favicon){
$this->favicon = '<link rel="shortcut icon" href="'.$favicon.'" type="image/'.substr($favicon,strrpos('.',$favicon)+1).'">';
}
/**
* add an external css stylesheet or css header definition
* @param string $css path to css file or css rules
* @param string $title optionnal title for the stylesheet
* @param bool $alternate set to true for alternate stylesheet
*/
function add_css($css,$title=null,$alternate=FALSE){
if(preg_match('!{[^}]+}!',$css)) # in this case we consider that we received a css string
@$this->_css .= $css."\n";
else
$this->css[] = '<link href="'.$css.'" rel="'.($alternate?'alternate ':'').'stylesheet" type="text/css" '
.(is_string($title)?"title=\"$title\" ":'').'/>';
}
/**
* add a javascript file or function in the header
* @param string $js path to js file or javascript code to include in the header
*/
function add_js($js){
if(substr_count($js,';')) # in this case we consider that we received a js string
@$this->_js .= $js."\n";
else
$this->js[] = '<script src="'.$js.'" type="text/javascript" language="javascript"></script>';
}
/**
* prepare meta tags
* be aware that multiple calls to this methods for the same type will only append to the previous setted tag.
* in a word you can only set asingle meta tag for each type (so you can add keywords by successives call of this method usefull
* when you want to dinamicly set it form your content)
* @param string $content
* @param string $type (publisher,keywords,robots,description,author,copyright,...) New refresh,no-cache
*/
function add_meta($content,$type='description',$lang=null){
$type = strtolower($type);
if(! isset($this->metas[$type]))
$this->metas[$type] = $content.($lang?"\" lang=\"$lang":'');
else
$this->metas[$type] .= $content.($lang?"\" lang=\"$lang":'');
}
/**
* add a string to the header
* @param string $str string to hadd in the <head></head> HTML tags
*/
function add_header($str){
@$this->_header .= "$str\n";
}
###### ADD BODY CONTENT METHODS #####
/**
* ajoute du contenu dans la page
*/
function add_content($content){
if( func_num_args()>1) # @todo supprimer cette ligne # this is for old stuff detection you can safely delete those 2 lines
show(print_r(func_get_args(),1).print_r(debug_backtrace(),1),red,1,1);
$this->content .= $content;
}
/**
* add content by calling the templatize method
*/
function add_templatize_content($vars,$sectioname){
if(! $this->section_exists($sectioname)){
$this->content .= '<b style="color:red;">Missing section '.$sectioname.'</b>';
}else{
$this->content .= $this->templatize($vars,$sectioname);
}
}
function add_templatize_string_content($string,$sectionvars=null){
$this->content .= $this->templatize_string($string,$sectionvars=null);
}
/**
* easy way to add a box to content, that's only a quick way of doing block_template::add_content(block_template::box($content,$title,$boxname))
* see box for more details
*/
function add_box_content($content,$title=null,$boxname=''){
if($str = $this->box($content,$title,$boxname))
$this->add_content($str);
}
/**
* return a 'BOX_*' section in a more common way
* BOX_* sections are section containings 2 vars boxtitle and boxcontent
* this function is the same as calling block_template::templatize(array('boxtitle'=>'title','boxcontent'=>'content'),'BOX_NAME');
* @param string $content
* @param string $title may be ommit
* @param string $boxname the BOX_ section to use
*/
function box($content,$title='',$boxname=''){
if(! $boxname)
$boxname = 'BOX';
if( substr($boxname,0,3) != 'BOX' )
$boxname = 'BOX_'.$boxname;
# maintenant la boite
if( $boxname = $this->choose_section(array($boxname,'BOX')) )
$out = $this->templatize(array('boxtitle'=>$title,'boxcontent'=>$content),$boxname);
else
$out = "<div id=\"$boxname\"'>".($title?"$title ":'')."$content</div>";
return $out;
}
/**
* add some attribute to the body tag, an onload event for example
* @param string $paramname name of the attribute
* @param mixed $paramvalue value of the attribute
*/
function add_body_param($paramname,$paramvalue,$overwrite=FALSE){
if($overwrite)
$this->body_params[$paramname] = $paramvalue;
else
$this->body_params[$paramname] .= $paramvalue;
}
##### GESTION DES SIGNAUX #####
/**
* enregistre une fonction de callback qui sera appelé lors de certains signaux.
* @param string $signame nom du signal (on-load, on-output, on-templatize)
* @param mixed $callback nom de la fonction de callback (peut prendre un tableau array($object,$method))
* @param string $tagtype type de tag sur lequel on applique le callback
* 0|3| applique le callback sur tout les types de tag
* 1| applique le callback uniquement au tag unique
* 2| applique le callback sur des tags disposant de tag de fermeture
* @param string $sectioname null par defaut, contraint le callback a la section précisé, ou toutes les sections si null
* @see _emit_signal pour le prototype de rappelle
* @return int callback handler id
*/
function register_callback($signame,$callback,$tagtype=3,$sectioname=null){
static $handlers=array() ,$hid=0; # gestion de pointeurs sur les signaux
# dereferencement d'un signal pé-éxistant
if( $signame=='-unregister-' && is_int($callback)){ # on detruit le pointeur sur ce signal
if( count($handlers) <1 || ! is_array($h=$handlers[$callback]) ) # pointeur invalide
return FALSE;
unset($this->callbacks[$h[0]][$h[1]][$h[2]][$callback]);
unset($handlers[$callback]);
return TRUE;
}
# referencement du signal
if($tagtype != 1 && $tagtype !=2)
$tagtype = 3;
if(! $sectioname>0)
$sectioname = 'ALL';
$hid++;
$this->callbacks[$signame][$tagtype][$sectioname][$hid] = $callback;
$handlers[$hid] = array($signame,$tagtype,$sectioname);
return $hid;
}
/**
* permet de dereferencer un callback associé a un signal par le biais de la methode register_callback()
* @param int $cb_handler pointeur de callback renvoyé par la methode register_callback()
* @see register_callback()
* @return bool
*/
function unregister_callback($cb_handler){
return $this->register_callback('-unregister-',$cb_handler);
}
/**
* le prototype de la fonction de rappelle sera function callback(block_template object,$section,$tagname,$params,$content)
* @private
* cette methode est utilisé par l'objet en interne afin de gerer les signaux
* @param string $signame nom du signal emis (on-templatize,on-output);
* @see _templatize output
*/
function _emit_signal($signame,$params=null,$tagname=null,$content=null,$section=null){
$tagtype = (strlen($content)?2:1);
if(! isset($this->callbacks[$signame]))
return FALSE;
# on test d'abord les callbacks restreint a cette section et a ce type de tag
if(@is_array($this->callbacks[$signame][$tagtype][$section])){
foreach($this->callbacks[$signame][$tagtype][$section] as $cb){
$res = call_user_func($cb,&$this,$section,$tagname,$params,$content);
if($res !== FALSE && $res !==null )
return $res;
}
}
# ensuite ceux restreint a cette section quel que soit le type de tag
if(@is_array($this->callbacks[$signame][3][$section])){
foreach($this->callbacks[$signame][3][$section] as $cb){
$res = call_user_func($cb,&$this,$section,$tagname,$params,$content);
if($res !== FALSE && $res !==null )
return $res;
}
}
# puis ceux restreint a ce type de tag
if(@is_array($this->callbacks[$signame][$tagtype]['ALL'])){
foreach($this->callbacks[$signame][$tagtype]['ALL'] as $cb){
$res = call_user_func($cb,&$this,$section,$tagname,$params,$content);
if($res !== FALSE && $res !==null )
return $res;
}
}
# puis enfin les generalistes qui se foutent de la section ou du type de tag
if(@is_array($this->callbacks[$signame][3]['ALL'])){
foreach($this->callbacks[$signame][3]['ALL'] as $cb){
$res = call_user_func($cb,&$this,$section,$tagname,$params,$content);
if($res !== FALSE && $res !==null )
return $res;
}
}
return FALSE;
}
##### TEMPLATIZE METHODS #####
/*
* will templatize your datas you can have as much vars as you like
* optionnal sub section tag can be used by adding a * to the sectioname (ie: sectioname*)
* if so thoose sections will be checked that there's either subsection or at least one not null (null or false but not 0) value in it
* @param array $sectionvars is an indexed array with index in $sectionkey giving the correspoding datas
* @param string $sectioname self explain
* @param bool $section_optional (used in internal for optionnal sub section you'll normally never use this one by your own)
*/
function templatize($sectionvars,$sectioname,$section_optional=FALSE){
$sectioname = strtoupper($sectioname);
if(! $this->section_exists($sectioname) )
return FALSE;
$section = $this->_sections[$sectioname]; # recupere le contenu de la section
# $section_keys = $this->get_section_vars($sectioname); # recupere les tags de la section
return $this->_templatize($section,$sectionvars,$sectioname,$section_optional);
}
/**
* parse la chaine $string comme une section de template.
* Cela permet au programmeur de parser une chaine recue d'une base de données ou encore généré dynamiquement.
* @note Cette méthode à été ajouter car elle me parassait apporter une certaine souplesse dans l'utilisation de block_template,
* cependant n'en ayant jamais fait usage, je serais tres interresser d'etre informé de l'utilisation que vous pouriez en faire.
*/
function templatize_string($string,$sectionvars=null){
# $section_tags = $this->get_string_vars($string);
return $this->_templatize($string,$sectionvars);
}
/**
* methode interne pour les methodes 'templatize'
* @see templatize,templatize_string
* @private
* @param string $section contenu de la section (ou chaine si on a appeller templatize_string)
* @param array $sectionvars variables en provenance du programmeur
* @param string $sectioname le nom de la section sur laquelle on travaille
* @param bool $section_optional flag pour le traitement des sections incluse (par un tag)
* @return string
*/
function _templatize($section,$sectionvars,$sectioname=null,$section_optional=FALSE){
# recuperation des variables
if($sectioname && ($keys = $this->get_section_vars($sectioname)) )
$section_keys = &$keys;
elseif($section && ($keys = $this->get_string_vars($section)) )
$section_keys = &$keys;
if( @is_array($section_keys) ){ # ne traite les variables que si il y en a
# on verifie que les sections optionnelles recoivent au moins une variable non null
if( $section_optional){
if(isset($sectionvars['require'])){ # verifie les prérequis
$required = explode(',',$sectionvars['require']);
foreach($required as $req){
if(! (@$sectionvars[$req] || $this->section_exists($req)))
return FALSE;
}
}else{
foreach($section_keys as $key){
if( $this->section_exists($key['tagname']) || (isset($sectionvars[$key['tagname']]) && $sectionvars[$key['tagname']]!='') ){ $vars=TRUE;break; }
}
if(! isset($vars))
return FALSE;
}
}
if(! is_array($sectionvars)) $sectionvars = array();
# on remplace les tags
foreach($section_keys as $var){
#preparation des parametres de la fonction de callback
$_params = array_merge((array) @$var['params'],$sectionvars);
# peparsing des parametre si demandé
if(isset($_params['preparse'])){
if($preparse = explode(',',$_params['preparse'])){
unset($_params['preparse']);
foreach($preparse as $k){
$_params[$k] = $this->templatize_string($_params[$k],$_params);
}
}
}
# emission du signal on-templatize sur ce tag
$tmp_str = $this->_emit_signal('on-templatize',$_params,$var['tagname'] ,@$_params['tagcontent'],$sectioname);
if($tmp_str!==FALSE){
$section = str_replace($var['str_replace'],$tmp_str,$section);
continue;
}
# si le tag porte le nom d'une section on l'inclus
if(isset($this->_sections[$var['tagname']])){
if( (! $var['is_optionnal']) && isset($_params['require'])) $var['is_optionnal']=TRUE;
$section = str_replace($var['str_replace'],$this->templatize($_params,$var['tagname'],$var['is_optionnal']),$section);
continue;
}
# prepare la valeur de remplacement
if( isset($_params[$var['tagname']]) ){ # cherche un parametre du meme nom
$value = $_params[$var['tagname']];
# on verifie que ce n'est pas une reference vers un autre parametre
if( $value && $value[0]=='@' && isset($_params[substr($value,1)]) ){
$value = $_params[substr($value,1)];
}
}elseif( isset($_params['default']) ){ # sinon prend la valeur par defaut
$value = $_params['default'];
}else{
$value = '' ;
}
# si c'est le nom d'une section on remplace par la section (pas d'inclusion optionnelle ici)
if($this->section_exists($value) && $value !== $sectioname)
$section = str_replace($var['str_replace'],$this->templatize($_params,$value),$section);
else # sinon on remplace par sa valeur
$section = str_replace($var['str_replace'],$value,$section);
}
}
return $section;
}
##### GETTING VARS #####
/**
* renvoie les variables attendus par la section $sectioname du template
* @param string $sectioname le nom de la section
* @param bool $nocache par defaut vaut false ainsi les resultats sont gardé en cache de facon a accellerer les futures requetes.
* il peut s'averer utile de ne pas caché ses resultats (pour une section appeller une seule fois par exemple)
* auquel cas il suffit de passer cette option a TRUE
* @param bool $include_vars par defaut vaut FALSE si passer a TRUE alors retourne aussi les variables attendu par les sections incluses ou imbriqués.
* @return array or FALSE if none
* the array will contain arrays(tagname,params,str_replace,is_optionnal[,content]) for complex vars,
* where sectionvarname is equal to the sting return for single vars, params is an array of parameter array('paramname or int'=>'value',...)
* and finally the original_tag which is the complete tag as it is in the template (will be use for string replacement)
*/
function get_section_vars($sectioname,$nocache=FALSE,$include_vars=FALSE){
static $sectionvars,$fullsectionvars;
if(! $this->section_exists($sectioname)) # first of all check that the section exists
return FALSE;
if($include_vars){ # recursively append all included sections vars to the result
if( (!$nocache) && @is_array($fullsectionvars[$sectioname]) ) # return cached datas if exists according to $nocache
return $fullsectionvars[$sectioname];
# get first level sectionvars using or not cached datas
if(! is_array($svars = $this->get_section_vars($sectioname,$nocache,FALSE)) )
return FALSE;
# walk thru sectionvars to get vars of included sections.
foreach($svars as $var){
if($this->section_exists($var['tagname']) && is_array($vars_ = $this->get_section_vars($var['tagname'],$nocache,TRUE)) )
foreach($vars_ as $vars__) $svars[] = $vars__;
}
if($nocache)
return $svars;
else
return $fullsectionvars[$sectioname] = $svars;
}
if($nocache) # no cache so give the result as is
return $this->get_string_vars($this->_sections[$sectioname]);
# return cached content and create it if needed
if(isset($sectionvars[$sectioname]) && is_array($sectionvars[$sectioname]))
return $sectionvars[$sectioname];
else
return $sectionvars[$sectioname] = $this->get_string_vars($this->_sections[$sectioname]);
}
/**
* renvoie les variables contenue dans la chaine $string comme si c'était une section de template
* @param string string
* @todo devrait fonctionner selon un principe de 'pile' afin de permettre la lecture de tags imbriqués
*/
function get_string_vars($string){
# $tagexp = "!@=(\w+)(\*)?" # tagname
# ."((?:[^@]+|[^=]@)+)?" # params
#// ."(/)?=@((?(4)(.*?)@=/\\1=@))!s" ;
# ."(?:/=@|=@(.*?)@=/\\2=@)!s" ;
$tagexp = "!@=(\w+)(\*)?((?:\s+\w+(?:\s*=\s*([\"']).*?\\4))+)?\s*(?:/=@|=@(.*?)@=/\\1=@)!s";
# check single vars as needed
if(! preg_match_all($tagexp,$string,$m,PREG_SET_ORDER)){
$vars = FALSE;
}else{
foreach($m as $k=>$tagdata){
$vars[$k]['tagname'] = $tagdata[1];
$vars[$k]['is_optionnal'] = (bool) @$tagdata[2];
# $vars[$k]['is_optionnal'] = (bool) (substr($tagdata[1],-1)==='*');
if(isset($tagdata[3])){
preg_match_all("!\s+(\w+)(?:\s*=\s*(([\"'])?(?(3).*?\\3|[^\s=]+)))?!s",$tagdata[3],$m2,PREG_SET_ORDER);
unset($params);
foreach($m2 as $k2=>$v2){
if(! isset($v2[2])){
$params[] = $v2[1];
}else{
if(! isset($v2[3]))
$params[$v2[1]] = $v2[2];
else
eval('$params[$v2[1]] = '.$v2[2].';');
}
}
$vars[$k]['params'] = @$params;
}
if(isset($tagdata[5])){
# $vars[$k]['content'] = $tagdata[5];
# $vars[$k]['params']['tagcontent'] = $vars[$k]['content']; # Quick and dirty hack to enable the 'tagcontent' parameter
$vars[$k]['params']['tagcontent'] = $tagdata[5];
}
$vars[$k]['str_replace'] = $tagdata[0];
}
}
return $vars;
}
##### MANIPULATION DES SECTIONS #####
/**
* renvoie un tableau contenant le nom des sections disponibles dans le template
* @return array or FALSE si pas de sections
*/
function get_sections(){
if(! is_array($this->_sections)) return FALSE;
return array_keys($this->_sections);
}
/**
* retourne le code html d'un element select contenant la liste des sections du template.
* @param string $name nom de l'element de formulaire (valeur de l'attribut name de la balise select)
* @param string $selected nom de la section preselectionnée (si null alors essaie de trouver une occurence dans _POST ou _GET)
* @param bool $autoselect si oui alors ajoute un submit onchange
* @param string $id attribut id optionnel de la balise select.
* @return string HTML code
*/
function get_sections_select($name='template_section',$selected=null,$autoselect=TRUE,$id=null){
if(! $sections = $this->get_sections())
return "<b style='color:silver;'>Aucune section disponible</b>";
# try to find the selected value
if(is_null($selected) && (isset($_GET[$name])||isset($_POST[$name])) )
$selected = (@$_POST[$name]?$_POST[$name]:(@$_GET[$name]?$_GET[$name]:null));
# make option list
$opts[] = "<option value=\"\">- Sections du template $this->template -</option>";
foreach($sections as $sec){
$opts[] = "<option value=\"$sec\"".(($selected && $sec==$selected)?' selected="selected"':'')." >$sec</option>";
}
return "\n\t<select name=\"$name\"".($autoselect?' onchange="if(this.value!=\'\')this.form.submit();"':'').(is_string($id)?" id=\"$id\"":'')." >\n\t\t".implode("\n\t\t",$opts)."\n\t</select>";
}
/**
* retourne le contenue d'une section de template tel quel sans le parser
* @param string $sectioname
* @return string
*/
function get_section($sectioname){
return $this->section_exists($sectioname)?$this->_sections[$sectioname]:FALSE;
}
/**
* verifie qu'une section existe
* @param string $sectioname nom de la section dont on veut verifier l'existence
* @param bool $returnname si passer a TRUE alors la fonction retournera le nom de la section en cas de succes au lieu de TRUE
* @return bool
*/
function section_exists($sectioname,$returnname=FALSE){
$ret = isset($this->_sections[$sectioname]);
if($returnname && $ret)
return $sectioname;
return $ret;
}
/**
* prend une liste de nom de section sous forme de tableau ou de chaine et retourne la premiere qui est trouvé.
* cette fonction peut etre utile si votre application veut permettre l'utilisation de section par defaut au cas ou le
* template ne fournirais pas la section données par exemple: block_template->choose_section('SEC1|SEC2|SEC3) testera successivement
* les sections passé en arguments et retournera la premiere section existante.
* @param mixed $section_list string('SEC1|SEC2...') ou array(SEC1,SEC2..)
* @return string first section name matching an existing section or '' if no section match and false on input error
*/
function choose_section($section_list){
if(is_string($section_list))
$section_list = explode('|',$section_list);
if(! is_array($section_list))
return FALSE;
foreach($section_list as $v){
if($this->section_exists($v) )
return $v;
}
return '';
}
/**
* permet l'ajout dynamique de section par le programmeur
* @param string $sectioname le nom de la section
* @param string $section_content le contenu de la section
* @param bool $overwrite si passe a TRUE alors ecrasera une eventuelle section existante au lieu de renvoyer FALSE
*/
function add_section($sectioname,$section_content='',$overwrite=FALSE){
if($overwrite || !$this->section_exists($sectioname) )
$this->_sections[$sectioname] = $section_content;
else
return FALSE;
}
/**
* ajoute du contenu a la fin d'une section
* @param string $sectioname le nom de la section
* @param string $section_content contenu a ajouter
* @param bool $autocreate TRUE par defaut, si FALSE ne creera pas la section si elle n'existe pas
*/
function append_section($sectioname,$section_content,$autocreate=TRUE){
if( (!$this->section_exists($sectioname)) && !$autocreate )
return FALSE;
$this->_sections[$sectioname] = ($this->section_exists($sectioname)?$this->_sections[$sectioname]:'').$section_content;
}
/**
* ajoute du contenu au debut d'une section
* @param string $sectioname le nom de la section
* @param string $section_content contenu a ajouter
* @param bool $autocreate TRUE par defaut, si FALSE ne creera pas la section si elle n'existe pas
*/
function prepend_section($sectioname,$section_content,$autocreate=TRUE){
if( (!$this->section_exists($sectioname)) && !$autocreate )
return FALSE;
$this->_sections[$sectioname] = $section_content.($this->section_exists($sectioname)?$this->_sections[$sectioname]:'');
}
##### PREPARATION DES SORIES #####
/**
*Prepare the header to output
*@access Private
*/
function _header(){
$this->header = "<head>\n";
$this->header .= "<title>$this->page_title</title>\n";
# add the meta tags
if($this->metas){
$equivs = array('content-type','refresh','pragma','expires');
foreach($this->metas as $name=>$value){
if(in_array($name ,$equivs))
$this->header .= "<meta http-equiv='$name' content='$value' />\n";
else
$this->header .= "<meta name=\"$name\" content=\"$value\" />\n";
}
}
# add favicon
if(is_string($this->favicon))
$this->header .= $this->favicon."\n";
# add css
if(is_array($this->css))
$this->header .= implode("\n",$this->css);
if(is_string($this->_css))
$this->header .= '<style type="text/css">'.$this->_css.'</style>';
# add js
if(is_array($this->js))
$this->header .= implode("\n",$this->js);
if(is_string($this->_js))
$this->header .= "<script type=\"text/javascript\" language=\"javascript\">\n<!--\n".$this->_js."\n//-->\n</script>";
# add user specific content
$this->header .= (isset($this->_header)?$this->_header:'')."\n</head>\n";
return $this->header;
}
/**
*Prepare the body content to output
*@access Private
*@todo supprimer les variables logo et consorts
*/
function _body($bodyvars=null){
if(! is_array($bodyvars)) $bodyvars = array();
# prepare les parametres du tag body
if(@is_array($this->body_params)){
foreach($this->body_params as $paramname=>$paramvalue)
$bodytag .= " $paramname=\"$paramvalue\"";
$bodyvars['bodyparams'] = $bodytag;
}
$bodyvars['content'] = isset($this->content)?$this->content:'';
return $this->body = $this->templatize($bodyvars,'BODY');
}
/**
* retourne le code de la chaine comme un code source de template avec coloration syntaxique au format html
* @param str $str chaine de caractere a colorer
* @param str $outfile nom de fichier de sortie optionnel, si fournis alors la sortie sera sauvegarder dans un fichier.
*/
function highlight_str($str,$outfile=null){
if(! is_string($str))
return FALSE;
$str = htmlspecialchars($str);
$str = preg_replace('!(@#\w+)!',"<b style='color:#3333cc;'>$1</b>",$str);
$str = preg_replace('!(@=\w+)!',"<b style='color:#33cc33;'>$1",$str);
$str = preg_replace('!(=@)!',"$1</b>",$str);
# return "$str";
return "<code><pre>$str</pre></code>";
}
function highlight_section($sectioname,$outfile=null){
return $this->highlight_str($this->_sections[$sectioname],$outfile);
}
function highlight_template_file($file=null,$outfile=null){
if(is_null($file))
$file = $this->template_dir.$this->template.DIRECTORY_SEPARATOR.'template.php';
return $this->highlight_str(join('',file($file)),$outfile);
}
}
?>
|