1<?php
2/**
3 * Syntax Component Blog
4 */
5
6// must be run within Dokuwiki
7if (!defined('DOKU_INC')) die();
8
9/**
10 * Covers all <blog *> syntax commands
11 */
12class syntax_plugin_blogtng_blog extends DokuWiki_Syntax_Plugin {
13
14    /**
15     * Default configuration for all setups
16     */
17    var $config = array(
18        'sortorder' => 'DESC',
19        'sortby'    => 'created',
20        'tpl'       => 'default',
21        'limit'     => 5,
22        'offset'    => 0,
23        'blog'      => null,
24        'tags'      => array(),
25        'page'      => false,
26        'cache'     => false,
27        'title'     => '',
28        'format'    => ':blog:%Y:%m:%{title}',
29        'listwrap'  => 0, //default depends on syntax type
30    );
31
32    /** @var helper_plugin_blogtng_entry */
33    var $entryhelper  = null;
34    /** @var helper_plugin_blogtng_tools */
35    var $tools = null;
36    /** @var helper_plugin_blogtng_comments */
37    var $commenthelper  = null;
38    /** @var helper_plugin_blogtng_tags */
39    var $taghelper;
40
41    /**
42     * Types we accept in our syntax
43     */
44    var $type_whitelist = array('list', 'pagination', 'related', 'recentcomments', 'newform', 'tagcloud', 'tagsearch');
45
46    /**
47     * Values accepted in syntax
48     */
49    var $data_whitelist = array(
50        'sortyorder' => array('asc', 'desc'),
51        'sortby' => array('created', 'lastmod', 'title', 'page', 'random'),
52    );
53
54    // default plugin functions...
55    /**
56     * Syntax Type
57     *
58     * @return string
59     */
60    function getType() { return 'substition'; }
61
62    /**
63     * Paragraph Type
64     *
65     * @return string
66     */
67    function getPType() { return 'block'; }
68
69    /**
70     * Sort for applying this mode
71     *
72     * @return int
73     */
74    function getSort() { return 300; }
75
76    /**
77     * Register the <blog *></blog> syntax
78     *
79     * @param string $mode
80     */
81    function connectTo($mode) {
82        $this->Lexer->addSpecialPattern('<blog ?[^>]*>.*?</blog>', $mode, 'plugin_blogtng_blog');
83    }
84
85    /**
86     * Parse the type and configuration data from the syntax
87     *
88     * @param   string       $match   The text matched by the patterns
89     * @param   int          $state   The lexer state for the match
90     * @param   int          $pos     The character position of the matched text
91     * @param   Doku_Handler $handler The Doku_Handler object
92     * @return  bool|array Return an array with all data you want to use in render, false don't add an instruction
93     */
94    public function handle($match, $state, $pos, Doku_Handler $handler) {
95        $match = substr(trim($match), 5, -7); // strip '<blog' and '</blog>'
96        list($type,$conf) = explode('>',$match,2);
97        $type = trim($type);
98        $conf = trim($conf);
99        $conf = linesToHash(explode("\n", $conf));
100        if(!$type) $type = 'list';
101
102        // check type
103        if(!in_array($type,$this->type_whitelist)){
104            msg('Unknown blog syntax type "'.hsc($type).'" using "list" instead',-1);
105            $type = 'list';
106        }
107
108        // handle multi keys
109        $conf['blog'] = array_filter(array_map('trim', explode(',', $conf['blog'])));
110        $conf['tags'] = array_filter(array_map('trim', explode(',', $conf['tags'])));
111        $conf['type'] = array_filter(array_map('trim', explode(',', $conf['type'])));
112
113        if (($type != 'tagsearch') && (!count($conf['blog']))) {
114
115            $conf['blog'] = array('default');
116
117        }
118
119        // higher default limit for tag cloud
120        if($type == 'tagcloud' && !$conf['limit']) {
121            $conf['limit'] = 25;
122        }
123
124        // default to listwrap for recent comments
125        if(($type == 'recentcomments' || $type == 'tagsearch') && !isset($conf['listwrap'])){
126            $conf['listwrap'] = 1;
127        }
128
129        // reversed listwrap syntax
130        if($conf['nolistwrap']) {
131            $conf['listwrap'] = 0;
132            unset($conf['nolistwrap']);
133        }
134        // reversed nolist to listwrap syntax (backward compatibility)
135        if($conf['nolist']) {
136            $conf['listwrap'] = 0;
137            unset($conf['nolist']);
138        }
139
140        // merge with default config
141        $conf = array_merge($this->config, $conf);
142
143        return array('type'=>$type, 'conf'=>$conf);
144    }
145
146    /**
147     * Handles the actual output creation.
148     *
149     * @param string          $mode     output format being rendered
150     * @param Doku_Renderer   $renderer the current renderer object
151     * @param array           $data     data created by handler()
152     * @return  boolean                 rendered correctly? (however, returned value is not used at the moment)
153     */
154    public function render($mode, Doku_Renderer $renderer, $data) {
155        if($mode != 'xhtml') return false;
156
157        $this->loadHelpers();
158
159        // set target if not set yet
160        global $ID;
161        if(!isset($data['conf']['target'])) $data['conf']['target'] = $ID;
162
163        // add additional data from request parameters
164        if($start = $this->tools->getParam('pagination/start')){  // start offset
165            $data['conf']['offset'] = (int) $start;
166        }
167
168        if($tags = $this->tools->getParam('post/tags')){  // tags
169            $data['conf']['tags'] = array_merge(
170                                       $data['conf']['tags'],
171                                       explode(',',$tags));
172        }
173        $data['conf']['tags'] = array_map('trim',$data['conf']['tags']);
174        $data['conf']['tags'] = array_unique($data['conf']['tags']);
175        $data['conf']['tags'] = array_filter($data['conf']['tags']);
176
177        // dispatch to the correct type handler
178        $renderer->info['cache'] = (bool)$data['conf']['cache'];
179        switch($data['type']){
180            case 'related':
181                $renderer->doc .= $this->entryhelper->xhtml_related($data['conf']);
182                break;
183            case 'pagination':
184                $renderer->doc .= $this->entryhelper->xhtml_pagination($data['conf']);
185                break;
186            case 'newform':
187                $renderer->info['cache'] = false; //never cache this
188                $renderer->doc .= $this->entryhelper->xhtml_newform($data['conf']);
189                break;
190            case 'recentcomments':
191                // FIXME to cache or not to cache?
192                $renderer->doc .= $this->commenthelper->xhtml_recentcomments($data['conf']);
193                break;
194            case 'tagcloud':
195                $renderer->info['cache'] = false; // never cache this
196                $renderer->doc .= $this->taghelper->xhtml_tagcloud($data['conf']);
197                break;
198            case 'tagsearch':
199                $renderer->doc .= $this->entryhelper->xhtml_tagsearch($data['conf'], $renderer);
200                break;
201            default:
202                $renderer->doc .= $this->entryhelper->xhtml_list($data['conf'], $renderer);
203        }
204
205        return true;
206    }
207
208    /**
209     * Parse options given in the syntax
210     *
211     * @param $opt
212     */
213    function _parse_opt($opt) {
214        switch(true) {
215            case (in_array($opt, $this->data_whitelist['sortorder'])):
216                $this->config['sortorder'] = strtoupper($opt);
217                break;
218            case (in_array($opt, $this->data_whitelist['sortby'])):
219                $this->config['sortby'] = substr($opt, 2);
220                break;
221            case (preg_match('/^\d$/', $opt)):
222                $this->config['limit'] = $opt;
223                break;
224            case (preg_match('/^\+(\d+)$/', $opt, $match)):
225                $this->config['order'] = $match[1];
226                break;
227            case (preg_match('/^tpl(\w+)$/', $opt, $match)):
228                $this->config['tpl'] = $match[1];
229                break;
230            default;
231                continue;
232        }
233    }
234
235    /**
236     * Load required helper plugins.
237     */
238    private function loadHelpers() {
239        $this->entryhelper = plugin_load('helper', 'blogtng_entry');
240        $this->tools = plugin_load('helper', 'blogtng_tools');
241        $this->commenthelper = plugin_load('helper', 'blogtng_comments');
242        $this->taghelper = plugin_load('helper', 'blogtng_tags');
243    }
244}
245// vim:ts=4:sw=4:et:
246