Dotclear

source: inc/public/class.dc.template.php @ 2953:fdcac99dd62d

Revision 2953:fdcac99dd62d, 92.1 KB checked in by franck <carnet.franck.paul@…>, 11 years ago (diff)

Add an ellipsis on short displayed entry content (with new tpl:EntryIfContentCut), closes #2015

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

Sites map