Dotclear

source: inc/public/class.dc.template.php @ 980:308abbb4125b

Revision 980:308abbb4125b, 92.1 KB checked in by noe@…, 13 years ago (diff)

small Typo in code doc

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

Sites map