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