Dotclear

source: inc/public/class.dc.template.php @ 833:e52d87b4cbd1

Revision 833:e52d87b4cbd1, 90.6 KB checked in by Dsls <dsls@…>, 13 years ago (diff)

Small tuning in scheduled entries management,
Updated TemplatePrepareParams? behavior

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2011 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) { return; }
13
14class dcTemplate extends template
15{
16     private $core;
17     private $current_tag;
18     
19     protected $unknown_value_handler = null;
20     protected $unknown_block_handler = null;
21     
22     function __construct($cache_dir,$self_name,$core)
23     {
24          parent::__construct($cache_dir,$self_name);
25         
26          $this->remove_php = !$core->blog->settings->system->tpl_allow_php;
27          $this->use_cache = $core->blog->settings->system->tpl_use_cache;
28         
29          $this->tag_block = '<tpl:(\w+)(?:(\s+.*?)>|>)((?:[^<]|<(?!/?tpl:\1)|(?R))*)</tpl:\1>';
30          $this->tag_value = '{{tpl:(\w+)(\s(.*?))?}}';
31         
32          $this->core =& $core;
33         
34          # Transitional tags
35          $this->addValue('EntryTrackbackCount',array($this,'EntryPingCount'));
36          $this->addValue('EntryTrackbackData',array($this,'EntryPingData'));
37          $this->addValue('EntryTrackbackLink',array($this,'EntryPingLink'));
38         
39          # l10n
40          $this->addValue('lang',array($this,'l10n'));
41         
42          # Loops test tags
43          $this->addBlock('LoopPosition',array($this,'LoopPosition'));
44         
45          # Archives
46          $this->addBlock('Archives',array($this,'Archives'));
47          $this->addBlock('ArchivesHeader',array($this,'ArchivesHeader'));
48          $this->addBlock('ArchivesFooter',array($this,'ArchivesFooter'));
49          $this->addBlock('ArchivesYearHeader',array($this,'ArchivesYearHeader'));
50          $this->addBlock('ArchivesYearFooter',array($this,'ArchivesYearFooter'));
51          $this->addValue('ArchiveDate',array($this,'ArchiveDate'));
52          $this->addBlock('ArchiveNext',array($this,'ArchiveNext'));
53          $this->addBlock('ArchivePrevious',array($this,'ArchivePrevious'));
54          $this->addValue('ArchiveEntriesCount',array($this,'ArchiveEntriesCount'));
55          $this->addValue('ArchiveURL',array($this,'ArchiveURL'));
56         
57          # Blog
58          $this->addValue('BlogArchiveURL',array($this,'BlogArchiveURL'));
59          $this->addValue('BlogCopyrightNotice',array($this,'BlogCopyrightNotice'));
60          $this->addValue('BlogDescription',array($this,'BlogDescription'));
61          $this->addValue('BlogEditor',array($this,'BlogEditor'));
62          $this->addValue('BlogFeedID',array($this,'BlogFeedID'));
63          $this->addValue('BlogFeedURL',array($this,'BlogFeedURL'));
64          $this->addValue('BlogRSDURL',array($this,'BlogRSDURL'));
65          $this->addValue('BlogName',array($this,'BlogName'));
66          $this->addValue('BlogLanguage',array($this,'BlogLanguage'));
67          $this->addValue('BlogThemeURL',array($this,'BlogThemeURL'));
68          $this->addValue('BlogUpdateDate',array($this,'BlogUpdateDate'));
69          $this->addValue('BlogID',array($this,'BlogID'));
70          $this->addValue('BlogURL',array($this,'BlogURL'));
71          $this->addValue('BlogPublicURL',array($this,'BlogPublicURL'));
72          $this->addValue('BlogQmarkURL',array($this,'BlogQmarkURL'));
73          $this->addValue('BlogMetaRobots',array($this,'BlogMetaRobots'));
74         
75          # Categories
76          $this->addBlock('Categories',array($this,'Categories'));
77          $this->addBlock('CategoriesHeader',array($this,'CategoriesHeader'));
78          $this->addBlock('CategoriesFooter',array($this,'CategoriesFooter'));
79          $this->addBlock('CategoryIf',array($this,'CategoryIf'));
80          $this->addBlock('CategoryFirstChildren',array($this,'CategoryFirstChildren'));
81          $this->addBlock('CategoryParents',array($this,'CategoryParents'));
82          $this->addValue('CategoryFeedURL',array($this,'CategoryFeedURL'));
83          $this->addValue('CategoryURL',array($this,'CategoryURL'));
84          $this->addValue('CategoryShortURL',array($this,'CategoryShortURL'));
85          $this->addValue('CategoryDescription',array($this,'CategoryDescription'));
86          $this->addValue('CategoryTitle',array($this,'CategoryTitle'));
87         
88          # Comments
89          $this->addBlock('Comments',array($this,'Comments'));
90          $this->addValue('CommentAuthor',array($this,'CommentAuthor'));
91          $this->addValue('CommentAuthorDomain',array($this,'CommentAuthorDomain'));
92          $this->addValue('CommentAuthorLink',array($this,'CommentAuthorLink'));
93          $this->addValue('CommentAuthorMailMD5',array($this,'CommentAuthorMailMD5'));
94          $this->addValue('CommentAuthorURL',array($this,'CommentAuthorURL'));
95          $this->addValue('CommentContent',array($this,'CommentContent'));
96          $this->addValue('CommentDate',array($this,'CommentDate'));
97          $this->addValue('CommentTime',array($this,'CommentTime'));
98          $this->addValue('CommentEmail',array($this,'CommentEmail'));
99          $this->addValue('CommentEntryTitle',array($this,'CommentEntryTitle'));
100          $this->addValue('CommentFeedID',array($this,'CommentFeedID'));
101          $this->addValue('CommentID',array($this,'CommentID'));
102          $this->addBlock('CommentIf',array($this,'CommentIf'));
103          $this->addValue('CommentIfFirst',array($this,'CommentIfFirst'));
104          $this->addValue('CommentIfMe',array($this,'CommentIfMe'));
105          $this->addValue('CommentIfOdd',array($this,'CommentIfOdd'));
106          $this->addValue('CommentIP',array($this,'CommentIP'));
107          $this->addValue('CommentOrderNumber',array($this,'CommentOrderNumber'));
108          $this->addBlock('CommentsFooter',array($this,'CommentsFooter'));
109          $this->addBlock('CommentsHeader',array($this,'CommentsHeader'));
110          $this->addValue('CommentPostURL',array($this,'CommentPostURL'));
111          $this->addBlock('IfCommentAuthorEmail',array($this,'IfCommentAuthorEmail'));
112          $this->addValue('CommentHelp',array($this,'CommentHelp'));
113         
114          # Comment preview
115          $this->addBlock('IfCommentPreview',array($this,'IfCommentPreview'));
116          $this->addValue('CommentPreviewName',array($this,'CommentPreviewName'));
117          $this->addValue('CommentPreviewEmail',array($this,'CommentPreviewEmail'));
118          $this->addValue('CommentPreviewSite',array($this,'CommentPreviewSite'));
119          $this->addValue('CommentPreviewContent',array($this,'CommentPreviewContent'));
120          $this->addValue('CommentPreviewCheckRemember',array($this,'CommentPreviewCheckRemember'));
121         
122          # Entries
123          $this->addBlock('DateFooter',array($this,'DateFooter'));
124          $this->addBlock('DateHeader',array($this,'DateHeader'));
125          $this->addBlock('Entries',array($this,'Entries'));
126          $this->addBlock('EntriesFooter',array($this,'EntriesFooter'));
127          $this->addBlock('EntriesHeader',array($this,'EntriesHeader'));
128          $this->addValue('EntryExcerpt',array($this,'EntryExcerpt'));
129          $this->addValue('EntryAuthorCommonName',array($this,'EntryAuthorCommonName'));
130          $this->addValue('EntryAuthorDisplayName',array($this,'EntryAuthorDisplayName'));
131          $this->addValue('EntryAuthorEmail',array($this,'EntryAuthorEmail'));
132          $this->addValue('EntryAuthorID',array($this,'EntryAuthorID'));
133          $this->addValue('EntryAuthorLink',array($this,'EntryAuthorLink'));
134          $this->addValue('EntryAuthorURL',array($this,'EntryAuthorURL'));
135          $this->addValue('EntryBasename',array($this,'EntryBasename'));
136          $this->addValue('EntryCategory',array($this,'EntryCategory'));
137          $this->addBlock('EntryCategoriesBreadcrumb',array($this,'EntryCategoriesBreadcrumb'));
138          $this->addValue('EntryCategoryID',array($this,'EntryCategoryID'));
139          $this->addValue('EntryCategoryURL',array($this,'EntryCategoryURL'));
140          $this->addValue('EntryCategoryShortURL',array($this,'EntryCategoryShortURL'));
141          $this->addValue('EntryCommentCount',array($this,'EntryCommentCount'));
142          $this->addValue('EntryContent',array($this,'EntryContent'));
143          $this->addValue('EntryDate',array($this,'EntryDate'));
144          $this->addValue('EntryFeedID',array($this,'EntryFeedID'));
145          $this->addValue('EntryFirstImage',array($this,'EntryFirstImage'));
146          $this->addValue('EntryID',array($this,'EntryID'));
147          $this->addBlock('EntryIf',array($this,'EntryIf'));
148          $this->addValue('EntryIfFirst',array($this,'EntryIfFirst'));
149          $this->addValue('EntryIfOdd',array($this,'EntryIfOdd'));
150          $this->addValue('EntryIfSelected',array($this,'EntryIfSelected'));
151          $this->addValue('EntryLang',array($this,'EntryLang'));
152          $this->addBlock('EntryNext',array($this,'EntryNext'));
153          $this->addValue('EntryPingCount',array($this,'EntryPingCount'));
154          $this->addValue('EntryPingData',array($this,'EntryPingData'));
155          $this->addValue('EntryPingLink',array($this,'EntryPingLink'));
156          $this->addBlock('EntryPrevious',array($this,'EntryPrevious'));
157          $this->addValue('EntryTitle',array($this,'EntryTitle'));
158          $this->addValue('EntryTime',array($this,'EntryTime'));
159          $this->addValue('EntryURL',array($this,'EntryURL'));
160         
161          # Languages
162          $this->addBlock('Languages',array($this,'Languages'));
163          $this->addBlock('LanguagesHeader',array($this,'LanguagesHeader'));
164          $this->addBlock('LanguagesFooter',array($this,'LanguagesFooter'));
165          $this->addValue('LanguageCode',array($this,'LanguageCode'));
166          $this->addBlock('LanguageIfCurrent',array($this,'LanguageIfCurrent'));
167          $this->addValue('LanguageURL',array($this,'LanguageURL'));
168         
169          # Pagination
170          $this->addBlock('Pagination',array($this,'Pagination'));
171          $this->addValue('PaginationCounter',array($this,'PaginationCounter'));
172          $this->addValue('PaginationCurrent',array($this,'PaginationCurrent'));
173          $this->addBlock('PaginationIf',array($this,'PaginationIf'));
174          $this->addValue('PaginationURL',array($this,'PaginationURL'));
175         
176          # Trackbacks
177          $this->addValue('PingBlogName',array($this,'PingBlogName'));
178          $this->addValue('PingContent',array($this,'PingContent'));
179          $this->addValue('PingDate',array($this,'PingDate'));
180          $this->addValue('PingEntryTitle',array($this,'PingEntryTitle'));
181          $this->addValue('PingFeedID',array($this,'PingFeedID'));
182          $this->addValue('PingID',array($this,'PingID'));
183          $this->addValue('PingIfFirst',array($this,'PingIfFirst'));
184          $this->addValue('PingIfOdd',array($this,'PingIfOdd'));
185          $this->addValue('PingIP',array($this,'PingIP'));
186          $this->addValue('PingNoFollow',array($this,'PingNoFollow'));
187          $this->addValue('PingOrderNumber',array($this,'PingOrderNumber'));
188          $this->addValue('PingPostURL',array($this,'PingPostURL'));
189          $this->addBlock('Pings',array($this,'Pings'));
190          $this->addBlock('PingsFooter',array($this,'PingsFooter'));
191          $this->addBlock('PingsHeader',array($this,'PingsHeader'));
192          $this->addValue('PingTime',array($this,'PingTime'));
193          $this->addValue('PingTitle',array($this,'PingTitle'));
194          $this->addValue('PingAuthorURL',array($this,'PingAuthorURL'));
195         
196          # System
197          $this->addValue('SysBehavior',array($this,'SysBehavior'));
198          $this->addBlock('SysIf',array($this,'SysIf'));
199          $this->addBlock('SysIfCommentPublished',array($this,'SysIfCommentPublished'));
200          $this->addBlock('SysIfCommentPending',array($this,'SysIfCommentPending'));
201          $this->addBlock('SysIfFormError',array($this,'SysIfFormError'));
202          $this->addValue('SysFeedSubtitle',array($this,'SysFeedSubtitle'));
203          $this->addValue('SysFormError',array($this,'SysFormError'));
204          $this->addValue('SysPoweredBy',array($this,'SysPoweredBy'));
205          $this->addValue('SysSearchString',array($this,'SysSearchString'));
206          $this->addValue('SysSelfURI',array($this,'SysSelfURI'));
207     }
208     
209     public function getData($________)
210     {
211          # --BEHAVIOR-- tplBeforeData
212          if ($this->core->hasBehavior('tplBeforeData'))
213          {
214               self::$_r = $this->core->callBehavior('tplBeforeData',$this->core);
215               if (self::$_r) {
216                    return self::$_r;
217               }
218          }
219         
220          parent::getData($________);
221         
222          # --BEHAVIOR-- tplAfterData
223          if ($this->core->hasBehavior('tplAfterData')) {
224               $this->core->callBehavior('tplAfterData',$this->core,self::$_r);
225          }
226         
227          return self::$_r;
228     }
229     
230     protected function compileFile($file)
231     {
232          $fc = file_get_contents($file);
233         
234          $this->compile_stack[] = $file;
235         
236          # Remove every PHP tags
237          if ($this->remove_php)
238          {
239               $fc = preg_replace('/<\?(?=php|=|\s).*?\?>/ms','',$fc);
240          }
241         
242          # Transform what could be considered as PHP short tags
243          $fc = preg_replace('/(<\?(?!php|=|\s))(.*?)(\?>)/ms',
244          '<?php echo "$1"; ?>$2<?php echo "$3"; ?>',$fc);
245         
246          # Remove template comments <!-- #... -->
247          $fc = preg_replace('/(^\s*)?<!-- #(.*?)-->/ms','',$fc);
248         
249          # Lexer part : split file into small pieces
250          # each array entry will be either a tag or plain text
251          $blocks = preg_split(
252               '#(<tpl:\w+[^>]*>)|(</tpl:\w+>)|({{tpl:\w+[^}]*}})#msu',$fc,-1,
253               PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
254         
255          # Next : build semantic tree from tokens.
256          $rootNode = new tplNode();
257          $node = $rootNode;
258          $errors = array();
259          foreach ($blocks as $id => $block) {
260               $isblock = preg_match('#<tpl:(\w+)(?:(\s+.*?)>|>)|</tpl:(\w+)>|{{tpl:(\w+)(\s(.*?))?}}#ms',$block,$match);
261               if ($isblock == 1) {
262                    if (substr($match[0],1,1) == '/') {
263                         // Closing tag, check if it matches current opened node
264                         $tag = $match[3];
265                         if (($node instanceof tplNodeBlock) && $node->getTag() == $tag) {
266                              $node->setClosing();
267                              $node = $node->getParent();
268                         } else {
269                              // Closing tag does not match opening tag
270                              // Search if it closes a parent tag
271                              $search = $node;
272                              while($search->getTag() != 'ROOT' && $search->getTag() != $tag) {
273                                   $search = $search->getParent();
274                              }
275                              if ($search->getTag() == $tag) {
276                                   $errors[] = sprintf(
277                                        __('Did not find closing tag for block <tpl:%s>. Content has been ignored.'),
278                                        html::escapeHTML($node->getTag()));
279                                   $search->setClosing();
280                                   $node = $search->getParent();
281                              } else {
282                                   $errors[]=sprintf(
283                                        __('Unexpected closing tag </tpl:%s> found.'),
284                                        $tag);;
285                              }
286                         }
287                    } elseif (substr($match[0],0,1) == '{') {
288                         // Value tag
289                         $tag = $match[4];
290                         $str_attr = '';
291                         $attr = array();
292                         if (isset($match[6])) {
293                              $str_attr = $match[6];
294                              $attr = $this->getAttrs($match[6]);
295                         }
296                         $node->addChild(new tplNodeValue($tag,$attr,$str_attr));
297                    } else {
298                         // Opening tag, create new node and dive into it
299                         $tag = $match[1];
300                         $newnode = new tplNodeBlock($tag,isset($match[2])?$this->getAttrs($match[2]):array());
301                         $node->addChild($newnode);
302                         $node = $newnode;
303                    }
304               } else {
305                    // Simple text
306                    $node->addChild(new tplNodeText($block));
307               }
308          }
309         
310          if (($node instanceof tplNodeBlock) && !$node->isClosed()) {
311               $errors[] = sprintf(
312                    __('Did not find closing tag for block <tpl:%s>. Content has been ignored.'),
313                    html::escapeHTML($node->getTag()));
314          }
315         
316          $err = "";
317          if (count($errors) > 0) {
318               $err = "\n\n<!-- \n".
319                    __('WARNING: the following errors have been found while parsing template file :').
320                    "\n * ".
321                    join("\n * ",$errors).
322                    "\n -->\n";
323          }
324         
325          return $rootNode->compile($this).$err;
326     }
327   
328     public function compileBlockNode($tag,$attr,$content)
329     {
330          $this->current_tag = $tag;
331          $attr = new ArrayObject($attr);
332          # --BEHAVIOR-- templateBeforeBlock
333          $res = $this->core->callBehavior('templateBeforeBlock',$this->core,$this->current_tag,$attr);
334         
335          # --BEHAVIOR-- templateInsideBlock
336          $this->core->callBehavior('templateInsideBlock',$this->core,$this->current_tag,$attr,array(&$content));
337         
338          if (isset($this->blocks[$this->current_tag])) {
339               $res .= call_user_func($this->blocks[$this->current_tag],$attr,$content);
340          } elseif ($this->unknown_block_handler != null) {
341               $res .= call_user_func($this->unknown_block_handler,$this->current_tag,$attr,$content);
342          }
343         
344          # --BEHAVIOR-- templateAfterBlock
345          $res .= $this->core->callBehavior('templateAfterBlock',$this->core,$this->current_tag,$attr);
346         
347          return $res;
348     }
349     
350     public function compileValueNode($tag,$attr,$str_attr)
351     {
352          $this->current_tag = $tag;
353         
354          $attr = new ArrayObject($attr);
355          # --BEHAVIOR-- templateBeforeValue
356          $res = $this->core->callBehavior('templateBeforeValue',$this->core,$this->current_tag,$attr);
357         
358          if (isset($this->values[$this->current_tag])) {
359               $res .= call_user_func($this->values[$this->current_tag],$attr,ltrim($str_attr));
360          } elseif ($this->unknown_value_handler != null) {
361               $res .= call_user_func($this->unknown_value_handler,$this->current_tag,$attr,$str_attr);
362          }
363       
364          # --BEHAVIOR-- templateAfterValue
365          $res .= $this->core->callBehavior('templateAfterValue',$this->core,$this->current_tag,$attr);
366         
367          return $res;
368     }
369   
370     public function setUnknownValueHandler($callback)
371     {
372          if (is_callable($callback)) {
373               $this->unknown_value_handler = $callback;
374          }
375     }
376   
377     public function setUnknownBlockHandler($callback)
378     {
379          if (is_callable($callback)) {
380               $this->unknown_block_handler = $callback;
381          }
382     }
383   
384     public function getFilters($attr)
385     {
386          $p[0] = '0';   # encode_xml
387          $p[1] = '0';   # remove_html
388          $p[2] = '0';   # cut_string
389          $p[3] = '0';   # lower_case
390          $p[4] = '0';   # upper_case
391         
392          $p[0] = (integer) (!empty($attr['encode_xml']) || !empty($attr['encode_html']));
393          $p[1] = (integer) !empty($attr['remove_html']);
394         
395          if (!empty($attr['cut_string']) && (integer) $attr['cut_string'] > 0) {
396               $p[2] = (integer) $attr['cut_string'];
397          }
398         
399          $p[3] = (integer) !empty($attr['lower_case']);
400          $p[4] = (integer) !empty($attr['upper_case']);
401         
402          return "context::global_filter(%s,".implode(",",$p).",'".addslashes($this->current_tag)."')";
403     }
404     
405     public static function getOperator($op)
406     {
407          switch (strtolower($op))
408          {
409               case 'or':
410               case '||':
411                    return '||';
412               case 'and':
413               case '&&':
414               default:
415                    return '&&';
416          }
417     }
418     
419     public function getSortByStr($attr,$table = null)
420     {
421          $res = array();
422         
423          $default_order = 'desc';
424         
425          $default_alias = array(
426               'post' => array(
427                    'title' => 'post_title',
428                    'selected' => 'post_selected',
429                    'author' => 'user_id',
430                    'date' => 'post_dt',
431                    'id' => 'post_id',
432                    'comment' => 'nb_comment',
433                    'trackback' => 'nb_trackback'
434               ),
435               'comment' => array(
436                    'author' => 'comment_author',
437                    'date' => 'comment_dt',
438                    'id' => 'comment_id'
439               )
440          );
441         
442          $alias = new ArrayObject();
443         
444          # --BEHAVIOR-- templateCustomSortByAlias
445          $this->core->callBehavior('templateCustomSortByAlias',$alias);
446         
447          $alias = $alias->getArrayCopy();
448         
449          if (is_array($alias)) {
450               foreach ($alias as $k => $v) {
451                    if (!is_array($v)) {
452                         $alias[$k] = array();
453                    }
454                    if (!is_array($v)) {
455                         $default_alias[$k] = array();
456                    }
457                    $default_alias[$k] = array_merge($default_alias[$k],$alias[$k]);
458               }
459          }
460         
461          if (!array_key_exists($table,$default_alias)) {
462               return implode(', ',$res);
463          }
464         
465          if (isset($attr['order']) && preg_match('/^(desc|asc)$/i',$attr['order'])) {
466               $default_order = $attr['order'];
467          }
468          if (isset($attr['sortby'])) {
469               $sorts = explode(',',$attr['sortby']);
470               foreach ($sorts as $k => $sort) {
471                    $order = $default_order;
472                    if (preg_match('/([a-z]*)\s*\?(desc|asc)$/i',$sort,$matches)) {
473                         $sort = $matches[1];
474                         $order = $matches[2];
475                    }
476                    if (array_key_exists($sort,$default_alias[$table])) {
477                         array_push($res,$default_alias[$table][$sort].' '.$order);
478                    }
479               }
480          }
481         
482          if (count($res) === 0) {
483               array_push($res,$default_alias[$table]['date'].' '.$default_order);
484          }
485         
486          return implode(', ',$res);
487     }
488     
489     public function getAge($attr)
490     {
491          if (isset($attr['age']) && preg_match('/^(\-[0-9]+|last).*$/i',$attr['age'])) {
492               if (($ts = strtotime($attr['age'])) !== false) {
493                    return dt::str('%Y-%m-%d %H:%m:%S',$ts);
494               }
495          }
496          return '';
497     }
498     
499     /* TEMPLATE FUNCTIONS
500     ------------------------------------------------------- */
501     
502     public function l10n($attr,$str_attr)
503     {
504          # Normalize content
505          $str_attr = preg_replace('/\s+/x',' ',$str_attr);
506         
507          return "<?php echo __('".str_replace("'","\\'",$str_attr)."'); ?>";
508     }
509     
510     public function LoopPosition($attr,$content)
511     {
512          $start = isset($attr['start']) ? (integer) $attr['start'] : '0';
513          $length = isset($attr['length']) ? (integer) $attr['length'] : 'null';
514          $even = isset($attr['even']) ? (integer) (boolean) $attr['even'] : 'null';
515         
516          if ($start > 0) {
517               $start--;
518          }
519         
520          return
521          '<?php if ($_ctx->loopPosition('.$start.','.$length.','.$even.')) : ?>'.
522          $content.
523          "<?php endif; ?>";
524     }
525     
526     
527     /* Archives ------------------------------------------- */
528     /*dtd
529     <!ELEMENT tpl:Archives - - -- Archives dates loop -->
530     <!ATTLIST tpl:Archives
531     type      (day|month|year)    #IMPLIED  -- Get days, months or years, default to month --
532     category  CDATA               #IMPLIED  -- Get dates of given category --
533     no_context (1|0)              #IMPLIED  -- Override context information
534     order     (asc|desc)          #IMPLIED  -- Sort asc or desc --
535     post_type CDATA               #IMPLIED  -- Get dates of given type of entries, default to post --
536     post_lang CDATA          #IMPLIED  -- Filter on the given language
537     >
538     */
539     public function Archives($attr,$content)
540     {
541          $p = "if (!isset(\$params)) \$params = array();\n";
542          $p .= "\$params['type'] = 'month';\n";
543          if (isset($attr['type'])) {
544               $p .= "\$params['type'] = '".addslashes($attr['type'])."';\n";
545          }
546         
547          if (isset($attr['category'])) {
548               $p .= "\$params['cat_url'] = '".addslashes($attr['category'])."';\n";
549          }
550       
551          if (isset($attr['post_type'])) {
552               $p .= "\$params['post_type'] = '".addslashes($attr['post_type'])."';\n";
553          }
554       
555          if (isset($attr['post_lang'])) {
556               $p .= "\$params['post_lang'] = '".addslashes($attr['post_lang'])."';\n";
557          }
558         
559          if (empty($attr['no_context']) && !isset($attr['category']))
560          {
561               $p .=
562               'if ($_ctx->exists("categories")) { '.
563                    "\$params['cat_id'] = \$_ctx->categories->cat_id; ".
564               "}\n";
565          }
566         
567          $order = 'desc';
568          if (isset($attr['order']) && preg_match('/^(desc|asc)$/i',$attr['order'])) {
569               $p .= "\$params['order'] = '".$attr['order']."';\n ";
570          }
571         
572          $res = "<?php\n";
573          $res .= $p;
574          $res .= $this->core->callBehavior("templatePrepareParams", 
575               array("tag" => "Archives","method" => "blog::getDates"), 
576               $attr,$content);
577          $res .= '$_ctx->archives = $core->blog->getDates($params); unset($params);'."\n";
578          $res .= "?>\n";
579         
580          $res .=
581          '<?php while ($_ctx->archives->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->archives = null; ?>';
582         
583          return $res;
584     }
585     
586     /*dtd
587     <!ELEMENT tpl:ArchivesHeader - - -- First archives result container -->
588     */
589     public function ArchivesHeader($attr,$content)
590     {
591          return
592          "<?php if (\$_ctx->archives->isStart()) : ?>".
593          $content.
594          "<?php endif; ?>";
595     }
596     
597     /*dtd
598     <!ELEMENT tpl:ArchivesFooter - - -- Last archives result container -->
599     */
600     public function ArchivesFooter($attr,$content)
601     {
602          return
603          "<?php if (\$_ctx->archives->isEnd()) : ?>".
604          $content.
605          "<?php endif; ?>";
606     }
607     
608     /*dtd
609     <!ELEMENT tpl:ArchivesYearHeader - - -- First result of year in archives container -->
610     */
611     public function ArchivesYearHeader($attr,$content)
612     {
613          return
614          "<?php if (\$_ctx->archives->yearHeader()) : ?>".
615          $content.
616          "<?php endif; ?>";
617     }
618     
619     /*dtd
620     <!ELEMENT tpl:ArchivesYearFooter - - -- Last result of year in archives container -->
621     */
622     public function ArchivesYearFooter($attr,$content)
623     {
624          return
625          "<?php if (\$_ctx->archives->yearFooter()) : ?>".
626          $content.
627          "<?php endif; ?>";
628     }
629     
630     /*dtd
631     <!ELEMENT tpl:ArchiveDate - O -- Archive result date -->
632     <!ATTLIST tpl:ArchiveDate
633     format    CDATA     #IMPLIED  -- Date format (Default %B %Y) --
634     >
635     */
636     public function ArchiveDate($attr)
637     {
638          $format = '%B %Y';
639          if (!empty($attr['format'])) {
640               $format = addslashes($attr['format']);
641          }
642         
643          $f = $this->getFilters($attr);
644          return '<?php echo '.sprintf($f,"dt::dt2str('".$format."',\$_ctx->archives->dt)").'; ?>';
645     }
646     
647     /*dtd
648     <!ELEMENT tpl:ArchiveEntriesCount - O -- Current archive result number of entries -->
649     */
650     public function ArchiveEntriesCount($attr)
651     {
652          $f = $this->getFilters($attr);
653          return '<?php echo '.sprintf($f,'$_ctx->archives->nb_post').'; ?>';
654     }
655     
656     /*dtd
657     <!ELEMENT tpl:ArchiveNext - - -- Next archive result container -->
658     <!ATTLIST tpl:ArchiveNext
659     type      (day|month|year)    #IMPLIED  -- Get days, months or years, default to month --
660     post_type CDATA               #IMPLIED  -- Get dates of given type of entries, default to post --
661     post_lang CDATA          #IMPLIED  -- Filter on the given language
662     >
663     */
664     public function ArchiveNext($attr,$content)
665     {
666          $p = "if (!isset(\$params)) \$params = array();\n";
667          $p .= "\$params['type'] = 'month';\n";
668          if (isset($attr['type'])) {
669               $p .= "\$params['type'] = '".addslashes($attr['type'])."';\n";
670          }
671         
672          if (isset($attr['post_type'])) {
673               $p .= "\$params['post_type'] = '".addslashes($attr['post_type'])."';\n";
674          }
675         
676          if (isset($attr['post_lang'])) {
677               $p .= "\$params['post_lang'] = '".addslashes($attr['post_lang'])."';\n";
678          }
679       
680          $p .= "\$params['next'] = \$_ctx->archives->dt;";
681         
682          $res = "<?php\n";
683          $res .= $p;
684          $res .= $this->core->callBehavior("templatePrepareParams",
685               array("tag" => "ArchiveNext","method" => "blog::getDates"), 
686               $attr, $content);
687          $res .= '$_ctx->archives = $core->blog->getDates($params); unset($params);'."\n";
688          $res .= "?>\n";
689         
690          $res .=
691          '<?php while ($_ctx->archives->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->archives = null; ?>';
692         
693          return $res;
694     }
695     
696     /*dtd
697     <!ELEMENT tpl:ArchivePrevious - - -- Previous archive result container -->
698     <!ATTLIST tpl:ArchivePrevious
699     type      (day|month|year)    #IMPLIED  -- Get days, months or years, default to month --
700     post_type CDATA               #IMPLIED  -- Get dates of given type of entries, default to post --
701     post_lang CDATA          #IMPLIED  -- Filter on the given language
702     >
703     */
704     public function ArchivePrevious($attr,$content)
705     {
706          $p = 'if (!isset($params)) $params = array();';
707          $p .= "\$params['type'] = 'month';\n";
708          if (isset($attr['type'])) {
709               $p .= "\$params['type'] = '".addslashes($attr['type'])."';\n";
710          }
711         
712          if (isset($attr['post_type'])) {
713               $p .= "\$params['post_type'] = '".addslashes($attr['post_type'])."';\n";
714          }
715       
716          if (isset($attr['post_lang'])) {
717               $p .= "\$params['post_lang'] = '".addslashes($attr['post_lang'])."';\n";
718          }
719       
720          $p .= "\$params['previous'] = \$_ctx->archives->dt;";
721         
722          $res = "<?php\n";
723          $res .= $this->core->callBehavior("templatePrepareParams",
724               array("tag" => "ArchivePrevious","method" => "blog::getDates"), 
725               $attr, $content);
726          $res .= $p;
727          $res .= '$_ctx->archives = $core->blog->getDates($params); unset($params);'."\n";
728          $res .= "?>\n";
729         
730          $res .=
731          '<?php while ($_ctx->archives->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->archives = null; ?>';
732         
733          return $res;
734     }
735     
736     /*dtd
737     <!ELEMENT tpl:ArchiveURL - O -- Current archive result URL -->
738     */
739     public function ArchiveURL($attr)
740     {
741          $f = $this->getFilters($attr);
742          return '<?php echo '.sprintf($f,'$_ctx->archives->url($core)').'; ?>';
743     }
744     
745     
746     /* Blog ----------------------------------------------- */
747     /*dtd
748     <!ELEMENT tpl:BlogArchiveURL - O -- Blog Archives URL -->
749     */
750     public function BlogArchiveURL($attr)
751     {
752          $f = $this->getFilters($attr);
753          return '<?php echo '.sprintf($f,'$core->blog->url.$core->url->getURLFor("archive")').'; ?>';
754     }
755     
756     /*dtd
757     <!ELEMENT tpl:BlogCopyrightNotice - O -- Blog copyrght notices -->
758     */
759     public function BlogCopyrightNotice($attr)
760     {
761          $f = $this->getFilters($attr);
762          return '<?php echo '.sprintf($f,'$core->blog->settings->system->copyright_notice').'; ?>';
763     }
764     
765     /*dtd
766     <!ELEMENT tpl:BlogDescription - O -- Blog Description -->
767     */
768     public function BlogDescription($attr)
769     {
770          $f = $this->getFilters($attr);
771          return '<?php echo '.sprintf($f,'$core->blog->desc').'; ?>';
772     }
773     
774     /*dtd
775     <!ELEMENT tpl:BlogEditor - O -- Blog Editor -->
776     */
777     public function BlogEditor($attr)
778     {
779          $f = $this->getFilters($attr);
780          return '<?php echo '.sprintf($f,'$core->blog->settings->system->editor').'; ?>';
781     }
782     
783     /*dtd
784     <!ELEMENT tpl:BlogFeedID - O -- Blog Feed ID -->
785     */
786     public function BlogFeedID($attr)
787     {
788          $f = $this->getFilters($attr);
789          return '<?php echo '.sprintf($f,'"urn:md5:".$core->blog->uid').'; ?>';
790     }
791     
792     /*dtd
793     <!ELEMENT tpl:BlogFeedURL - O -- Blog Feed URL -->
794     <!ATTLIST tpl:BlogFeedURL
795     type (rss2|atom)    #IMPLIED  -- feed type (default : rss2)
796     >
797     */
798     public function BlogFeedURL($attr)
799     {
800          $type = !empty($attr['type']) ? $attr['type'] : 'atom';
801         
802          if (!preg_match('#^(rss2|atom)$#',$type)) {
803               $type = 'atom';
804          }
805         
806          $f = $this->getFilters($attr);
807          return '<?php echo '.sprintf($f,'$core->blog->url.$core->url->getURLFor("feed","'.$type.'")').'; ?>';
808     }
809     
810     /*dtd
811     <!ELEMENT tpl:BlogName - O -- Blog Name -->
812     */
813     public function BlogName($attr)
814     {
815          $f = $this->getFilters($attr);
816          return '<?php echo '.sprintf($f,'$core->blog->name').'; ?>';
817     }
818     
819     /*dtd
820     <!ELEMENT tpl:BlogLanguage - O -- Blog Language -->
821     */
822     public function BlogLanguage($attr)
823     {
824          $f = $this->getFilters($attr);
825          return '<?php echo '.sprintf($f,'$core->blog->settings->system->lang').'; ?>';
826     }
827     
828     /*dtd
829     <!ELEMENT tpl:BlogThemeURL - O -- Blog's current Themei URL -->
830     */
831     public function BlogThemeURL($attr)
832     {
833          $f = $this->getFilters($attr);
834          return '<?php echo '.sprintf($f,'$core->blog->settings->system->themes_url."/".$core->blog->settings->system->theme').'; ?>';
835     }
836   
837     /*dtd
838     <!ELEMENT tpl:BlogPublicURL - O -- Blog Public directory URL -->
839     */
840     public function BlogPublicURL($attr)
841     {
842          $f = $this->getFilters($attr);
843          return '<?php echo '.sprintf($f,'$core->blog->settings->system->public_url').'; ?>';
844     }
845     
846     /*dtd
847     <!ELEMENT tpl:BlogUpdateDate - O -- Blog last update date -->
848     <!ATTLIST tpl:BlogUpdateDate
849     format    CDATA     #IMPLIED  -- date format (encoded in dc:str by default if iso8601 or rfc822 not specified)
850     iso8601   CDATA     #IMPLIED  -- if set, tells that date format is ISO 8601
851     rfc822    CDATA     #IMPLIED  -- if set, tells that date format is RFC 822
852     >
853     */
854     public function BlogUpdateDate($attr)
855     {
856          $format = '';
857          if (!empty($attr['format'])) {
858               $format = addslashes($attr['format']);
859          } else {
860               $format = '%Y-%m-%d %H:%M:%S';
861          }
862         
863          $iso8601 = !empty($attr['iso8601']);
864          $rfc822 = !empty($attr['rfc822']);
865         
866          $f = $this->getFilters($attr);
867         
868          if ($rfc822) {
869               return '<?php echo '.sprintf($f,"dt::rfc822(\$core->blog->upddt,\$core->blog->settings->system->blog_timezone)").'; ?>';
870          } elseif ($iso8601) {
871               return '<?php echo '.sprintf($f,"dt::iso8601(\$core->blog->upddt,\$core->blog->settings->system->blog_timezone)").'; ?>';
872          } else {
873               return '<?php echo '.sprintf($f,"dt::str('".$format."',\$core->blog->upddt)").'; ?>';
874          }
875     }
876     
877     /*dtd
878     <!ELEMENT tpl:BlogID - 0 -- Blog ID -->
879     */
880     public function BlogID($attr)
881     {
882          $f = $this->getFilters($attr);
883          return '<?php echo '.sprintf($f,'$core->blog->id').'; ?>';
884     }
885     
886     /*dtd
887     <!ELEMENT tpl:BlogRSDURL - O -- Blog RSD URL -->
888     */
889     public function BlogRSDURL($attr)
890     {
891          $f = $this->getFilters($attr);
892          return '<?php echo '.sprintf($f,'$core->blog->url.$core->url->getURLFor(\'rsd\')').'; ?>';
893     }
894     
895     /*dtd
896     <!ELEMENT tpl:BlogURL - O -- Blog URL -->
897     */
898     public function BlogURL($attr)
899     {
900          $f = $this->getFilters($attr);
901          return '<?php echo '.sprintf($f,'$core->blog->url').'; ?>';
902     }
903     
904     /*dtd
905     <!ELEMENT tpl:BlogQmarkURL - O -- Blog URL, ending with a question mark -->
906     */
907     public function BlogQmarkURL($attr)
908     {
909          $f = $this->getFilters($attr);
910          return '<?php echo '.sprintf($f,'$core->blog->getQmarkURL()').'; ?>';
911     }
912     
913     /*dtd
914     <!ELEMENT tpl:BlogMetaRobots - O -- Blog meta robots tag definition, overrides robots_policy setting -->
915     <!ATTLIST tpl:BlogMetaRobots
916     robots    CDATA     #IMPLIED  -- can be INDEX,FOLLOW,NOINDEX,NOFOLLOW,ARCHIVE,NOARCHIVE
917     >
918     */
919     public function BlogMetaRobots($attr)
920     {
921          $robots = isset($attr['robots']) ? addslashes($attr['robots']) : '';
922          return "<?php echo context::robotsPolicy(\$core->blog->settings->system->robots_policy,'".$robots."'); ?>";
923     }
924     
925     /* Categories ----------------------------------------- */
926     
927     /*dtd
928     <!ELEMENT tpl:Categories - - -- Categories loop -->
929     */
930     public function Categories($attr,$content)
931     {
932          $p = "if (!isset(\$params)) \$params = array();\n";
933         
934          if (isset($attr['url'])) {
935               $p .= "\$params['cat_url'] = '".addslashes($attr['url'])."';\n";
936          }
937         
938          if (!empty($attr['post_type'])) {
939               $p .= "\$params['post_type'] = '".addslashes($attr['post_type'])."';\n";
940          }
941         
942          if (!empty($attr['level'])) {
943               $p .= "\$params['level'] = ".(integer) $attr['level'].";\n";
944          }
945         
946          $res = "<?php\n";
947          $res .= $p;
948          $res .= $this->core->callBehavior("templatePrepareParams", 
949               array("tag" => "Categories","method" => "blog::getCategories"), 
950               $attr,$content);
951          $res .= '$_ctx->categories = $core->blog->getCategories($params);'."\n";
952          $res .= "?>\n";
953          $res .= '<?php while ($_ctx->categories->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->categories = null; unset($params); ?>';
954         
955          return $res;
956     }
957     
958     /*dtd
959     <!ELEMENT tpl:CategoriesHeader - - -- First Categories result container -->
960     */
961     public function CategoriesHeader($attr,$content)
962     {
963          return
964          "<?php if (\$_ctx->categories->isStart()) : ?>".
965          $content.
966          "<?php endif; ?>";
967     }
968     
969     /*dtd
970     <!ELEMENT tpl:CategoriesFooter - - -- Last Categories result container -->
971     */
972     public function CategoriesFooter($attr,$content)
973     {
974          return
975          "<?php if (\$_ctx->categories->isEnd()) : ?>".
976          $content.
977          "<?php endif; ?>";
978     }
979     
980     /*dtd
981     <!ELEMENT tpl:CategoryIf - - -- tests on current entry -->
982     <!ATTLIST tpl:CategoryIf
983     url       CDATA     #IMPLIED  -- category has given url
984     has_entries    (0|1)     #IMPLIED  -- post is the first post from list (value : 1) or not (value : 0)
985     has_description     (0|1)     #IMPLIED  -- category has description (value : 1) or not (value : 0)
986     >
987     */
988     public function CategoryIf($attr,$content)
989     {
990          $if = new ArrayObject();
991          $operator = isset($attr['operator']) ? $this->getOperator($attr['operator']) : '&&';
992         
993          if (isset($attr['url'])) {
994               $url = addslashes(trim($attr['url']));
995               if (substr($url,0,1) == '!') {
996                    $url = substr($url,1);
997                    $if[] = '($_ctx->categories->cat_url != "'.$url.'")';
998               } else {
999                    $if[] = '($_ctx->categories->cat_url == "'.$url.'")';
1000               }
1001          }
1002         
1003          if (isset($attr['has_entries'])) {
1004               $sign = (boolean) $attr['has_entries'] ? '>' : '==';
1005               $if[] = '$_ctx->categories->nb_post '.$sign.' 0';
1006          }
1007         
1008          if (isset($attr['has_description'])) { 
1009               $sign = (boolean) $attr['has_description'] ? '!=' : '=='; 
1010               $if[] = '$_ctx->categories->cat_desc '.$sign.' ""'; 
1011          } 
1012         
1013          $this->core->callBehavior('tplIfConditions','CategoryIf',$attr,$content,$if);
1014         
1015          if (count($if) != 0) {
1016               return '<?php if('.implode(' '.$operator.' ', (array) $if).') : ?>'.$content.'<?php endif; ?>';
1017          } else {
1018               return $content;
1019          }
1020     }
1021     
1022     /*dtd
1023     <!ELEMENT tpl:CategoryFirstChildren - - -- Current category first children loop -->
1024     */
1025     public function CategoryFirstChildren($attr,$content)
1026     {
1027          return
1028          "<?php\n".
1029          '$_ctx->categories = $core->blog->getCategoryFirstChildren($_ctx->categories->cat_id);'."\n".
1030          'while ($_ctx->categories->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->categories = null; ?>';
1031     }
1032     
1033     /*dtd
1034     <!ELEMENT tpl:CategoryParents - - -- Current category parents loop -->
1035     */
1036     public function CategoryParents($attr,$content)
1037     {
1038          return
1039          "<?php\n".
1040          '$_ctx->categories = $core->blog->getCategoryParents($_ctx->categories->cat_id);'."\n".
1041          'while ($_ctx->categories->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->categories = null; ?>';
1042     }
1043     
1044     /*dtd
1045     <!ELEMENT tpl:CategoryFeedURL - O -- Category feed URL -->
1046     <!ATTLIST tpl:CategoryFeedURL
1047     type (rss2|atom)    #IMPLIED  -- feed type (default : rss2)
1048     >
1049     */
1050     public function CategoryFeedURL($attr)
1051     {
1052          $type = !empty($attr['type']) ? $attr['type'] : 'atom';
1053         
1054          if (!preg_match('#^(rss2|atom)$#',$type)) {
1055               $type = 'atom';
1056          }
1057         
1058          $f = $this->getFilters($attr);
1059          return '<?php echo '.sprintf($f,'$core->blog->url.$core->url->getURLFor("feed","category/".'.
1060          '$_ctx->categories->cat_url."/'.$type.'")').'; ?>';
1061     }
1062     
1063     /*dtd
1064     <!ELEMENT tpl:CategoryURL - O -- Category URL (complete iabsolute URL, including blog URL) -->
1065     */
1066     public function CategoryURL($attr)
1067     {
1068          $f = $this->getFilters($attr);
1069          return '<?php echo '.sprintf($f,'$core->blog->url.$core->url->getURLFor("category",'.
1070               '$_ctx->categories->cat_url)').'; ?>';
1071     }
1072     
1073     /*dtd
1074     <!ELEMENT tpl:CategoryShortURL - O -- Category short URL (relative URL, from /category/) -->
1075     */
1076     public function CategoryShortURL($attr)
1077     {
1078          $f = $this->getFilters($attr);
1079          return '<?php echo '.sprintf($f,'$_ctx->categories->cat_url').'; ?>';
1080     }
1081     
1082     /*dtd
1083     <!ELEMENT tpl:CategoryDescription - O -- Category description -->
1084     */
1085     public function CategoryDescription($attr)
1086     {
1087          $f = $this->getFilters($attr);
1088          return '<?php echo '.sprintf($f,'$_ctx->categories->cat_desc').'; ?>';
1089     }
1090     
1091     /*dtd
1092     <!ELEMENT tpl:CategoryTitle - O -- Category title -->
1093     */
1094     public function CategoryTitle($attr)
1095     {
1096          $f = $this->getFilters($attr);
1097          return '<?php echo '.sprintf($f,'$_ctx->categories->cat_title').'; ?>';
1098     }
1099     
1100     /* Entries -------------------------------------------- */
1101     /*dtd
1102     <!ELEMENT tpl:Entries - - -- Blog Entries loop -->
1103     <!ATTLIST tpl:Entries
1104     lastn     CDATA     #IMPLIED  -- limit number of results to specified value
1105     author    CDATA     #IMPLIED  -- get entries for a given user id
1106     category  CDATA     #IMPLIED  -- get entries for specific categories only (multiple comma-separated categories can be specified. Use "!" as prefix to exclude a category)
1107     no_category    CDATA     #IMPLIED  -- get entries without category
1108     no_context (1|0)    #IMPLIED  -- Override context information
1109     sortby    (title|selected|author|date|id)    #IMPLIED  -- specify entries sort criteria (default : date) (multiple comma-separated sortby can be specified. Use "?asc" or "?desc" as suffix to provide an order for each sorby)
1110     order     (desc|asc)     #IMPLIED  -- specify entries order (default : desc)
1111     no_content     (0|1)     #IMPLIED  -- do not retrieve entries content
1112     selected  (0|1)     #IMPLIED  -- retrieve posts marked as selected only (value: 1) or not selected only (value: 0)
1113     url       CDATA     #IMPLIED  -- retrieve post by its url
1114     type      CDATA     #IMPLIED  -- retrieve post with given post_type (there can be many ones separated by comma)
1115     age       CDATA     #IMPLIED  -- retrieve posts by maximum age (ex: -2 days, last month, last week)
1116     ignore_pagination   (0|1)     #IMPLIED  -- ignore page number provided in URL (useful when using multiple tpl:Entries on the same page)
1117     >
1118     */
1119     public function Entries($attr,$content)
1120     {
1121          $lastn = -1;
1122          if (isset($attr['lastn'])) {
1123               $lastn = abs((integer) $attr['lastn'])+0;
1124          }
1125         
1126          $p = 'if (!isset($_page_number)) { $_page_number = 1; }'."\n";
1127         
1128          if ($lastn != 0) {
1129               if ($lastn > 0) {
1130                    $p .= "\$params['limit'] = ".$lastn.";\n";
1131               } else {
1132                    $p .= "\$params['limit'] = \$_ctx->nb_entry_per_page;\n";
1133               }
1134               
1135               if (!isset($attr['ignore_pagination']) || $attr['ignore_pagination'] == "0") {
1136                    $p .= "\$params['limit'] = array(((\$_page_number-1)*\$params['limit']),\$params['limit']);\n";
1137               } else {
1138                    $p .= "\$params['limit'] = array(0, \$params['limit']);\n";
1139               }
1140          }
1141         
1142          if (isset($attr['author'])) {
1143               $p .= "\$params['user_id'] = '".addslashes($attr['author'])."';\n";
1144          }
1145         
1146          if (isset($attr['category'])) {
1147               $p .= "\$params['cat_url'] = '".addslashes($attr['category'])."';\n";
1148               $p .= "context::categoryPostParam(\$params);\n";
1149          }
1150         
1151          if (isset($attr['no_category']) && $attr['no_category']) {
1152               $p .= "@\$params['sql'] .= ' AND P.cat_id IS NULL ';\n";
1153               $p .= "unset(\$params['cat_url']);\n";
1154          }
1155         
1156          if (!empty($attr['type'])) {
1157               $p .= "\$params['post_type'] = preg_split('/\s*,\s*/','".addslashes($attr['type'])."',-1,PREG_SPLIT_NO_EMPTY);\n";
1158          }
1159         
1160          if (!empty($attr['url'])) {
1161               $p .= "\$params['post_url'] = '".addslashes($attr['url'])."';\n";
1162          }
1163         
1164          if (empty($attr['no_context']))
1165          {
1166               if (!isset($attr['author']))
1167               {
1168                    $p .=
1169                    'if ($_ctx->exists("users")) { '.
1170                         "\$params['user_id'] = \$_ctx->users->user_id; ".
1171                    "}\n";
1172               }
1173               
1174               if (!isset($attr['category']) && (!isset($attr['no_category']) || !$attr['no_category']))
1175               {
1176                    $p .=
1177                    'if ($_ctx->exists("categories")) { '.
1178                         "\$params['cat_id'] = \$_ctx->categories->cat_id; ".
1179                    "}\n";
1180               }
1181               
1182               $p .=
1183               'if ($_ctx->exists("archives")) { '.
1184                    "\$params['post_year'] = \$_ctx->archives->year(); ".
1185                    "\$params['post_month'] = \$_ctx->archives->month(); ";
1186               if (!isset($attr['lastn'])) {
1187                    $p .= "unset(\$params['limit']); ";
1188               }
1189               $p .=
1190               "}\n";
1191               
1192               $p .=
1193               'if ($_ctx->exists("langs")) { '.
1194                    "\$params['post_lang'] = \$_ctx->langs->post_lang; ".
1195               "}\n";
1196               
1197               $p .=
1198               'if (isset($_search)) { '.
1199                    "\$params['search'] = \$_search; ".
1200               "}\n";
1201          }
1202         
1203          $p .= "\$params['order'] = '".$this->getSortByStr($attr,'post')."';\n";
1204         
1205          if (isset($attr['no_content']) && $attr['no_content']) {
1206               $p .= "\$params['no_content'] = true;\n";
1207          }
1208         
1209          if (isset($attr['selected'])) {
1210               $p .= "\$params['post_selected'] = ".(integer) (boolean) $attr['selected'].";";
1211          }
1212         
1213          if (isset($attr['age'])) {
1214               $age = $this->getAge($attr);
1215               $p .= !empty($age) ? "@\$params['sql'] .= ' AND P.post_dt > \'".$age."\'';\n" : '';
1216          }
1217         
1218          $res = "<?php\n";
1219          $res .= $p;
1220          $res .= $this->core->callBehavior("templatePrepareParams", 
1221               array("tag" => "Entries","method" => "blog::getPosts"), 
1222               $attr,$content);
1223          $res .= '$_ctx->post_params = $params;'."\n";
1224          $res .= '$_ctx->posts = $core->blog->getPosts($params); unset($params);'."\n";
1225          $res .= "?>\n";
1226          $res .=
1227          '<?php while ($_ctx->posts->fetch()) : ?>'.$content.'<?php endwhile; '.
1228          '$_ctx->posts = null; $_ctx->post_params = null; ?>';
1229         
1230          return $res;
1231     }
1232     
1233     /*dtd
1234     <!ELEMENT tpl:DateHeader - O -- Displays date, if post is the first post of the given day -->
1235     */
1236     public function DateHeader($attr,$content)
1237     {
1238          return
1239          "<?php if (\$_ctx->posts->firstPostOfDay()) : ?>".
1240          $content.
1241          "<?php endif; ?>";
1242     }
1243     
1244     /*dtd
1245     <!ELEMENT tpl:DateFooter - O -- Displays date,  if post is the last post of the given day -->
1246     */
1247     public function DateFooter($attr,$content)
1248     {
1249          return
1250          "<?php if (\$_ctx->posts->lastPostOfDay()) : ?>".
1251          $content.
1252          "<?php endif; ?>";
1253     }
1254     
1255     /*dtd
1256     <!ELEMENT tpl:EntryIf - - -- tests on current entry -->
1257     <!ATTLIST tpl:EntryIf
1258     type CDATA     #IMPLIED  -- post has a given type (default: "post")
1259     category  CDATA     #IMPLIED  -- post has a given category
1260     first     (0|1)     #IMPLIED  -- post is the first post from list (value : 1) or not (value : 0)
1261     odd  (0|1)     #IMPLIED  -- post is in an odd position (value : 1) or not (value : 0)
1262     even (0|1)     #IMPLIED  -- post is in an even position (value : 1) or not (value : 0)
1263     extended  (0|1)     #IMPLIED  -- post has an excerpt (value : 1) or not (value : 0)
1264     selected  (0|1)     #IMPLIED  -- post is selected (value : 1) or not (value : 0)
1265     has_category   (0|1)     #IMPLIED  -- post has a category (value : 1) or not (value : 0)
1266     has_attachment (0|1)     #IMPLIED  -- post has attachments (value : 1) or not (value : 0) (see Attachment plugin for code)
1267     comments_active     (0|1)     #IMPLIED  -- comments are active for this post (value : 1) or not (value : 0)
1268     pings_active   (0|1)     #IMPLIED  -- trackbacks are active for this post (value : 1) or not (value : 0)
1269     show_comments  (0|1)     #IMPLIED  -- there are comments for this post (value : 1) or not (value : 0)
1270     show_pings     (0|1)     #IMPLIED  -- there are trackbacks for this post (value : 1) or not (value : 0)
1271     operator  (and|or)  #IMPLIED  -- combination of conditions, if more than 1 specifiec (default: and)
1272     url       CDATA     #IMPLIED  -- post has given url
1273     >
1274     */
1275     public function EntryIf($attr,$content)
1276     {
1277          $if = new ArrayObject();
1278          $extended = null;
1279          $hascategory = null;
1280         
1281          $operator = isset($attr['operator']) ? $this->getOperator($attr['operator']) : '&&';
1282       
1283          if (isset($attr['type'])) {
1284               $type = trim($attr['type']);
1285               $type = !empty($type)?$type:'post';
1286               $if[] = '$_ctx->posts->post_type == "'.addslashes($type).'"';
1287          }
1288         
1289          if (isset($attr['url'])) {
1290               $url = trim($attr['url']);
1291               if (substr($url,0,1) == '!') {
1292                    $url = substr($url,1);
1293                    $if[] = '$_ctx->posts->post_url != "'.addslashes($url).'"';
1294               } else {
1295                    $if[] = '$_ctx->posts->post_url == "'.addslashes($url).'"';
1296               }
1297          }
1298         
1299          if (isset($attr['category'])) {
1300               $category = addslashes(trim($attr['category']));
1301               if (substr($category,0,1) == '!') {
1302                    $category = substr($category,1);
1303                    $if[] = '($_ctx->posts->cat_url != "'.$category.'")';
1304               } else {
1305                    $if[] = '($_ctx->posts->cat_url == "'.$category.'")';
1306               }
1307          }
1308         
1309          if (isset($attr['first'])) {
1310               $sign = (boolean) $attr['first'] ? '=' : '!';
1311               $if[] = '$_ctx->posts->index() '.$sign.'= 0';
1312          }
1313         
1314          if (isset($attr['odd'])) {
1315               $sign = (boolean) $attr['odd'] ? '=' : '!';
1316               $if[] = '($_ctx->posts->index()+1)%2 '.$sign.'= 1';
1317          }
1318         
1319          if (isset($attr['extended'])) {
1320               $sign = (boolean) $attr['extended'] ? '' : '!';
1321               $if[] = $sign.'$_ctx->posts->isExtended()';
1322          }
1323         
1324          if (isset($attr['selected'])) {
1325               $sign = (boolean) $attr['selected'] ? '' : '!';
1326               $if[] = $sign.'(boolean)$_ctx->posts->post_selected';
1327          }
1328         
1329          if (isset($attr['has_category'])) {
1330               $sign = (boolean) $attr['has_category'] ? '' : '!';
1331               $if[] = $sign.'$_ctx->posts->cat_id';
1332          }
1333         
1334          if (isset($attr['comments_active'])) {
1335               $sign = (boolean) $attr['comments_active'] ? '' : '!';
1336               $if[] = $sign.'$_ctx->posts->commentsActive()';
1337          }
1338         
1339          if (isset($attr['pings_active'])) {
1340               $sign = (boolean) $attr['pings_active'] ? '' : '!';
1341               $if[] = $sign.'$_ctx->posts->trackbacksActive()';
1342          }
1343         
1344          if (isset($attr['has_comment'])) {
1345               $sign = (boolean) $attr['has_comment'] ? '' : '!';
1346               $if[] = $sign.'$_ctx->posts->hasComments()';
1347          }
1348         
1349          if (isset($attr['has_ping'])) {
1350               $sign = (boolean) $attr['has_ping'] ? '' : '!';
1351               $if[] = $sign.'$_ctx->posts->hasTrackbacks()';
1352          }
1353         
1354          if (isset($attr['show_comments'])) {
1355               if ((boolean) $attr['show_comments']) {
1356                    $if[] = '($_ctx->posts->hasComments() || $_ctx->posts->commentsActive())';
1357               } else {
1358                    $if[] = '(!$_ctx->posts->hasComments() && !$_ctx->posts->commentsActive())';
1359               }
1360          }
1361         
1362          if (isset($attr['show_pings'])) {
1363               if ((boolean) $attr['show_pings']) {
1364                    $if[] = '($_ctx->posts->hasTrackbacks() || $_ctx->posts->trackbacksActive())';
1365               } else {
1366                    $if[] = '(!$_ctx->posts->hasTrackbacks() && !$_ctx->posts->trackbacksActive())';
1367               }
1368          }
1369         
1370          $this->core->callBehavior('tplIfConditions','EntryIf',$attr,$content,$if);
1371         
1372          if (count($if) != 0) {
1373               return '<?php if('.implode(' '.$operator.' ', (array) $if).') : ?>'.$content.'<?php endif; ?>';
1374          } else {
1375               return $content;
1376          }
1377     }
1378     
1379     /*dtd
1380     <!ELEMENT tpl:EntryIfFirst - O -- displays value if entry is the first one -->
1381     <!ATTLIST tpl:EntryIfFirst
1382     return    CDATA     #IMPLIED  -- value to display in case of success (default: first)
1383     >
1384     */
1385     public function EntryIfFirst($attr)
1386     {
1387          $ret = isset($attr['return']) ? $attr['return'] : 'first';
1388          $ret = html::escapeHTML($ret);
1389         
1390          return
1391          '<?php if ($_ctx->posts->index() == 0) { '.
1392          "echo '".addslashes($ret)."'; } ?>";
1393     }
1394     
1395     /*dtd
1396     <!ELEMENT tpl:EntryIfOdd - O -- displays value if entry is in an odd position -->
1397     <!ATTLIST tpl:EntryIfOdd
1398     return    CDATA     #IMPLIED  -- value to display in case of success (default: odd)
1399     >
1400     */
1401     public function EntryIfOdd($attr)
1402     {
1403          $ret = isset($attr['return']) ? $attr['return'] : 'odd';
1404          $ret = html::escapeHTML($ret);
1405         
1406          return
1407          '<?php if (($_ctx->posts->index()+1)%2 == 1) { '.
1408          "echo '".addslashes($ret)."'; } ?>";
1409     }
1410     
1411     /*dtd
1412     <!ELEMENT tpl:EntryIfSelected - O -- displays value if entry is selected -->
1413     <!ATTLIST tpl:EntryIfSelected
1414     return    CDATA     #IMPLIED  -- value to display in case of success (default: selected)
1415     >
1416     */
1417     public function EntryIfSelected($attr)
1418     {
1419          $ret = isset($attr['return']) ? $attr['return'] : 'selected';
1420          $ret = html::escapeHTML($ret);
1421         
1422          return
1423          '<?php if ($_ctx->posts->post_selected) { '.
1424          "echo '".addslashes($ret)."'; } ?>";
1425     }
1426     
1427     /*dtd
1428     <!ELEMENT tpl:EntryContent - O -- Entry content -->
1429     <!ATTLIST tpl:EntryContent
1430     absolute_urls  CDATA     #IMPLIED -- transforms local URLs to absolute one
1431     full           (1|0)     #IMPLIED -- returns full content with excerpt
1432     >
1433     */
1434     public function EntryContent($attr)
1435     {
1436          $urls = '0';
1437          if (!empty($attr['absolute_urls'])) {
1438               $urls = '1';
1439          }
1440         
1441          $f = $this->getFilters($attr);
1442         
1443          if (!empty($attr['full'])) {
1444               return '<?php echo '.sprintf($f,
1445                    '$_ctx->posts->getExcerpt('.$urls.')." ".$_ctx->posts->getContent('.$urls.')').'; ?>';
1446          } else {
1447               return '<?php echo '.sprintf($f,'$_ctx->posts->getContent('.$urls.')').'; ?>';
1448          }
1449     }
1450     
1451     /*dtd
1452     <!ELEMENT tpl:EntryExcerpt - O -- Entry excerpt -->
1453     <!ATTLIST tpl:EntryExcerpt
1454     absolute_urls  CDATA     #IMPLIED -- transforms local URLs to absolute one
1455     >
1456     */
1457     public function EntryExcerpt($attr)
1458     {
1459          $urls = '0';
1460          if (!empty($attr['absolute_urls'])) {
1461               $urls = '1';
1462          }
1463         
1464          $f = $this->getFilters($attr);
1465          return '<?php echo '.sprintf($f,'$_ctx->posts->getExcerpt('.$urls.')').'; ?>';
1466     }
1467     
1468     
1469     /*dtd
1470     <!ELEMENT tpl:EntryAuthorCommonName - O -- Entry author common name -->
1471     */
1472     public function EntryAuthorCommonName($attr)
1473     {
1474          $f = $this->getFilters($attr);
1475          return '<?php echo '.sprintf($f,'$_ctx->posts->getAuthorCN()').'; ?>';
1476     }
1477     
1478     /*dtd
1479     <!ELEMENT tpl:EntryAuthorDisplayName - O -- Entry author display name -->
1480     */
1481     public function EntryAuthorDisplayName($attr)
1482     {
1483          $f = $this->getFilters($attr);
1484          return '<?php echo '.sprintf($f,'$_ctx->posts->user_displayname').'; ?>';
1485     }
1486     
1487     /*dtd
1488     <!ELEMENT tpl:EntryAuthorID - O -- Entry author ID -->
1489     */
1490     public function EntryAuthorID($attr)
1491     {
1492          $f = $this->getFilters($attr);
1493          return '<?php echo '.sprintf($f,'$_ctx->posts->user_id').'; ?>';
1494     }
1495     
1496     /*dtd
1497     <!ELEMENT tpl:EntryAuthorEmail - O -- Entry author email -->
1498     <!ATTLIST tpl:EntryAuthorEmail
1499     spam_protected (0|1)     #IMPLIED  -- protect email from spam (default: 1)
1500     >
1501     */
1502     public function EntryAuthorEmail($attr)
1503     {
1504          $p = 'true';
1505          if (isset($attr['spam_protected']) && !$attr['spam_protected']) {
1506               $p = 'false';
1507          }
1508         
1509          $f = $this->getFilters($attr);
1510          return '<?php echo '.sprintf($f,"\$_ctx->posts->getAuthorEmail(".$p.")").'; ?>';
1511     }
1512     
1513     /*dtd
1514     <!ELEMENT tpl:EntryAuthorLink - O -- Entry author link -->
1515     */
1516     public function EntryAuthorLink($attr)
1517     {
1518          $f = $this->getFilters($attr);
1519          return '<?php echo '.sprintf($f,'$_ctx->posts->getAuthorLink()').'; ?>';
1520     }
1521     
1522     /*dtd
1523     <!ELEMENT tpl:EntryAuthorURL - O -- Entry author URL -->
1524     */
1525     public function EntryAuthorURL($attr)
1526     {
1527          $f = $this->getFilters($attr);
1528          return '<?php echo '.sprintf($f,'$_ctx->posts->user_url').'; ?>';
1529     }
1530     
1531     /*dtd
1532     <!ELEMENT tpl:EntryBasename - O -- Entry short URL (relative to /post) -->
1533     */
1534     public function EntryBasename($attr)
1535     {
1536          $f = $this->getFilters($attr);
1537          return '<?php echo '.sprintf($f,'$_ctx->posts->post_url').'; ?>';
1538     }
1539     
1540     /*dtd
1541     <!ELEMENT tpl:EntryCategory - O -- Entry category (full name) -->
1542     */
1543     public function EntryCategory($attr)
1544     {
1545          $f = $this->getFilters($attr);
1546          return '<?php echo '.sprintf($f,'$_ctx->posts->cat_title').'; ?>';
1547     }
1548     
1549     /*dtd
1550     <!ELEMENT tpl:EntryCategoriesBreadcrumb - - -- Current entry parents loop (without last one) -->
1551     */
1552     public function EntryCategoriesBreadcrumb($attr,$content)
1553     {
1554          return
1555          "<?php\n".
1556          '$_ctx->categories = $core->blog->getCategoryParents($_ctx->posts->cat_id);'."\n".
1557          'while ($_ctx->categories->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->categories = null; ?>';
1558     }
1559     
1560     /*dtd
1561     <!ELEMENT tpl:EntryCategoryID - O -- Entry category ID -->
1562     */
1563     public function EntryCategoryID($attr)
1564     {
1565          $f = $this->getFilters($attr);
1566          return '<?php echo '.sprintf($f,'$_ctx->posts->cat_id').'; ?>';
1567     }
1568     
1569     /*dtd
1570     <!ELEMENT tpl:EntryCategoryURL - O -- Entry category URL -->
1571     */
1572     public function EntryCategoryURL($attr)
1573     {
1574          $f = $this->getFilters($attr);
1575          return '<?php echo '.sprintf($f,'$_ctx->posts->getCategoryURL()').'; ?>';
1576     }
1577     
1578     /*dtd
1579     <!ELEMENT tpl:EntryCategoryShortURL - O -- Entry category short URL (relative URL, from /category/) -->
1580     */
1581     public function EntryCategoryShortURL($attr)
1582     {
1583          $f = $this->getFilters($attr);
1584          return '<?php echo '.sprintf($f,'$_ctx->posts->cat_url').'; ?>';
1585     }
1586     
1587     
1588     /*dtd
1589     <!ELEMENT tpl:EntryFeedID - O -- Entry feed ID -->
1590     */
1591     public function EntryFeedID($attr)
1592     {
1593          $f = $this->getFilters($attr);
1594          return '<?php echo '.sprintf($f,'$_ctx->posts->getFeedID()').'; ?>';
1595     }
1596     
1597     /*dtd
1598     <!ELEMENT tpl:EntryFirstImage - O -- Extracts entry first image if exists -->
1599     <!ATTLIST tpl:EntryAuthorEmail
1600     size           (sq|t|s|m|o)   #IMPLIED  -- Image size to extract
1601     class          CDATA          #IMPLIED  -- Class to add on image tag
1602     with_category  (1|0)          #IMPLIED  -- Search in entry category description if present (default 0)
1603     >
1604     */
1605     public function EntryFirstImage($attr)
1606     {
1607          $size = !empty($attr['size']) ? $attr['size'] : '';
1608          $class = !empty($attr['class']) ? $attr['class'] : '';
1609          $with_category = !empty($attr['with_category']) ? 'true' : 'false';
1610         
1611          return "<?php echo context::EntryFirstImageHelper('".addslashes($size)."',".$with_category.",'".addslashes($class)."'); ?>";
1612     }
1613     
1614     /*dtd
1615     <!ELEMENT tpl:EntryID - O -- Entry ID -->
1616     */
1617     public function EntryID($attr)
1618     {
1619          $f = $this->getFilters($attr);
1620          return '<?php echo '.sprintf($f,'$_ctx->posts->post_id').'; ?>';
1621     }
1622     
1623     /*dtd
1624     <!ELEMENT tpl:EntryLang - O --  Entry language or blog lang if not defined -->
1625     */
1626     public function EntryLang($attr)
1627     {
1628          $f = $this->getFilters($attr);
1629          return
1630          '<?php if ($_ctx->posts->post_lang) { '.
1631               'echo '.sprintf($f,'$_ctx->posts->post_lang').'; '.
1632          '} else {'.
1633               'echo '.sprintf($f,'$core->blog->settings->system->lang').'; '.
1634          '} ?>';
1635     }
1636     
1637     /*dtd
1638     <!ELEMENT tpl:EntryNext - - -- Next entry block -->
1639     <!ATTLIST tpl:EntryNext
1640     restrict_to_category     (0|1)     #IMPLIED  -- find next post in the same category (default: 0)
1641     restrict_to_lang         (0|1)     #IMPLIED  -- find next post in the same language (default: 0)
1642     >
1643     */
1644     public function EntryNext($attr,$content)
1645     {
1646          $restrict_to_category = !empty($attr['restrict_to_category']) ? '1' : '0';
1647          $restrict_to_lang = !empty($attr['restrict_to_lang']) ? '1' : '0';
1648         
1649          return
1650          '<?php $next_post = $core->blog->getNextPost($_ctx->posts,1,'.$restrict_to_category.','.$restrict_to_lang.'); ?>'."\n".
1651          '<?php if ($next_post !== null) : ?>'.
1652               
1653               '<?php $_ctx->posts = $next_post; unset($next_post);'."\n".
1654               'while ($_ctx->posts->fetch()) : ?>'.
1655               $content.
1656               '<?php endwhile; $_ctx->posts = null; ?>'.
1657          "<?php endif; ?>\n";
1658     }
1659     
1660     /*dtd
1661     <!ELEMENT tpl:EntryPrevious - - -- Previous entry block -->
1662     <!ATTLIST tpl:EntryPrevious
1663     restrict_to_category     (0|1)     #IMPLIED  -- find previous post in the same category (default: 0)
1664     restrict_to_lang         (0|1)     #IMPLIED  -- find next post in the same language (default: 0)
1665     >
1666     */
1667     public function EntryPrevious($attr,$content)
1668     {
1669          $restrict_to_category = !empty($attr['restrict_to_category']) ? '1' : '0';
1670          $restrict_to_lang = !empty($attr['restrict_to_lang']) ? '1' : '0';
1671         
1672          return
1673          '<?php $prev_post = $core->blog->getNextPost($_ctx->posts,-1,'.$restrict_to_category.','.$restrict_to_lang.'); ?>'."\n".
1674          '<?php if ($prev_post !== null) : ?>'.
1675               
1676               '<?php $_ctx->posts = $prev_post; unset($prev_post);'."\n".
1677               'while ($_ctx->posts->fetch()) : ?>'.
1678               $content.
1679               '<?php endwhile; $_ctx->posts = null; ?>'.
1680          "<?php endif; ?>\n";
1681     }
1682     
1683     /*dtd
1684     <!ELEMENT tpl:EntryTitle - O -- Entry title -->
1685     */
1686     public function EntryTitle($attr)
1687     {
1688          $f = $this->getFilters($attr);
1689          return '<?php echo '.sprintf($f,'$_ctx->posts->post_title').'; ?>';
1690     }
1691     
1692     /*dtd
1693     <!ELEMENT tpl:EntryURL - O -- Entry URL -->
1694     */
1695     public function EntryURL($attr)
1696     {
1697          $f = $this->getFilters($attr);
1698          return '<?php echo '.sprintf($f,'$_ctx->posts->getURL()').'; ?>';
1699     }
1700     
1701     /*dtd
1702     <!ELEMENT tpl:EntryDate - O -- Entry date -->
1703     <!ATTLIST tpl:EntryDate
1704     format    CDATA     #IMPLIED  -- date format (encoded in dc:str by default if iso8601 or rfc822 not specified)
1705     iso8601   CDATA     #IMPLIED  -- if set, tells that date format is ISO 8601
1706     rfc822    CDATA     #IMPLIED  -- if set, tells that date format is RFC 822
1707     upddt     CDATA     #IMPLIED  -- if set, uses the post update time
1708     creadt    CDATA     #IMPLIED  -- if set, uses the post creation time
1709     >
1710     */
1711     public function EntryDate($attr)
1712     {
1713          $format = '';
1714          if (!empty($attr['format'])) {
1715               $format = addslashes($attr['format']);
1716          }
1717         
1718          $iso8601 = !empty($attr['iso8601']);
1719          $rfc822 = !empty($attr['rfc822']);
1720          $type = (!empty($attr['creadt']) ? 'creadt' : '');
1721          $type = (!empty($attr['upddt']) ? 'upddt' : $type);
1722         
1723          $f = $this->getFilters($attr);
1724         
1725          if ($rfc822) {
1726               return '<?php echo '.sprintf($f,"\$_ctx->posts->getRFC822Date('".$type."')").'; ?>';
1727          } elseif ($iso8601) {
1728               return '<?php echo '.sprintf($f,"\$_ctx->posts->getISO8601Date('".$type."')").'; ?>';
1729          } else {
1730               return '<?php echo '.sprintf($f,"\$_ctx->posts->getDate('".$format."','".$type."')").'; ?>';
1731          }
1732     }
1733     
1734     /*dtd
1735     <!ELEMENT tpl:EntryTime - O -- Entry date -->
1736     <!ATTLIST tpl:EntryTime
1737     format    CDATA     #IMPLIED  -- time format
1738     upddt     CDATA     #IMPLIED  -- if set, uses the post update time
1739     creadt    CDATA     #IMPLIED  -- if set, uses the post creation time
1740     >
1741     */
1742     public function EntryTime($attr)
1743     {
1744          $format = '';
1745          if (!empty($attr['format'])) {
1746               $format = addslashes($attr['format']);
1747          }
1748         
1749          $type = (!empty($attr['creadt']) ? 'creadt' : '');
1750          $type = (!empty($attr['upddt']) ? 'upddt' : $type);
1751       
1752          $f = $this->getFilters($attr);
1753          return '<?php echo '.sprintf($f,"\$_ctx->posts->getTime('".$format."','".$type."')").'; ?>';
1754     }
1755     
1756     /*dtd
1757     <!ELEMENT tpl:EntriesHeader - - -- First entries result container -->
1758     */
1759     public function EntriesHeader($attr,$content)
1760     {
1761          return
1762          "<?php if (\$_ctx->posts->isStart()) : ?>".
1763          $content.
1764          "<?php endif; ?>";
1765     }
1766     
1767     /*dtd
1768     <!ELEMENT tpl:EntriesFooter - - -- Last entries result container -->
1769     */
1770     public function EntriesFooter($attr,$content)
1771     {
1772          return
1773          "<?php if (\$_ctx->posts->isEnd()) : ?>".
1774          $content.
1775          "<?php endif; ?>";
1776     }
1777     
1778     /*dtd
1779     <!ELEMENT tpl:EntryCommentCount - O -- Number of comments for entry -->
1780     <!ATTLIST tpl:EntryCommentCount
1781     none      CDATA     #IMPLIED  -- text to display for "no comment" (default: no comment)
1782     one       CDATA     #IMPLIED  -- text to display for "one comment" (default: one comment)
1783     more      CDATA     #IMPLIED  -- text to display for "more comments" (default: %s comments, %s is replaced by the number of comment)
1784     count_all CDATA     #IMPLIED  -- count comments and trackbacks
1785     >
1786     */
1787     public function EntryCommentCount($attr)
1788     {
1789          $none = 'no comment';
1790          $one = 'one comment';
1791          $more = '%d comments';
1792         
1793          if (isset($attr['none'])) {
1794               $none = addslashes($attr['none']);
1795          }
1796          if (isset($attr['one'])) {
1797               $one = addslashes($attr['one']);
1798          }
1799          if (isset($attr['more'])) {
1800               $more = addslashes($attr['more']);
1801          }
1802         
1803          if (empty($attr['count_all'])) {
1804               $operation = '$_ctx->posts->nb_comment';
1805          } else {
1806               $operation = '($_ctx->posts->nb_comment + $_ctx->posts->nb_trackback)';
1807          }
1808         
1809          return
1810          "<?php if (".$operation." == 0) {\n".
1811          "  printf(__('".$none."'),".$operation.");\n".
1812          "} elseif (".$operation." == 1) {\n".
1813          "  printf(__('".$one."'),".$operation.");\n".
1814          "} else {\n".
1815          "  printf(__('".$more."'),".$operation.");\n".
1816          "} ?>";
1817     }
1818     
1819     /*dtd
1820     <!ELEMENT tpl:EntryPingCount - O -- Number of trackbacks for entry -->
1821     <!ATTLIST tpl:EntryPingCount
1822     none CDATA     #IMPLIED  -- text to display for "no ping" (default: no ping)
1823     one  CDATA     #IMPLIED  -- text to display for "one ping" (default: one ping)
1824     more CDATA     #IMPLIED  -- text to display for "more pings" (default: %s trackbacks, %s is replaced by the number of pings)
1825     >
1826     */
1827     public function EntryPingCount($attr)
1828     {
1829          $none = 'no trackback';
1830          $one = 'one trackback';
1831          $more = '%d trackbacks';
1832         
1833          if (isset($attr['none'])) {
1834               $none = addslashes($attr['none']);
1835          }
1836          if (isset($attr['one'])) {
1837               $one = addslashes($attr['one']);
1838          }
1839          if (isset($attr['more'])) {
1840               $more = addslashes($attr['more']);
1841          }
1842         
1843          return
1844          "<?php if (\$_ctx->posts->nb_trackback == 0) {\n".
1845          "  printf(__('".$none."'),(integer) \$_ctx->posts->nb_trackback);\n".
1846          "} elseif (\$_ctx->posts->nb_trackback == 1) {\n".
1847          "  printf(__('".$one."'),(integer) \$_ctx->posts->nb_trackback);\n".
1848          "} else {\n".
1849          "  printf(__('".$more."'),(integer) \$_ctx->posts->nb_trackback);\n".
1850          "} ?>";
1851     }
1852     
1853     /*dtd
1854     <!ELEMENT tpl:EntryPingData - O -- Display trackback RDF information -->
1855     */
1856     public function EntryPingData($attr)
1857     {
1858          return "<?php if (\$_ctx->posts->trackbacksActive()) { echo \$_ctx->posts->getTrackbackData(); } ?>\n";
1859     }
1860     
1861     /*dtd
1862     <!ELEMENT tpl:EntryPingLink - O -- Entry trackback link -->
1863     */
1864     public function EntryPingLink($attr)
1865     {
1866          return "<?php if (\$_ctx->posts->trackbacksActive()) { echo \$_ctx->posts->getTrackbackLink(); } ?>\n";
1867     }
1868     
1869     /* Languages -------------------------------------- */
1870     /*dtd
1871     <!ELEMENT tpl:Languages - - -- Languages loop -->
1872     <!ATTLIST tpl:Languages
1873     lang CDATA     #IMPLIED  -- restrict loop on given lang
1874     order     (desc|asc)     #IMPLIED  -- languages ordering (default: desc)
1875     >
1876     */
1877     public function Languages($attr,$content)
1878     {
1879          $p = "if (!isset(\$params)) \$params = array();\n";
1880         
1881          if (isset($attr['lang'])) {
1882               $p = "\$params['lang'] = '".addslashes($attr['lang'])."';\n";
1883          }
1884         
1885          $order = 'desc';
1886          if (isset($attr['order']) && preg_match('/^(desc|asc)$/i',$attr['order'])) {
1887               $p .= "\$params['order'] = '".$attr['order']."';\n ";
1888          }
1889         
1890          $res = "<?php\n";
1891          $res .= $p;
1892          $res .= $this->core->callBehavior("templatePrepareParams", 
1893               array("tag" => "Languages","method" => "blog::getLangs"), 
1894               $attr,$content);
1895          $res .= '$_ctx->langs = $core->blog->getLangs($params); unset($params);'."\n";
1896          $res .= "?>\n";
1897         
1898          $res .=
1899          '<?php if ($_ctx->langs->count() > 1) : '.
1900          'while ($_ctx->langs->fetch()) : ?>'.$content.
1901          '<?php endwhile; $_ctx->langs = null; endif; ?>';
1902         
1903          return $res;
1904     }
1905     
1906     /*dtd
1907     <!ELEMENT tpl:LanguagesHeader - - -- First languages result container -->
1908     */
1909     public function LanguagesHeader($attr,$content)
1910     {
1911          return
1912          "<?php if (\$_ctx->langs->isStart()) : ?>".
1913          $content.
1914          "<?php endif; ?>";
1915     }
1916     
1917     /*dtd
1918     <!ELEMENT tpl:LanguagesFooter - - -- Last languages result container -->
1919     */
1920     public function LanguagesFooter($attr,$content)
1921     {
1922          return
1923          "<?php if (\$_ctx->langs->isEnd()) : ?>".
1924          $content.
1925          "<?php endif; ?>";
1926     }
1927     
1928     /*dtd
1929     <!ELEMENT tpl:LanguageCode - O -- Language code -->
1930     */
1931     public function LanguageCode($attr)
1932     {
1933          $f = $this->getFilters($attr);
1934          return '<?php echo '.sprintf($f,'$_ctx->langs->post_lang').'; ?>';
1935     }
1936     
1937     /*dtd
1938     <!ELEMENT tpl:LanguageIfCurrent - - -- tests if post language is current language -->
1939     */
1940     public function LanguageIfCurrent($attr,$content)
1941     {
1942          return
1943          "<?php if (\$_ctx->cur_lang == \$_ctx->langs->post_lang) : ?>".
1944          $content.
1945          "<?php endif; ?>";
1946     }
1947     
1948     /*dtd
1949     <!ELEMENT tpl:LanguageURL - O -- Language URL -->
1950     */
1951     public function LanguageURL($attr)
1952     {
1953          $f = $this->getFilters($attr);
1954          return '<?php echo '.sprintf($f,'$core->blog->url.$core->url->getURLFor("lang",'.
1955               '$_ctx->langs->post_lang)').'; ?>';
1956     }
1957     
1958     /* Pagination ------------------------------------- */
1959     /*dtd
1960     <!ELEMENT tpl:Pagination - - -- Pagination container -->
1961     <!ATTLIST tpl:Pagination
1962     no_context     (0|1)     #IMPLIED  -- override test on posts count vs number of posts per page
1963     >
1964     */
1965     public function Pagination($attr,$content)
1966     {
1967          $p = "<?php\n";
1968          $p .= '$params = $_ctx->post_params;'."\n";
1969          $p .= $this->core->callBehavior("templatePrepareParams", 
1970               array("tag" => "Pagination","method" => "blog::getPosts"), 
1971               $attr,$content);
1972          $p .= '$_ctx->pagination = $core->blog->getPosts($params,true); unset($params);'."\n";
1973          $p .= "?>\n";
1974         
1975          if (isset($attr['no_context']) && $attr['no_context']) {
1976               return $p.$content;
1977          }
1978       
1979          return
1980               $p.
1981               '<?php if ($_ctx->pagination->f(0) > $_ctx->posts->count()) : ?>'.
1982               $content.
1983               '<?php endif; ?>';
1984     }
1985     
1986     /*dtd
1987     <!ELEMENT tpl:PaginationCounter - O -- Number of pages -->
1988     */
1989     public function PaginationCounter($attr)
1990     {
1991          $f = $this->getFilters($attr);
1992          return '<?php echo '.sprintf($f,"context::PaginationNbPages()").'; ?>';
1993     }
1994     
1995     /*dtd
1996     <!ELEMENT tpl:PaginationCurrent - O -- current page -->
1997     */
1998     public function PaginationCurrent($attr)
1999     {
2000          $offset = 0;
2001          if (isset($attr['offset'])) {
2002               $offset = (integer) $attr['offset'];
2003          }
2004         
2005          $f = $this->getFilters($attr);
2006          return '<?php echo '.sprintf($f,"context::PaginationPosition(".$offset.")").'; ?>';
2007     }
2008     
2009     /*dtd
2010     <!ELEMENT tpl:PaginationIf - - -- pages tests -->
2011     <!ATTLIST tpl:PaginationIf
2012     start     (0|1)     #IMPLIED  -- test if we are at first page (value : 1) or not (value : 0)
2013     end  (0|1)     #IMPLIED  -- test if we are at last page (value : 1) or not (value : 0)
2014     >
2015     */
2016     public function PaginationIf($attr,$content)
2017     {
2018          $if = array();
2019         
2020          if (isset($attr['start'])) {
2021               $sign = (boolean) $attr['start'] ? '' : '!';
2022               $if[] = $sign.'context::PaginationStart()';
2023          }
2024         
2025          if (isset($attr['end'])) {
2026               $sign = (boolean) $attr['end'] ? '' : '!';
2027               $if[] = $sign.'context::PaginationEnd()';
2028          }
2029         
2030          $this->core->callBehavior('tplIfConditions','PaginationIf',$attr,$content,$if);
2031         
2032          if (count($if) != 0) {
2033               return '<?php if('.implode(' && ', (array) $if).') : ?>'.$content.'<?php endif; ?>';
2034          } else {
2035               return $content;
2036          }
2037     }
2038     
2039     /*dtd
2040     <!ELEMENT tpl:PaginationURL - O -- link to previoux/next page -->
2041     <!ATTLIST tpl:PaginationURL
2042     offset    CDATA     #IMPLIED  -- page offset (negative for previous pages), default: 0
2043     >
2044     */
2045     public function PaginationURL($attr)
2046     {
2047          $offset = 0;
2048          if (isset($attr['offset'])) {
2049               $offset = (integer) $attr['offset'];
2050          }
2051         
2052          $f = $this->getFilters($attr);
2053          return '<?php echo '.sprintf($f,"context::PaginationURL(".$offset.")").'; ?>';
2054     }
2055     
2056     /* Comments --------------------------------------- */
2057     /*dtd
2058     <!ELEMENT tpl:Comments - - -- Comments container -->
2059     <!ATTLIST tpl:Comments
2060     with_pings     (0|1)     #IMPLIED  -- include trackbacks in request
2061     lastn     CDATA     #IMPLIED  -- restrict the number of entries
2062     no_context (1|0)         #IMPLIED  -- Override context information
2063     sortby    (title|selected|author|date|id)    #IMPLIED  -- specify comments sort criteria (default : date) (multiple comma-separated sortby can be specified. Use "?asc" or "?desc" as suffix to provide an order for each sorby)
2064     order     (desc|asc)     #IMPLIED  -- result ordering (default: asc)
2065     age       CDATA     #IMPLIED  -- retrieve comments by maximum age (ex: -2 days, last month, last week)
2066     >
2067     */
2068     public function Comments($attr,$content)
2069     {
2070          $p = "";
2071          if (empty($attr['with_pings'])) {
2072               $p .= "\$params['comment_trackback'] = false;\n";
2073          }
2074         
2075          $lastn = 0;
2076          if (isset($attr['lastn'])) {
2077               $lastn = abs((integer) $attr['lastn'])+0;
2078          }
2079         
2080          if ($lastn > 0) {
2081               $p .= "\$params['limit'] = ".$lastn.";\n";
2082          } else {
2083               $p .= "if (\$_ctx->nb_comment_per_page !== null) { \$params['limit'] = \$_ctx->nb_comment_per_page; }\n";
2084          }
2085         
2086          if (empty($attr['no_context']))
2087          {
2088               $p .=
2089               "if (\$_ctx->posts !== null) { ".
2090                    "\$params['post_id'] = \$_ctx->posts->post_id; ".
2091                    "\$core->blog->withoutPassword(false);\n".
2092               "}\n";
2093               $p .=
2094               'if ($_ctx->exists("categories")) { '.
2095                    "\$params['cat_id'] = \$_ctx->categories->cat_id; ".
2096               "}\n";
2097               
2098               $p .=
2099               'if ($_ctx->exists("langs")) { '.
2100                    "\$params['sql'] = \"AND P.post_lang = '\".\$core->blog->con->escape(\$_ctx->langs->post_lang).\"' \"; ".
2101               "}\n";
2102          }
2103         
2104          if (!isset($attr['order'])) {
2105               $attr['order'] = 'asc';
2106          }
2107         
2108          $p .= "\$params['order'] = '".$this->getSortByStr($attr,'comment')."';\n";
2109         
2110          if (isset($attr['no_content']) && $attr['no_content']) {
2111               $p .= "\$params['no_content'] = true;\n";
2112          }
2113         
2114          if (isset($attr['age'])) {
2115               $age = $this->getAge($attr);
2116               $p .= !empty($age) ? "@\$params['sql'] .= ' AND P.post_dt > \'".$age."\'';\n" : '';
2117          }
2118         
2119          $res = "<?php\n";
2120          $res .= $this->core->callBehavior("templatePrepareParams", 
2121               array("tag" => "Comments","method" => "blog::getComments"), 
2122               $attr,$content);
2123          $res .= $p;
2124          $res .= '$_ctx->comments = $core->blog->getComments($params); unset($params);'."\n";
2125          $res .= "if (\$_ctx->posts !== null) { \$core->blog->withoutPassword(true);}\n";
2126         
2127          if (!empty($attr['with_pings'])) {
2128               $res .= '$_ctx->pings = $_ctx->comments;'."\n";
2129          }
2130         
2131          $res .= "?>\n";
2132         
2133          $res .=
2134          '<?php while ($_ctx->comments->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->comments = null; ?>';
2135         
2136          return $res;
2137     }
2138     
2139     /*dtd
2140     <!ELEMENT tpl:CommentAuthor - O -- Comment author -->
2141     */
2142     public function CommentAuthor($attr)
2143     {
2144          $f = $this->getFilters($attr);
2145          return '<?php echo '.sprintf($f,"\$_ctx->comments->comment_author").'; ?>';
2146     }
2147     
2148     /*dtd
2149     <!ELEMENT tpl:CommentAuthorDomain - O -- Comment author website domain -->
2150     */
2151     public function CommentAuthorDomain($attr)
2152     {
2153          return '<?php echo preg_replace("#^http(?:s?)://(.+?)/.*$#msu",\'$1\',$_ctx->comments->comment_site); ?>';
2154     }
2155     
2156     /*dtd
2157     <!ELEMENT tpl:CommentAuthorLink - O -- Comment author link -->
2158     */
2159     public function CommentAuthorLink($attr)
2160     {
2161          $f = $this->getFilters($attr);
2162          return '<?php echo '.sprintf($f,'$_ctx->comments->getAuthorLink()').'; ?>';
2163     }
2164     
2165     /*dtd
2166     <!ELEMENT tpl:CommentAuthorMailMD5 - O -- Comment author email MD5 sum -->
2167     */
2168     public function CommentAuthorMailMD5($attr)
2169     {
2170          return '<?php echo md5($_ctx->comments->comment_email) ; ?>';
2171     }
2172     
2173     /*dtd
2174     <!ELEMENT tpl:CommentAuthorURL - O -- Comment author URL -->
2175     */
2176     public function CommentAuthorURL($attr)
2177     {
2178          $f = $this->getFilters($attr);
2179          return '<?php echo '.sprintf($f,'$_ctx->comments->getAuthorURL()').'; ?>';
2180     }
2181     
2182     /*dtd
2183     <!ELEMENT tpl:CommentContent - O --  Comment content -->
2184     <!ATTLIST tpl:CommentContent
2185     absolute_urls  (0|1)     #IMPLIED  -- convert URLS to absolute urls
2186     >
2187     */
2188     public function CommentContent($attr)
2189     {
2190          $urls = '0';
2191          if (!empty($attr['absolute_urls'])) {
2192               $urls = '1';
2193          }
2194         
2195          $f = $this->getFilters($attr);
2196          return '<?php echo '.sprintf($f,'$_ctx->comments->getContent('.$urls.')').'; ?>';
2197     }
2198     
2199     /*dtd
2200     <!ELEMENT tpl:CommentDate - O -- Comment date -->
2201     <!ATTLIST tpl:CommentDate
2202     format    CDATA     #IMPLIED  -- date format (encoded in dc:str by default if iso8601 or rfc822 not specified)
2203     iso8601   CDATA     #IMPLIED  -- if set, tells that date format is ISO 8601
2204     rfc822    CDATA     #IMPLIED  -- if set, tells that date format is RFC 822
2205     upddt     CDATA     #IMPLIED  -- if set, uses the comment update time
2206     >
2207     */
2208     public function CommentDate($attr)
2209     {
2210          $format = '';
2211          if (!empty($attr['format'])) {
2212               $format = addslashes($attr['format']);
2213          }
2214         
2215          $iso8601 = !empty($attr['iso8601']);
2216          $rfc822 = !empty($attr['rfc822']);
2217          $type = (!empty($attr['upddt']) ? 'upddt' : '');
2218         
2219          $f = $this->getFilters($attr);
2220         
2221          if ($rfc822) {
2222               return '<?php echo '.sprintf($f,"\$_ctx->comments->getRFC822Date('".$type."')").'; ?>';
2223          } elseif ($iso8601) {
2224               return '<?php echo '.sprintf($f,"\$_ctx->comments->getISO8601Date('".$type."')").'; ?>';
2225          } else {
2226               return '<?php echo '.sprintf($f,"\$_ctx->comments->getDate('".$format."','".$type."')").'; ?>';
2227          }
2228     }
2229     
2230     /*dtd
2231     <!ELEMENT tpl:CommentTime - O -- Comment date -->
2232     <!ATTLIST tpl:CommentTime
2233     format    CDATA     #IMPLIED  -- time format
2234     upddt     CDATA     #IMPLIED  -- if set, uses the comment update time
2235     >
2236     */
2237     public function CommentTime($attr)
2238     {
2239          $format = '';
2240          if (!empty($attr['format'])) {
2241               $format = addslashes($attr['format']);
2242          }
2243          $type = (!empty($attr['upddt']) ? 'upddt' : '');
2244       
2245          $f = $this->getFilters($attr);
2246          return '<?php echo '.sprintf($f,"\$_ctx->comments->getTime('".$format."','".$type."')").'; ?>';
2247     }
2248     
2249     /*dtd
2250     <!ELEMENT tpl:CommentEmail - O -- Comment author email -->
2251     <!ATTLIST tpl:CommentEmail
2252     spam_protected (0|1)     #IMPLIED  -- protect email from spam (default: 1)
2253     >
2254     */
2255     public function CommentEmail($attr)
2256     {
2257          $p = 'true';
2258          if (isset($attr['spam_protected']) && !$attr['spam_protected']) {
2259               $p = 'false';
2260          }
2261         
2262          $f = $this->getFilters($attr);
2263          return '<?php echo '.sprintf($f,"\$_ctx->comments->getEmail(".$p.")").'; ?>';
2264     }
2265     
2266     /*dtd
2267     <!ELEMENT tpl:CommentEntryTitle - O -- Title of the comment entry -->
2268     */
2269     public function CommentEntryTitle($attr)
2270     {
2271          $f = $this->getFilters($attr);
2272          return '<?php echo '.sprintf($f,'$_ctx->comments->post_title').'; ?>';
2273     }
2274     
2275     /*dtd
2276     <!ELEMENT tpl:CommentFeedID - O -- Comment feed ID -->
2277     */
2278     public function CommentFeedID($attr)
2279     {
2280          $f = $this->getFilters($attr);
2281          return '<?php echo '.sprintf($f,'$_ctx->comments->getFeedID()').'; ?>';
2282     }
2283     
2284     /*dtd
2285     <!ELEMENT tpl:CommentID - O -- Comment ID -->
2286     */
2287     public function CommentID($attr)
2288     {
2289          return '<?php echo $_ctx->comments->comment_id; ?>';
2290     }
2291   
2292     /*dtd
2293     <!ELEMENT tpl:CommentIf - - -- test container for comments -->
2294     <!ATTLIST tpl:CommentIf
2295     is_ping   (0|1)     #IMPLIED  -- test if comment is a trackback (value : 1) or not (value : 0)
2296     >
2297     */
2298     public function CommentIf($attr,$content)
2299     {
2300          $if = array();
2301          $is_ping = null;
2302         
2303          if (isset($attr['is_ping'])) {
2304               $sign = (boolean) $attr['is_ping'] ? '' : '!';
2305               $if[] = $sign.'$_ctx->comments->comment_trackback';
2306          }
2307         
2308          $this->core->callBehavior('tplIfConditions','CommentIf',$attr,$content,$if);
2309         
2310          if (count($if) != 0) {
2311               return '<?php if('.implode(' && ', (array) $if).') : ?>'.$content.'<?php endif; ?>';
2312          } else {
2313               return $content;
2314          }
2315     }
2316     
2317     /*dtd
2318     <!ELEMENT tpl:CommentIfFirst - O -- displays value if comment is the first one -->
2319     <!ATTLIST tpl:CommentIfFirst
2320     return    CDATA     #IMPLIED  -- value to display in case of success (default: first)
2321     >
2322     */
2323     public function CommentIfFirst($attr)
2324     {
2325          $ret = isset($attr['return']) ? $attr['return'] : 'first';
2326          $ret = html::escapeHTML($ret);
2327         
2328          return
2329          '<?php if ($_ctx->comments->index() == 0) { '.
2330          "echo '".addslashes($ret)."'; } ?>";
2331     }
2332     
2333     /*dtd
2334     <!ELEMENT tpl:CommentIfMe - O -- displays value if comment is the from the entry author -->
2335     <!ATTLIST tpl:CommentIfMe
2336     return    CDATA     #IMPLIED  -- value to display in case of success (default: me)
2337     >
2338     */
2339     public function CommentIfMe($attr)
2340     {
2341          $ret = isset($attr['return']) ? $attr['return'] : 'me';
2342          $ret = html::escapeHTML($ret);
2343         
2344          return
2345          '<?php if ($_ctx->comments->isMe()) { '.
2346          "echo '".addslashes($ret)."'; } ?>";
2347     }
2348     
2349     /*dtd
2350     <!ELEMENT tpl:CommentIfOdd - O -- displays value if comment is  at an odd position -->
2351     <!ATTLIST tpl:CommentIfOdd
2352     return    CDATA     #IMPLIED  -- value to display in case of success (default: odd)
2353     >
2354     */
2355     public function CommentIfOdd($attr)
2356     {
2357          $ret = isset($attr['return']) ? $attr['return'] : 'odd';
2358          $ret = html::escapeHTML($ret);
2359         
2360          return
2361          '<?php if (($_ctx->comments->index()+1)%2) { '.
2362          "echo '".addslashes($ret)."'; } ?>";
2363     }
2364     
2365     /*dtd
2366     <!ELEMENT tpl:CommentIP - O -- Comment author IP -->
2367     */
2368     public function CommentIP($attr)
2369     {
2370          return '<?php echo $_ctx->comments->comment_ip; ?>';
2371     }
2372     
2373     /*dtd
2374     <!ELEMENT tpl:CommentOrderNumber - O -- Comment order in page -->
2375     */
2376     public function CommentOrderNumber($attr)
2377     {
2378          return '<?php echo $_ctx->comments->index()+1; ?>';
2379     }
2380     
2381     /*dtd
2382     <!ELEMENT tpl:CommentsFooter - - -- Last comments result container -->
2383     */
2384     public function CommentsFooter($attr,$content)
2385     {
2386          return
2387          "<?php if (\$_ctx->comments->isEnd()) : ?>".
2388          $content.
2389          "<?php endif; ?>";
2390     }
2391     
2392     /*dtd
2393     <!ELEMENT tpl:CommentsHeader - - -- First comments result container -->
2394     */
2395     public function CommentsHeader($attr,$content)
2396     {
2397          return
2398          "<?php if (\$_ctx->comments->isStart()) : ?>".
2399          $content.
2400          "<?php endif; ?>";
2401     }
2402     
2403     /*dtd
2404     <!ELEMENT tpl:CommentPostURL - O -- Comment Entry URL -->
2405     */
2406     public function CommentPostURL($attr)
2407     {
2408          $f = $this->getFilters($attr);
2409          return '<?php echo '.sprintf($f,'$_ctx->comments->getPostURL()').'; ?>';
2410     }
2411     
2412     /*dtd
2413     <!ELEMENT tpl:IfCommentAuthorEmail - - -- Container displayed if comment author email is set -->
2414     */
2415     public function IfCommentAuthorEmail($attr,$content)
2416     {
2417          return
2418          "<?php if (\$_ctx->comments->comment_email) : ?>".
2419          $content.
2420          "<?php endif; ?>";
2421     }
2422     
2423     /*dtd
2424     <!ELEMENT tpl:CommentHelp - 0 -- Comment syntax mini help -->
2425     */
2426     public function CommentHelp($attr,$content)
2427     {
2428          return
2429          "<?php if (\$core->blog->settings->system->wiki_comments) {\n".
2430          "  echo __('Comments can be formatted using a simple wiki syntax.');\n".
2431          "} else {\n".
2432          "  echo __('HTML code is displayed as text and web addresses are automatically converted.');\n".
2433          "} ?>";
2434     }
2435     
2436     /* Comment preview -------------------------------- */
2437     /*dtd
2438     <!ELEMENT tpl:IfCommentPreview - - -- Container displayed if comment is being previewed -->
2439     */
2440     public function IfCommentPreview($attr,$content)
2441     {
2442          return
2443          '<?php if ($_ctx->comment_preview !== null && $_ctx->comment_preview["preview"]) : ?>'.
2444          $content.
2445          '<?php endif; ?>';
2446     }
2447     
2448     /*dtd
2449     <!ELEMENT tpl:CommentPreviewName - O -- Author name for the previewed comment -->
2450     */
2451     public function CommentPreviewName($attr)
2452     {
2453          $f = $this->getFilters($attr);
2454          return '<?php echo '.sprintf($f,'$_ctx->comment_preview["name"]').'; ?>';
2455     }
2456     
2457     /*dtd
2458     <!ELEMENT tpl:CommentPreviewEmail - O -- Author email for the previewed comment -->
2459     */
2460     public function CommentPreviewEmail($attr)
2461     {
2462          $f = $this->getFilters($attr);
2463          return '<?php echo '.sprintf($f,'$_ctx->comment_preview["mail"]').'; ?>';
2464     }
2465     
2466     /*dtd
2467     <!ELEMENT tpl:CommentPreviewSite - O -- Author site for the previewed comment -->
2468     */
2469     public function CommentPreviewSite($attr)
2470     {
2471          $f = $this->getFilters($attr);
2472          return '<?php echo '.sprintf($f,'$_ctx->comment_preview["site"]').'; ?>';
2473     }
2474     
2475     /*dtd
2476     <!ELEMENT tpl:CommentPreviewContent - O -- Content of the previewed comment -->
2477     <!ATTLIST tpl:CommentPreviewContent
2478     raw  (0|1)     #IMPLIED  -- display comment in raw content
2479     >
2480     */
2481     public function CommentPreviewContent($attr)
2482     {
2483          $f = $this->getFilters($attr);
2484         
2485          if (!empty($attr['raw'])) {
2486               $co = '$_ctx->comment_preview["rawcontent"]';
2487          } else {
2488               $co = '$_ctx->comment_preview["content"]';
2489          }
2490         
2491          return '<?php echo '.sprintf($f,$co).'; ?>';
2492     }
2493     
2494     /*dtd
2495     <!ELEMENT tpl:CommentPreviewCheckRemember - O -- checkbox attribute for "remember me" (same value as before preview) -->
2496     */
2497     public function CommentPreviewCheckRemember($attr)
2498     {
2499          return
2500          "<?php if (\$_ctx->comment_preview['remember']) { echo ' checked=\"checked\"'; } ?>";
2501     }
2502     
2503     /* Trackbacks ------------------------------------- */
2504     /*dtd
2505     <!ELEMENT tpl:PingBlogName - O -- Trackback blog name -->
2506     */
2507     public function PingBlogName($attr)
2508     {
2509          $f = $this->getFilters($attr);
2510          return '<?php echo '.sprintf($f,'$_ctx->pings->comment_author').'; ?>';
2511     }
2512     
2513     /*dtd
2514     <!ELEMENT tpl:PingContent - O -- Trackback content -->
2515     */
2516     public function PingContent($attr)
2517     {
2518          $f = $this->getFilters($attr);
2519          return '<?php echo '.sprintf($f,'$_ctx->pings->getTrackbackContent()').'; ?>';
2520     }
2521     
2522     /*dtd
2523     <!ELEMENT tpl:PingDate - O -- Trackback date -->
2524     <!ATTLIST tpl:PingDate
2525     format    CDATA     #IMPLIED  -- date format (encoded in dc:str by default if iso8601 or rfc822 not specified)
2526     iso8601   CDATA     #IMPLIED  -- if set, tells that date format is ISO 8601
2527     rfc822    CDATA     #IMPLIED  -- if set, tells that date format is RFC 822
2528     upddt     CDATA     #IMPLIED  -- if set, uses the comment update time
2529     >
2530     */
2531     public function PingDate($attr,$type='')
2532     {
2533          $format = '';
2534          if (!empty($attr['format'])) {
2535               $format = addslashes($attr['format']);
2536          }
2537         
2538          $iso8601 = !empty($attr['iso8601']);
2539          $rfc822 = !empty($attr['rfc822']);
2540          $type = (!empty($attr['upddt']) ? 'upddt' : '');
2541         
2542          $f = $this->getFilters($attr);
2543         
2544          if ($rfc822) {
2545               return '<?php echo '.sprintf($f,"\$_ctx->pings->getRFC822Date('".$type."')").'; ?>';
2546          } elseif ($iso8601) {
2547               return '<?php echo '.sprintf($f,"\$_ctx->pings->getISO8601Date('".$type."')").'; ?>';
2548          } else {
2549               return '<?php echo '.sprintf($f,"\$_ctx->pings->getDate('".$format."','".$type."')").'; ?>';
2550          }
2551     }
2552     
2553     /*dtd
2554     <!ELEMENT tpl:PingTime - O -- Trackback date -->
2555     <!ATTLIST tpl:PingTime
2556     format    CDATA     #IMPLIED  -- time format
2557     upddt     CDATA     #IMPLIED  -- if set, uses the comment update time
2558     >
2559     */
2560     public function PingTime($attr)
2561     {
2562          $format = '';
2563          if (!empty($attr['format'])) {
2564               $format = addslashes($attr['format']);
2565          }
2566          $type = (!empty($attr['upddt']) ? 'upddt' : '');
2567         
2568          $f = $this->getFilters($attr);
2569          return '<?php echo '.sprintf($f,"\$_ctx->pings->getTime('".$format."','".$type."')").'; ?>';
2570     }
2571     
2572     /*dtd
2573     <!ELEMENT tpl:PingEntryTitle - O -- Trackback entry title -->
2574     */
2575     public function PingEntryTitle($attr)
2576     {
2577          $f = $this->getFilters($attr);
2578          return '<?php echo '.sprintf($f,'$_ctx->pings->post_title').'; ?>';
2579     }
2580     
2581     /*dtd
2582     <!ELEMENT tpl:PingFeedID - O -- Trackback feed ID -->
2583     */
2584     public function PingFeedID($attr)
2585     {
2586          $f = $this->getFilters($attr);
2587          return '<?php echo '.sprintf($f,'$_ctx->pings->getFeedID()').'; ?>';
2588     }
2589     
2590     /*dtd
2591     <!ELEMENT tpl:PingID - O -- Trackback ID -->
2592     */
2593     public function PingID($attr)
2594     {
2595          return '<?php echo $_ctx->pings->comment_id; ?>';
2596     }
2597     
2598     /*dtd
2599     <!ELEMENT tpl:PingIfFirst - O -- displays value if trackback is the first one -->
2600     <!ATTLIST tpl:PingIfFirst
2601     return    CDATA     #IMPLIED  -- value to display in case of success (default: first)
2602     >
2603     */
2604     public function PingIfFirst($attr)
2605     {
2606          $ret = isset($attr['return']) ? $attr['return'] : 'first';
2607          $ret = html::escapeHTML($ret);
2608         
2609          return
2610          '<?php if ($_ctx->pings->index() == 0) { '.
2611          "echo '".addslashes($ret)."'; } ?>";
2612     }
2613     
2614     /*dtd
2615     <!ELEMENT tpl:PingIfOdd - O -- displays value if trackback is  at an odd position -->
2616     <!ATTLIST tpl:PingIfOdd
2617     return    CDATA     #IMPLIED  -- value to display in case of success (default: odd)
2618     >
2619     */
2620     public function PingIfOdd($attr)
2621     {
2622          $ret = isset($attr['return']) ? $attr['return'] : 'odd';
2623          $ret = html::escapeHTML($ret);
2624         
2625          return
2626          '<?php if (($_ctx->pings->index()+1)%2) { '.
2627          "echo '".addslashes($ret)."'; } ?>";
2628     }
2629     
2630     /*dtd
2631     <!ELEMENT tpl:PingIP - O -- Trackback author IP -->
2632     */
2633     public function PingIP($attr)
2634     {
2635          return '<?php echo $_ctx->pings->comment_ip; ?>';
2636     }
2637     
2638     /*dtd
2639     <!ELEMENT tpl:PingNoFollow - O -- displays 'rel="nofollow"' if set in blog -->
2640     */
2641     public function PingNoFollow($attr)
2642     {
2643          return
2644          '<?php if($core->blog->settings->system->comments_nofollow) { '.
2645          'echo \' rel="nofollow"\';'.
2646          '} ?>';
2647     }
2648     
2649     /*dtd
2650     <!ELEMENT tpl:PingOrderNumber - O -- Trackback order in page -->
2651     */
2652     public function PingOrderNumber($attr)
2653     {
2654          return '<?php echo $_ctx->pings->index()+1; ?>';
2655     }
2656     
2657     /*dtd
2658     <!ELEMENT tpl:PingPostURL - O -- Trackback Entry URL -->
2659     */
2660     public function PingPostURL($attr)
2661     {
2662          $f = $this->getFilters($attr);
2663          return '<?php echo '.sprintf($f,'$_ctx->pings->getPostURL()').'; ?>';
2664     }
2665     
2666     /*dtd
2667     <!ELEMENT tpl:Pings - - -- Trackbacks container -->
2668     <!ATTLIST tpl:Pings
2669     with_pings     (0|1)     #IMPLIED  -- include trackbacks in request
2670     lastn     CDATA          #IMPLIED  -- restrict the number of entries
2671     no_context (1|0)         #IMPLIED  -- Override context information
2672     order     (desc|asc)     #IMPLIED  -- result ordering (default: asc)
2673     >
2674     */
2675     public function Pings($attr,$content)
2676     {
2677          $p =
2678          "if (\$_ctx->posts !== null) { ".
2679               "\$params['post_id'] = \$_ctx->posts->post_id; ".
2680               "\$core->blog->withoutPassword(false);\n".
2681          "}\n";
2682         
2683          $p .= "\$params['comment_trackback'] = true;\n";
2684         
2685          $lastn = 0;
2686          if (isset($attr['lastn'])) {
2687               $lastn = abs((integer) $attr['lastn'])+0;
2688          }
2689         
2690          if ($lastn > 0) {
2691               $p .= "\$params['limit'] = ".$lastn.";\n";
2692          } else {
2693               $p .= "if (\$_ctx->nb_comment_per_page !== null) { \$params['limit'] = \$_ctx->nb_comment_per_page; }\n";
2694          }
2695         
2696          if (empty($attr['no_context']))
2697          {
2698               $p .=
2699               'if ($_ctx->exists("categories")) { '.
2700                    "\$params['cat_id'] = \$_ctx->categories->cat_id; ".
2701               "}\n";
2702               
2703               $p .=
2704               'if ($_ctx->exists("langs")) { '.
2705                    "\$params['sql'] = \"AND P.post_lang = '\".\$core->blog->con->escape(\$_ctx->langs->post_lang).\"' \"; ".
2706               "}\n";
2707          }
2708         
2709          $order = 'asc';
2710          if (isset($attr['order']) && preg_match('/^(desc|asc)$/i',$attr['order'])) {
2711               $order = $attr['order'];
2712          }
2713         
2714          $p .= "\$params['order'] = 'comment_dt ".$order."';\n";
2715         
2716          if (isset($attr['no_content']) && $attr['no_content']) {
2717               $p .= "\$params['no_content'] = true;\n";
2718          }
2719         
2720          $res = "<?php\n";
2721          $res .= $p;
2722          $res .= $this->core->callBehavior("templatePrepareParams", 
2723               array("tag" => "Pings","method" => "blog::getComments"), 
2724               $attr,$content);
2725          $res .= '$_ctx->pings = $core->blog->getComments($params); unset($params);'."\n";
2726          $res .= "if (\$_ctx->posts !== null) { \$core->blog->withoutPassword(true);}\n";
2727          $res .= "?>\n";
2728         
2729          $res .=
2730          '<?php while ($_ctx->pings->fetch()) : ?>'.$content.'<?php endwhile; $_ctx->pings = null; ?>';
2731         
2732          return $res;
2733     }
2734     
2735     /*dtd
2736     <!ELEMENT tpl:PingsFooter - - -- Last trackbacks result container -->
2737     */
2738     public function PingsFooter($attr,$content)
2739     {
2740          return
2741          "<?php if (\$_ctx->pings->isEnd()) : ?>".
2742          $content.
2743          "<?php endif; ?>";
2744     }
2745     
2746     /*dtd
2747     <!ELEMENT tpl:PingsHeader - - -- First trackbacks result container -->
2748     */
2749     public function PingsHeader($attr,$content)
2750     {
2751          return
2752          "<?php if (\$_ctx->pings->isStart()) : ?>".
2753          $content.
2754          "<?php endif; ?>";
2755     }
2756     
2757     /*dtd
2758     <!ELEMENT tpl:PingTitle - O -- Trackback title -->
2759     */
2760     public function PingTitle($attr)
2761     {
2762          $f = $this->getFilters($attr);
2763          return '<?php echo '.sprintf($f,'$_ctx->pings->getTrackbackTitle()').'; ?>';
2764     }
2765     
2766     /*dtd
2767     <!ELEMENT tpl:PingAuthorURL - O -- Trackback author URL -->
2768     */
2769     public function PingAuthorURL($attr)
2770     {
2771          $f = $this->getFilters($attr);
2772          return '<?php echo '.sprintf($f,'$_ctx->pings->getAuthorURL()').'; ?>';
2773     }
2774     
2775     # System
2776     /*dtd
2777     <!ELEMENT tpl:SysBehavior - O -- Call a given behavior -->
2778     <!ATTLIST tpl:SysBehavior
2779     behavior  CDATA     #IMPLIED  -- behavior to call
2780     >
2781     */
2782     public function SysBehavior($attr,$raw)
2783     {
2784          if (!isset($attr['behavior'])) {
2785               return;
2786          }
2787         
2788          $b = addslashes($attr['behavior']);
2789          return
2790          '<?php if ($core->hasBehavior(\''.$b.'\')) { '.
2791               '$core->callBehavior(\''.$b.'\',$core,$_ctx);'.
2792          '} ?>';
2793     }
2794     
2795     /*dtd
2796     <!ELEMENT tpl:SysIf - - -- System settings tester container -->
2797     <!ATTLIST tpl:SysIf
2798     categories          (0|1)     #IMPLIED  -- test if categories are set in current context (value : 1) or not (value : 0)
2799     posts               (0|1)     #IMPLIED  -- test if posts are set in current context (value : 1) or not (value : 0)
2800     blog_lang           CDATA     #IMPLIED  -- tests if blog language is the one given in parameter
2801     current_tpl         CDATA     #IMPLIED  -- tests if current template is the one given in paramater
2802     current_mode        CDATA     #IMPLIED  -- tests if current URL mode is the one given in parameter
2803     has_tpl             CDATA     #IMPLIED  -- tests if a named template exists
2804     has_tag             CDATA     #IMPLIED  -- tests if a named template tag exists (see Tag plugin for code)
2805     blog_id             CDATA     #IMPLIED  -- tests if current blog ID is the one given in parameter
2806     comments_active     (0|1)     #IMPLIED  -- test if comments are enabled blog-wide
2807     pings_active        (0|1)     #IMPLIED  -- test if trackbacks are enabled blog-wide
2808     wiki_comments       (0|1)     #IMPLIED  -- test if wiki syntax is enabled for comments
2809     operator            (and|or)  #IMPLIED  -- combination of conditions, if more than 1 specifiec (default: and)
2810     >
2811     */
2812     public function SysIf($attr,$content)
2813     {
2814          $if = new ArrayObject();
2815          $is_ping = null;
2816         
2817          $operator = isset($attr['operator']) ? $this->getOperator($attr['operator']) : '&&';
2818         
2819          if (isset($attr['categories'])) {
2820               $sign = (boolean) $attr['categories'] ? '!' : '=';
2821               $if[] = '$_ctx->categories '.$sign.'== null';
2822          }
2823         
2824          if (isset($attr['posts'])) {
2825               $sign = (boolean) $attr['posts'] ? '!' : '=';
2826               $if[] = '$_ctx->posts '.$sign.'== null';
2827          }
2828         
2829          if (isset($attr['blog_lang'])) {
2830               $if[] = "\$core->blog->settings->system->lang == '".addslashes($attr['blog_lang'])."'";
2831          }
2832         
2833          if (isset($attr['current_tpl'])) {
2834               $sign = '=';
2835               if (substr($attr['current_tpl'],0,1) == '!') {
2836                    $sign = '!';
2837                    $attr['current_tpl'] = substr($attr['current_tpl'],1);
2838               }
2839               $if[] = "\$_ctx->current_tpl ".$sign."= '".addslashes($attr['current_tpl'])."'";
2840          }
2841         
2842          if (isset($attr['current_mode'])) {
2843               $sign = '=';
2844               if (substr($attr['current_mode'],0,1) == '!') {
2845                    $sign = '!';
2846                    $attr['current_mode'] = substr($attr['current_mode'],1);
2847               }
2848               $if[] = "\$core->url->type ".$sign."= '".addslashes($attr['current_mode'])."'";
2849          }
2850         
2851          if (isset($attr['has_tpl'])) {
2852               $sign = '';
2853               if (substr($attr['has_tpl'],0,1) == '!') {
2854                    $sign = '!';
2855                    $attr['has_tpl'] = substr($attr['has_tpl'],1);
2856               }
2857               $if[] = $sign."\$core->tpl->getFilePath('".addslashes($attr['has_tpl'])."') !== false";
2858          }
2859         
2860          if (isset($attr['blog_id'])) {
2861               $sign = '';
2862               if (substr($attr['blog_id'],0,1) == '!') {
2863                    $sign = '!';
2864                    $attr['blog_id'] = substr($attr['blog_id'],1);
2865               }
2866               $if[] = $sign."(\$core->blog->id == '".addslashes($attr['blog_id'])."')";
2867          }
2868         
2869          if (isset($attr['comments_active'])) {
2870               $sign = (boolean) $attr['comments_active'] ? '' : '!';
2871               $if[] = $sign.'$core->blog->settings->system->allow_comments';
2872          }
2873         
2874          if (isset($attr['pings_active'])) {
2875               $sign = (boolean) $attr['pings_active'] ? '' : '!';
2876               $if[] = $sign.'$core->blog->settings->system->allow_trackbacks';
2877          }
2878       
2879          if (isset($attr['wiki_comments'])) {
2880               $sign = (boolean) $attr['wiki_comments'] ? '' : '!';
2881               $if[] = $sign.'$core->blog->settings->system->wiki_comments';
2882          }
2883         
2884          if (isset($attr['search_count']) &&
2885               preg_match('/^((=|!|&gt;|&lt;)=|(&gt;|&lt;))\s*[0-9]+$/',trim($attr['search_count']))) {
2886               $if[] = '(isset($_search_count) && $_search_count '.html::decodeEntities($attr['search_count']).')';
2887          }
2888         
2889          $this->core->callBehavior('tplIfConditions','SysIf',$attr,$content,$if);
2890         
2891          if (count($if) != 0) {
2892               return '<?php if('.implode(' '.$operator.' ', (array) $if).') : ?>'.$content.'<?php endif; ?>';
2893          } else {
2894               return $content;
2895          }
2896     }
2897     
2898     /*dtd
2899     <!ELEMENT tpl:SysIfCommentPublished - - -- Container displayed if comment has been published -->
2900     */
2901     public function SysIfCommentPublished($attr,$content)
2902     {
2903          return
2904          '<?php if (!empty($_GET[\'pub\'])) : ?>'.
2905          $content.
2906          '<?php endif; ?>';
2907     }
2908     
2909     /*dtd
2910     <!ELEMENT tpl:SysIfCommentPending - - -- Container displayed if comment is pending after submission -->
2911     */
2912     public function SysIfCommentPending($attr,$content)
2913     {
2914          return
2915          '<?php if (isset($_GET[\'pub\']) && $_GET[\'pub\'] == 0) : ?>'.
2916          $content.
2917          '<?php endif; ?>';
2918     }
2919     
2920     /*dtd
2921     <!ELEMENT tpl:SysFeedSubtitle - O -- Feed subtitle -->
2922     */
2923     public function SysFeedSubtitle($attr)
2924     {
2925          $f = $this->getFilters($attr);
2926          return '<?php if ($_ctx->feed_subtitle !== null) { echo '.sprintf($f,'$_ctx->feed_subtitle').';} ?>';
2927     }
2928     
2929     /*dtd
2930     <!ELEMENT tpl:SysIfFormError - O -- Container displayed if an error has been detected after form submission -->
2931     */
2932     public function SysIfFormError($attr,$content)
2933     {
2934          return
2935          '<?php if ($_ctx->form_error !== null) : ?>'.
2936          $content.
2937          '<?php endif; ?>';
2938     }
2939     
2940     /*dtd
2941     <!ELEMENT tpl:SysIfFormError - O -- Form error -->
2942     */
2943     public function SysFormError($attr)
2944     {
2945          return
2946          '<?php if ($_ctx->form_error !== null) { echo $_ctx->form_error; } ?>';
2947     }
2948     
2949     public function SysPoweredBy($attr)
2950     {
2951          return
2952          '<?php printf(__("Powered by %s"),"<a href=\"http://dotclear.org/\">Dotclear</a>"); ?>';
2953     }
2954     
2955     public function SysSearchString($attr)
2956     {
2957          $s = isset($attr['string']) ? $attr['string'] : '%1$s';
2958         
2959          $f = $this->getFilters($attr);
2960          return '<?php if (isset($_search)) { echo sprintf(__(\''.$s.'\'),'.sprintf($f,'$_search').',$_search_count);} ?>';
2961     }
2962     
2963     public function SysSelfURI($attr)
2964     {
2965          $f = $this->getFilters($attr);
2966          return '<?php echo '.sprintf($f,'http::getSelfURI()').'; ?>';
2967     }
2968}
2969
2970# Template nodes, for parsing purposes
2971
2972# Generic list node, this one may only be instanciated
2973# once for root element
2974class tplNode 
2975{
2976     # Basic tree structure : links to parent, children forrest
2977     protected $parentNode;
2978     protected $children;
2979     
2980     public function __construct() {
2981          $this->children = array();
2982          $this->parentNode = null;
2983     }
2984     
2985     // Returns compiled block
2986     public function compile($tpl) {
2987          $res='';
2988          foreach ($this->children as $child) {
2989               $res .= $child->compile($tpl);
2990          }
2991          return $res;
2992     }
2993     
2994     # Add a children to current node
2995     public function addChild ($child) {
2996          $this->children[] = $child;
2997          $child->setParent($this);
2998     }
2999     
3000     # Defines parent for current node
3001     protected function setParent($parent) {
3002          $this->parentNode = $parent;
3003     }
3004     
3005     # Retrieves current node parent.
3006     # If parent is root node, null is returned
3007     public function getParent() {
3008          return $this->parentNode;
3009     }
3010     
3011     # Current node tag
3012     public function getTag() {
3013          return "ROOT";
3014     }
3015}
3016
3017// Text node, for any non-tpl content
3018class tplNodeText extends tplNode 
3019{
3020     // Simple text node, only holds its content
3021     protected $content;
3022     
3023     public function __construct($text) {
3024          parent::__construct();
3025          $this->content=$text;
3026     }
3027     
3028     public function compile($tpl) {
3029          return $this->content;
3030     }
3031     
3032     public function getTag() {
3033          return "TEXT";
3034     }
3035}
3036
3037// Block node, for all <tpl:Tag>...</tpl:Tag>
3038class tplNodeBlock extends tplNode 
3039{
3040     protected $attr;
3041     protected $tag;
3042     protected $closed;
3043   
3044     public function __construct($tag,$attr) {
3045          parent::__construct();
3046          $this->content='';
3047          $this->tag = $tag;
3048          $this->attr = $attr;
3049          $this->closed=false;
3050     }
3051     public function setClosing() {
3052          $this->closed = true;
3053     }
3054     public function isClosed() {
3055          return $this->closed;
3056     }
3057     public function compile($tpl) {
3058          if ($this->closed) {
3059               $content = parent::compile($tpl);
3060               return $tpl->compileBlockNode($this->tag,$this->attr,$content);
3061          } else {
3062               // if tag has not been closed, silently ignore its content...
3063               return '';
3064          }
3065     }
3066     public function getTag() {
3067          return $this->tag;
3068     }
3069}
3070
3071// Value node, for all {{tpl:Tag}}
3072class tplNodeValue extends tplNode 
3073{
3074     protected $attr;
3075     protected $str_attr;
3076     protected $tag;
3077     
3078     public function __construct($tag,$attr,$str_attr) {
3079          parent::__construct();
3080          $this->content='';
3081          $this->tag = $tag;
3082          $this->attr = $attr;
3083          $this->str_attr = $str_attr;
3084     }
3085     
3086     public function compile($tpl) {
3087          return $tpl->compileValueNode($this->tag,$this->attr,$this->str_attr);
3088     }
3089     
3090     public function getTag() {
3091          return $this->tag;
3092     }
3093}
3094
3095?>
Note: See TracBrowser for help on using the repository browser.

Sites map