Dotclear

source: inc/public/class.dc.template.php @ 0:54703be25dd6

Revision 0:54703be25dd6, 95.2 KB checked in by Dsls <dsls@…>, 14 years ago (diff)

2.3 branch (trunk) first checkin

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

Sites map