Dotclear

source: inc/public/class.dc.template.php @ 928:1bb2aef1cb93

Revision 928:1bb2aef1cb93, 91.7 KB checked in by franck <carnet.franck.paul@…>, 13 years ago (diff)

Put dcTemplate::getAge() function to static, fixes #1050

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

Sites map