1<?php
2
3/**
4 * DokuWiki Plugin Numbered Headings; action component
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Satoshi Sahara <sahara.satoshi@gmail.com>
8 */
9class action_plugin_numberedheadings extends DokuWiki_Action_Plugin
10{
11    /**
12     * Registers a callback function for a given event
13     */
14    public function register(Doku_Event_Handler $controller)
15    {
16        $controller->register_hook(
17            'PARSER_HANDLER_DONE', 'BEFORE', $this, 'numbering', []
18        );
19
20        if ($this->getConf('fancy')) {
21            $controller->register_hook(
22                'RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'decorateTieredNumber'
23            );
24        }
25    }
26
27    /**
28     * PARSER_HANDLER_DONE event handler
29     * convert plugin instruction to header
30     */
31    public function numbering(Doku_Event $event)
32    {
33        // load helper object
34        static $numbering;
35        isset($numbering) || $numbering = $this->loadHelper($this->getPluginName());
36
37        $instructions =& $event->data->calls;
38
39        foreach ($instructions as $k => &$ins) {
40            if ($ins[0] == 'plugin' && $ins[1][0] == 'numberedheadings') {
41                // initialise variables to be extracted from data array
42                // that was compacted in handle() process
43                unset($dash, $level, $number, $title, $format);
44                extract($ins[1][1]);
45
46                if (!isset($dash)) { // not numbered headings
47                    // set tier1 only
48                    $numbering->setTier1($level);
49                  //unset($instructions[$k]);
50                    continue;
51                }
52
53                // auto-detect the first tier (Tier1) level
54                $tier1 = $numbering->getTier1();
55                if (!$tier1) {
56                    $tier1 = $this->getConf('tier1') ?: $level;
57                    $numbering->setTier1($tier1);
58                }
59                $tier = $level - $tier1 +1;
60
61                // non-visible numbered headings, marked with '--'
62                if ($dash > 1) {
63                    // set the heading counter only if number seems meaningful
64                    if ($number !== '') {
65                        $numbering->setHeadingCounter($level, $number);
66                    }
67
68                    if (isset($format)) {
69                        // set numbering format of current tier (and subtiers) in the page
70                        $numbering->setTierFormat($format, $tier);
71
72                    } elseif ($dash > 2 || $number === '' && $title === '' && $tier == 1) {
73                        // reset numbering feature
74                        // the first tier (Tier1) level should be decided in next match
75                        $numbering->setTier1();
76                        $numbering->setTierFormat();
77                        $numbering->setHeadingCounter();
78                    }
79                  //unset($instructions[$k]);
80                    continue;
81                }
82
83                // set the heading counter
84                $numbering->setHeadingCounter($level, $number);
85
86                // build tiered numbers for hierarchical headings
87                $tieredNumbers = $numbering->getTieredNumbers($level);
88                if ($tieredNumbers) {
89                    // append double spaces after tiered number to distinguish title
90                    $tieredNumbers .= $this->getConf('fancy') ? '  ' : ' ';
91                }
92                $text = $tieredNumbers.$title;
93
94                // rewrite plugin call to header
95                $ins[0] = 'header';
96                $ins[1] = [$text, $level, $ins[2]];
97            }
98        }
99        unset($ins);
100        // reset numbering feature prior to process other pages
101        $numbering->setTier1();
102        $numbering->setTierFormat();
103        $numbering->setHeadingCounter();
104    }
105
106    /**
107     * RENDERER_CONTENT_POSTPROCESS
108     * enclose tiered numbers of hierarchical headings in span tag
109     */
110    public function decorateTieredNumber(Doku_Event $event)
111    {
112        if ($event->data[0] == 'xhtml') {
113            $search = '#(<h\d.*?>)(.+?)(  )(?=.*?</h\d>)#';
114            $replacement = '${1}<span class="plugin_numberedheadings">${2}</span>'."\t";
115            $event->data[1] = preg_replace($search, $replacement, $event->data[1]);
116        }
117    }
118
119}
120