1<?php
2/**
3 * TocTweak plugin for DokuWiki; Syntax metatoc
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Satoshi Sahara <sahara.satoshi@gmail.com>
7 */
8
9if(!defined('DOKU_INC')) die();
10
11class syntax_plugin_toctweak_metatoc extends DokuWiki_Syntax_Plugin {
12
13    protected $mode;
14    protected $pattern = array(
15        5 => '{{(?:METATOC|TOC)\b.*?}}',
16    );
17    protected $tocStyle = array(  // default toc visual design
18        'METATOC' => 'toc_hierarchical',
19        'TOC'     => 'toc_dokuwiki',
20    );
21
22    function __construct() {
23        $this->mode = substr(get_class($this), 7); // drop 'syntax_' from class name
24    }
25
26    function getType() { return 'substition'; }
27    function getPType(){ return 'block'; }
28    function getSort() { return 30; }
29
30    /**
31     * Connect pattern to lexer
32     */
33    function connectTo($mode) {
34        $this->Lexer->addSpecialPattern($this->pattern[5], $mode, $this->mode);
35    }
36
37    /**
38     * Handle the match
39     */
40    function handle($match, $state, $pos, Doku_Handler $handler) {
41        global $ID;
42
43        // load helper object
44        isset($tocTweak) || $tocTweak = $this->loadHelper($this->getPluginName());
45
46        // Ex: {{METATOC 2-4 width18 toc_hierarchical >id#section | title}}
47
48        preg_match('/^{{([A-Z]+)([>: ]?)/', $match, $m);
49        $start = strlen($m[1]) +2;
50        $param = substr($match, $start+1, -2);
51
52        list($topLv, $maxLv, $tocClass, $tocTitle, $id) = $tocTweak->parse($param);
53
54        $hash = strstr($id, '#');
55        if ($id == $hash) { $id = $ID.$hash; }
56
57        // should disable built-in TOC here?
58        if ($m[1] == 'TOC') {
59            $handler->_addCall('notoc', array(), $pos);
60        }
61
62        // check basic tocStyle
63        if (!preg_match('/\btoc_.*\b/', $tocClass)) {
64            $tocStyle = $this->tocStyle[$m[1]];
65            $tocClass = implode(' ', array($tocStyle, $tocClass));
66        }
67
68        $data = array($id, $topLv, $maxLv, $tocClass, $tocTitle);
69        return $data;
70    }
71
72    /**
73     * Create output
74     */
75    function render($format, Doku_Renderer $renderer, $data) {
76        global $INFO, $conf, $lang;
77
78        list($id, $topLv, $maxLv, $tocClass, $tocTitle) = $data;
79        list($id, $hash) = explode('#', $id);
80        $section = $hash ? sectionID($hash, $check = false) : '';
81
82        switch ($format) {
83            case 'metadata':
84                if ($id != $INFO['id']) { // current page
85                    // set dependency info for PARSER_CACHE_USE event handler
86                    $renderer->meta['relation']['toctweak'][] = metaFN($id,'.meta');
87                }
88                return true;
89
90            case 'xhtml':
91             // $renderer->info['cache'] = false; // disable xhtml cache
92
93                // load helper object
94                isset($tocTweak) || $tocTweak = $this->loadHelper($this->getPluginName());
95
96                // retrieve TableOfContents from metadata
97                $toc = $tocTweak->get_metatoc($id, $topLv, $maxLv, $section);
98                if (empty($toc)) {
99                    $toc[] = array(  // error entry
100                        'hid'   => $section,
101                        'page'  => $id,
102                        'url'   => wl($id.'#'.$section),
103                        'class' => 'wikilink2',
104                        'title' => $id.'#'.$section,
105                        'type'  => 'ul',
106                        'level' => 1,
107                    );
108                }
109
110                // toc wrapper attributes
111                $attr['class'] = $tocClass;
112                $title = isset($tocTitle) ? $tocTitle : $lang['toc'];
113
114                $html = '<!-- METATOC START -->'.DOKU_LF;
115                $html.= '<div '.buildAttributes($attr).'>';
116                $html.= $title ? '<h3>'.hsc($title).'</h3>' : '';
117                $html.= '<div>';
118                $html.= html_buildlist($toc, 'toc', array($this, 'html_list_metatoc'));
119                $html.= '</div>';
120                $html.= '</div>'.DOKU_LF;
121                $html.= '<!-- METATOC END -->'.DOKU_LF;
122
123                $renderer->doc .= $html;
124                return true;
125        }
126    }
127
128    /**
129     * Callback for html_buildlist called from $this->render()
130     * Builds html of each list item
131     */
132    function html_list_metatoc($item) {
133        $html = '<span class="li">';
134        if (isset($item['page'])) {
135            $html.= '<a title="'.$item['page'].'#'.$item['hid'].'"';
136            $html.= ' href="'.$item['url'].'" class="'.$item['class'].'">';
137        } else {
138            $html.= '<a href="#'.$item['hid'].'">';
139        }
140        $html.= hsc($item['title']).'</a>';
141        $html.= '</span>';
142        return $html;
143    }
144
145}
146