5 require_once ROOT
. '/include/libs/template_lite/class.template.php';
7 class Template
extends \Template_Lite
9 static protected $_instance = null;
11 static public function getInstance()
13 return self
::$_instance ?
: self
::$_instance = new Template
;
16 private function __clone()
20 public function __construct()
22 parent
::__construct();
26 $this->compile_dir
= DATA_ROOT
. '/cache/compiled';
27 $this->template_dir
= ROOT
. '/templates';
29 $this->compile_check
= true;
31 $this->reserved_template_varname
= 'tpl';
33 $this->assign('www_url', WWW_URL
);
34 $this->assign('self_url', utils
::getSelfUrl());
36 $this->assign('is_logged', false);
40 $tpl = Template
::getInstance();
42 function tpl_csrf_field($params)
44 $name = utils
::CSRF_field_name($params['key']);
45 $value = utils
::CSRF_create($params['key']);
47 return '<input type="hidden" name="'.$name.'" value="'.$value.'" />';
50 function tpl_form_field($params)
52 if (!isset($params['name']))
53 throw new \
BadFunctionCallException('name argument is mandatory');
55 $name = $params['name'];
57 if (isset($_POST[$name]))
58 $value = $_POST[$name];
59 elseif (isset($params['data']) && isset($params['data'][$name]))
60 $value = $params['data'][$name];
61 elseif (isset($params['default']))
62 $value = $params['default'];
71 if (isset($params['checked']))
73 if ($value == $params['checked'])
74 return ' checked="checked" ';
78 elseif (isset($params['selected']))
80 if ($value == $params['selected'])
81 return ' selected="selected" ';
86 return htmlspecialchars((string)$value, ENT_QUOTES
, 'UTF-8');
89 function tpl_format_tel($n)
91 $n = preg_replace('![^\d\+]!', '', $n);
93 if (substr($n, 0, 1) == '+')
95 $n = preg_replace('!^\+(?:1|2[07]|2\d{2}|3[0-469]|3\d{2}|4[013-9]|'
96 . '4\d{2}|5[1-8]|5\d{2}|6[0-6]|6\d{2}|7\d|8[1-469]|8\d{2}|'
97 . '9[0-58]|9\d{2})!', '\\0 ', $n);
99 elseif (preg_match('/^\d{10}$/', $n))
101 $n = preg_replace('!(\d{2})!', '\\1 ', $n);
107 function tpl_strftime_fr($ts, $format)
109 return utils
::strftime_fr($format, $ts);
112 function tpl_date_fr($ts, $format)
114 return utils
::date_fr($format, $ts);
117 function tpl_format_droits($params)
119 $droits = $params['droits'];
121 $out = ['connexion' => '', 'inscription' => '', 'membres' => '', 'compta' => '',
122 'wiki' => '', 'config' => ''];
124 Membres
::DROIT_AUCUN
=> 'aucun',
125 Membres
::DROIT_ACCES
=> 'acces',
126 Membres
::DROIT_ECRITURE
=> 'ecriture',
127 Membres
::DROIT_ADMIN
=> 'admin',
130 foreach ($droits as $cle=>$droit)
132 $cle = str_replace('droit_', '', $cle);
134 if (array_key_exists($cle, $out))
137 $class = $classes[$droit];
141 if ($cle == 'connexion')
143 if ($droit == Membres
::DROIT_AUCUN
)
144 $desc = 'N\'a pas le droit de se connecter';
146 $desc = 'A le droit de se connecter';
148 elseif ($cle == 'inscription')
150 if ($droit == Membres
::DROIT_AUCUN
)
151 $desc = 'N\'a pas le droit de s\'inscrire seul';
153 $desc = 'A le droit de s\'inscrire seul';
155 elseif ($cle == 'config')
159 if ($droit == Membres
::DROIT_AUCUN
)
160 $desc = 'Ne peut modifier la configuration';
162 $desc = 'Peut modifier la configuration';
164 elseif ($cle == 'compta')
170 $s = strtoupper($cle[0]);
174 $desc = ucfirst($cle). ' : ';
176 if ($droit == Membres
::DROIT_AUCUN
)
177 $desc .= 'Pas accès';
178 elseif ($droit == Membres
::DROIT_ACCES
)
179 $desc .= 'Lecture uniquement';
180 elseif ($droit == Membres
::DROIT_ECRITURE
)
181 $desc .= 'Lecture & écriture';
183 $desc .= 'Administration';
186 $out[$cle] = '<b class="'.$class.' '.$cle.'" title="'
187 .htmlspecialchars($desc, ENT_QUOTES
, 'UTF-8').'">'.$s.'</b>';
191 return implode(' ', $out);
194 function tpl_format_wiki($str)
196 $str = utils
::htmlLinksOnUrls($str);
197 $str = utils
::htmlSpip($str);
198 $str = utils
::htmlGarbage2xhtml($str);
202 function tpl_liens_wiki($str, $prefix)
204 return preg_replace_callback('!<a href="([^/.:@]+)">!i', function ($matches) use ($prefix) {
205 return '<a href="' . $prefix . Wiki
::transformTitleToURI($matches[1]) . '">';
209 function tpl_pagination($params)
211 if (!isset($params['url']) ||
!isset($params['page']) ||
!isset($params['bypage']) ||
!isset($params['total']))
212 throw new \
BadFunctionCallException("Paramètre manquant pour pagination");
214 if ($params['total'] == -1)
217 $pagination = utils
::getGenericPagination($params['page'], $params['total'], $params['bypage']);
219 if (empty($pagination))
222 $out = '<ul class="pagination">';
224 foreach ($pagination as &$page)
228 if (!empty($page['class']))
229 $attributes .= ' class="' . htmlspecialchars($page['class']) . '" ';
231 $out .= '<li'.$attributes.'>';
235 if (!empty($page['accesskey']))
236 $attributes .= ' accesskey="' . htmlspecialchars($page['accesskey']) . '" ';
238 $out .= '<a' . $attributes . ' href="' . str_replace('[ID]', htmlspecialchars($page['id']), $params['url']) . '">';
239 $out .= htmlspecialchars($page['label']);
241 $out .= '</li>' . "\n";
249 function tpl_diff($params)
251 if (!isset($params['old']) ||
!isset($params['new']))
253 throw new Template_Exception('Paramètres old et new requis.');
256 $old = $params['old'];
257 $new = $params['new'];
259 require_once ROOT
. '/include/libs/diff/class.simplediff.php';
260 $diff = \simpleDiff
::diff_to_array(false, $old, $new, 3);
262 $out = '<table class="diff">';
265 foreach ($diff as $i=>$line)
269 $out .= '<tr><td colspan="5" class="separator"><hr /></td></tr>';
272 list($type, $old, $new) = $line;
274 $class1 = $class2 = '';
277 if ($type == \simpleDiff
::INS
)
280 $t2 = '<b class="icn">➕</b>';
281 $old = htmlspecialchars($old, ENT_QUOTES
, 'UTF-8');
282 $new = htmlspecialchars($new, ENT_QUOTES
, 'UTF-8');
284 elseif ($type == \simpleDiff
::DEL
)
287 $t1 = '<b class="icn">➖</b>';
288 $old = htmlspecialchars($old, ENT_QUOTES
, 'UTF-8');
289 $new = htmlspecialchars($new, ENT_QUOTES
, 'UTF-8');
291 elseif ($type == \simpleDiff
::CHANGED
)
295 $t1 = '<b class="icn">➖</b>';
296 $t2 = '<b class="icn">➕</b>';
298 $lineDiff = \simpleDiff
::wdiff($old, $new);
299 $lineDiff = htmlspecialchars($lineDiff, ENT_QUOTES
, 'UTF-8');
301 // Don't show new things in deleted line
302 $old = preg_replace('!\{\+(?:.*)\+\}!U', '', $lineDiff);
303 $old = str_replace(' ', ' ', $old);
304 $old = str_replace('-] [-', ' ', $old);
305 $old = preg_replace('!\[-(.*)-\]!U', '<del>\\1</del>', $old);
307 // Don't show old things in added line
308 $new = preg_replace('!\[-(?:.*)-\]!U', '', $lineDiff);
309 $new = str_replace(' ', ' ', $new);
310 $new = str_replace('+} {+', ' ', $new);
311 $new = preg_replace('!\{\+(.*)\+\}!U', '<ins>\\1</ins>', $new);
315 $old = htmlspecialchars($old, ENT_QUOTES
, 'UTF-8');
316 $new = htmlspecialchars($new, ENT_QUOTES
, 'UTF-8');
320 $out .= '<td class="line">'.($i+
1).'</td>';
321 $out .= '<td class="leftChange">'.$t1.'</td>';
322 $out .= '<td class="leftText '.$class1.'">'.$old.'</td>';
323 $out .= '<td class="rightChange">'.$t2.'</td>';
324 $out .= '<td class="rightText '.$class2.'">'.$new.'</td>';
334 function tpl_select_compte($params)
336 $name = $params['name'];
337 $comptes = $params['comptes'];
338 $selected = isset($params['data'][$params['name']]) ?
$params['data'][$params['name']] : utils
::post($name);
340 $out = '<select name="'.$name.'" id="f_'.$name.'" class="large">';
342 foreach ($comptes as $compte)
344 // Ne pas montrer les comptes désactivés
345 if (!empty($compte['desactive']))
348 if (!isset($compte['id'][1]))
350 $out.= '<optgroup label="'.htmlspecialchars($compte['libelle'], ENT_QUOTES
, 'UTF-8', false).'" class="niveau_1"></optgroup>';
352 elseif (!isset($compte['id'][2]) && empty($params['create']))
354 if ($compte['id'] > 10)
355 $out.= '</optgroup>';
357 $out.= '<optgroup label="'.htmlspecialchars($compte['id'] . ' - ' . $compte['libelle'], ENT_QUOTES
, 'UTF-8', false).'" class="niveau_2">';
361 $out .= '<option value="'.htmlspecialchars($compte['id'], ENT_QUOTES
, 'UTF-8', false).'" class="niveau_'.strlen($compte['id']).'"';
363 if ($selected == $compte['id'])
365 $out .= ' selected="selected"';
368 $out .= '>' . htmlspecialchars($compte['id'] . ' - ' . $compte['libelle'], ENT_QUOTES
, 'UTF-8', false);
373 $out .= '</optgroup>';
379 function escape_money($number)
381 return number_format((float)$number, 2, ',', ' ');
384 function tpl_html_money($number)
386 return '<b class="money">' . escape_money($number) . '</b>';
389 function tpl_html_champ_membre($params)
391 if (empty($params['config']) ||
empty($params['name']))
392 throw new \
BadFunctionCallException('Paramètres type et name obligatoires.');
394 $config = $params['config'];
395 $type = $config['type'];
397 if ($params['name'] == 'passe' ||
(!empty($params['user_mode']) && !empty($config['private'])))
402 if ($type == 'select')
404 if (empty($config['options']))
405 throw new \
BadFunctionCallException('Paramètre options obligatoire pour champ de type select.');
407 elseif ($type == 'country')
410 $config['options'] = utils
::getCountryList();
411 $params['default'] = Config
::getInstance()->get('pays');
413 elseif ($type == 'date')
415 $params['pattern'] = '\d{4}-\d{2}-\d{2}';
417 elseif ($type == 'multiple')
419 if (empty($config['options']))
420 throw new \
BadFunctionCallException('Paramètre options obligatoire pour champ de type multiple.');
424 $value = tpl_form_field($params);
425 $attributes = 'name="' . htmlspecialchars($params['name'], ENT_QUOTES
, 'UTF-8') . '" ';
426 $attributes .= 'id="f_' . htmlspecialchars($params['name'], ENT_QUOTES
, 'UTF-8') . '" ';
428 if (!empty($params['disabled']))
430 $attributes .= 'disabled="disabled" ';
433 if (!empty($config['mandatory']))
435 $attributes .= 'required="required" ';
438 if (!empty($params['user_mode']) && empty($config['editable']))
440 $out = '<dt>' . htmlspecialchars($config['title'], ENT_QUOTES
, 'UTF-8') . '</dt>';
441 $out .= '<dd>' . htmlspecialchars((trim($value) === '' ?
'Non renseigné' : $value), ENT_QUOTES
, 'UTF-8') . '</dd>';
445 if ($type == 'select')
447 $field .= '<select '.$attributes.'>';
448 foreach ($config['options'] as $k=>$v)
453 $field .= '<option value="' . htmlspecialchars($k, ENT_QUOTES
, 'UTF-8') . '"';
455 if ($value == $k ||
empty($value) && !empty($params['default']))
456 $field .= ' selected="selected"';
458 $field .= '>' . htmlspecialchars($v, ENT_QUOTES
, 'UTF-8') . '</option>';
460 $field .= '</select>';
462 elseif ($type == 'multiple')
464 if (is_array($value))
468 foreach ($value as $k => $v)
470 if (array_key_exists($k, $config['options']) && !empty($v))
472 $binary |
= 0x01 << $k;
479 foreach ($config['options'] as $k=>$v)
481 $b = 0x01 << (int)$k;
482 $field .= '<label><input type="checkbox" name="'
483 . htmlspecialchars($params['name'], ENT_QUOTES
, 'UTF-8') . '[' . (int)$k . ']" value="1" '
484 . (($value & $b) ?
'checked="checked"' : '') . ' ' . $attributes . '/> '
485 . htmlspecialchars($v, ENT_QUOTES
, 'UTF-8') . '</label><br />';
488 elseif ($type == 'textarea')
490 $field .= '<textarea ' . $attributes . 'cols="30" rows="5">' . $value . '</textarea>';
494 if ($type == 'checkbox')
498 $attributes .= 'checked="checked" ';
504 $field .= '<input type="' . $type . '" ' . $attributes . ' value="' . $value . '" />';
510 if ($type == 'checkbox')
512 $out .= $field . ' ';
515 $out .= '<label for="f_' . htmlspecialchars($params['name'], ENT_QUOTES
, 'UTF-8') . '">'
516 . htmlspecialchars($config['title'], ENT_QUOTES
, 'UTF-8') . '</label>';
518 if (!empty($config['mandatory']))
520 $out .= ' <b title="(Champ obligatoire)">obligatoire</b>';
525 if (!empty($config['help']))
528 <dd class="help">' . htmlspecialchars($config['help'], ENT_QUOTES
, 'UTF-8') . '</dd>';
531 if ($type != 'checkbox')
534 <dd>' . $field . '</dd>';
540 $tpl->register_compiler('continue', function() { return 'continue;'; });
542 $tpl->register_function('csrf_field', 'Garradin\tpl_csrf_field');
543 $tpl->register_function('form_field', 'Garradin\tpl_form_field');
544 $tpl->register_function('select_compte', 'Garradin\tpl_select_compte');
546 $tpl->register_function('format_droits', 'Garradin\tpl_format_droits');
548 $tpl->register_function('pagination', 'Garradin\tpl_pagination');
550 $tpl->register_function('diff', 'Garradin\tpl_diff');
551 $tpl->register_function('html_champ_membre', 'Garradin\tpl_html_champ_membre');
553 $tpl->register_function('plugin_url', ['Garradin\utils', 'plugin_url']);
555 $tpl->register_modifier('get_country_name', ['Garradin\utils', 'getCountryName']);
556 $tpl->register_modifier('format_tel', 'Garradin\tpl_format_tel');
557 $tpl->register_modifier('format_wiki', 'Garradin\tpl_format_wiki');
558 $tpl->register_modifier('liens_wiki', 'Garradin\tpl_liens_wiki');
559 $tpl->register_modifier('escape_money', 'Garradin\escape_money');
560 $tpl->register_modifier('html_money', 'Garradin\tpl_html_money');
561 $tpl->register_modifier('abs', 'abs');
563 $tpl->register_modifier('display_champ_membre', function ($v, $config) {
564 if ($config['type'] == 'checkbox') {
565 return $v ?
'Oui' : 'Non';
566 } elseif ($config['type'] == 'email') {
567 return '<a href="mailto:' . $v . '">' . $v . '</a>';
568 } elseif ($config['type'] == 'tel') {
569 return '<a href="tel:' . $v . '">' . $v . '</a>';
570 } elseif ($config['type'] == 'url') {
571 return '<a href="' . $v . '">' . $v . '</a>';
572 } elseif ($config['type'] == 'country') {
573 return utils
::getCountryName($v);
574 } elseif ($config['type'] == 'multiple') {
577 foreach ($config['options'] as $b => $name)
579 if ($v & (0x01 << $b))
583 return implode(', ', $out);
590 $tpl->register_modifier('format_sqlite_date_to_french', ['Garradin\utils', 'sqliteDateToFrench']);
592 $tpl->register_modifier('format_bytes', function ($size) {
593 if ($size > (1024 * 1024))
594 return round($size / 1024 / 1024, 2) . ' Mo';
595 elseif ($size > 1024)
596 return round($size / 1024, 2) . ' Ko';
598 return $size . ' ob_get_contents(oid)';
601 $tpl->register_modifier('strftime_fr', 'Garradin\tpl_strftime_fr');
602 $tpl->register_modifier('date_fr', 'Garradin\tpl_date_fr');