Dotclear

source: inc/public/class.dc.template.php @ 3366:1627515406c9

Revision 3366:1627515406c9, 91.0 KB checked in by franck <carnet.franck.paul@…>, 9 years ago (diff)

Add new categories attribute to EntryIf? template tag, closes #2199

Ex:

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

Sites map