Dotclear

source: inc/public/class.dc.template.php @ 779:58c45f1b96e5

Revision 779:58c45f1b96e5, 90.1 KB checked in by Dsls <dsls@…>, 14 years ago (diff)

Small fixes since [777], notices should not appear now...

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

Sites map