xref: /plugin/autonumbering/syntax.php (revision 55913da9fae0b8ead662618c8b9ce6364a6d8b0d)
1937e5910SFlorian Wehner<?php
2*55913da9SDaniel Hofer
3937e5910SFlorian Wehner/**
4937e5910SFlorian Wehner * DokuWiki Plugin autonumbering (Syntax Component)
5937e5910SFlorian Wehner *
6937e5910SFlorian Wehner * @description         :   This plugin allows the use of multiples counters
7937e5910SFlorian Wehner *                          with multiples levels, within the same page.
8937e5910SFlorian Wehner *
9937e5910SFlorian Wehner * @syntax (Base)       :   ~~#~~
10937e5910SFlorian Wehner *                              --> Where ~~#~~ will be replaced by a number,
11937e5910SFlorian Wehner *                                  auto incremented, and saved in a common
12937e5910SFlorian Wehner *                                  counter.
13937e5910SFlorian Wehner * @syntax (ID)         :   ~~#@COUNTERID~~
14937e5910SFlorian Wehner *                              --> Where COUNTERID is an alphanumeric
15937e5910SFlorian Wehner *                                  identificator, including unserscore,
16937e5910SFlorian Wehner *                                  and starting with a @. This allows
17937e5910SFlorian Wehner *                                  the use of multiple counters.
18937e5910SFlorian Wehner * @syntax (forced)     :   ~~#NUM~~
19937e5910SFlorian Wehner *                              --> Where NUM is a positive number that will
20937e5910SFlorian Wehner *                                  be the begining of the auto incrementation
21937e5910SFlorian Wehner *                                  from there.
22937e5910SFlorian Wehner * @syntax (multilevel) :   ~~#.#~~
23937e5910SFlorian Wehner *                              --> Where .# represent a sublevel and can be
24937e5910SFlorian Wehner *                                  repeated as much as needed.
25937e5910SFlorian Wehner *
26937e5910SFlorian Wehner * @syntax (text)       :   ~~REPORT.EXAMPLE.#~~
27937e5910SFlorian Wehner *                              --> Where only the third level will be an auto
28937e5910SFlorian Wehner *                                  incremented number. The first level will
29937e5910SFlorian Wehner *                                  be a repeated text. Here it will be REPORT.
30937e5910SFlorian Wehner *                                  Samething for the second level with EXAMPLE.
31937e5910SFlorian Wehner *                                  When using text in a level, it will be
32937e5910SFlorian Wehner *                                  implicitly used as counter ID if no counter
33937e5910SFlorian Wehner *                                  ID have been set with @COUNTERID.
34937e5910SFlorian Wehner *
35937e5910SFlorian Wehner * @example             :   ~~Test.#4.#6@CTR_ONE~~
36937e5910SFlorian Wehner *                              --> Where the number will have three levels.
37937e5910SFlorian Wehner *                                  First level will be the text « Test ».
38937e5910SFlorian Wehner *                                  Second level will be an auto incremented
39937e5910SFlorian Wehner *                                  number starting at 4. Third level will be
40937e5910SFlorian Wehner *                                  an auto incremented number starting at 6.
41937e5910SFlorian Wehner *                                  All this will be save in the counter
42937e5910SFlorian Wehner *                                  « CTR_ONE ».
43937e5910SFlorian Wehner *
44937e5910SFlorian Wehner * @license             :   GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
45937e5910SFlorian Wehner */
46937e5910SFlorian Wehner
47*55913da9SDaniel Hofer// phpcs:disable PSR1.Files.SideEffects.FoundWithSymbols
48*55913da9SDaniel Hoferuse dokuwiki\Extension\SyntaxPlugin;
49937e5910SFlorian Wehner
50937e5910SFlorian Wehner// must be run within DokuWiki
51*55913da9SDaniel Hoferif (!defined('DOKU_INC')) {
52*55913da9SDaniel Hofer    die();
53*55913da9SDaniel Hofer}
54*55913da9SDaniel Hofer// phpcs:enable
55937e5910SFlorian Wehner
56*55913da9SDaniel Hoferclass syntax_plugin_autonumbering extends SyntaxPlugin
57*55913da9SDaniel Hofer{
58*55913da9SDaniel Hofer    public $PLUGIN_PATTERN = "~~[a-zA-Z0-9_\.#@]*#[a-zA-Z0-9_\.#@]*~~";
59*55913da9SDaniel Hofer    public $NUMBER_PATTERN = "[0-9]+";
60*55913da9SDaniel Hofer    public $COUNTER_ID_PATTERN = "[a-zA-Z0-9_]+";
61937e5910SFlorian Wehner
62*55913da9SDaniel Hofer    public function getType()
63*55913da9SDaniel Hofer    {
640d804a35SFlorian Wehner        return 'substition';
650d804a35SFlorian Wehner    }
660d804a35SFlorian Wehner
67*55913da9SDaniel Hofer    public function getPType()
68*55913da9SDaniel Hofer    {
690d804a35SFlorian Wehner        return 'normal';
700d804a35SFlorian Wehner    }
710d804a35SFlorian Wehner
72*55913da9SDaniel Hofer    public function getSort()
73*55913da9SDaniel Hofer    {
740d804a35SFlorian Wehner        return 45;
750d804a35SFlorian Wehner    }
760d804a35SFlorian Wehner
77*55913da9SDaniel Hofer    public function connectTo($mode)
78*55913da9SDaniel Hofer    {
79937e5910SFlorian Wehner        $this->Lexer->addSpecialPattern($this->PLUGIN_PATTERN, $mode, 'plugin_autonumbering');
80937e5910SFlorian Wehner    }
81937e5910SFlorian Wehner
82*55913da9SDaniel Hofer    public function handle($match, $state, $pos, Doku_Handler $handler)
83*55913da9SDaniel Hofer    {
84937e5910SFlorian Wehner        global $COUNTER;
85937e5910SFlorian Wehner        $counterID = '';
86bbc4fb60SJan Kończak        $class = 'autonumberingAll autonumbering';
87937e5910SFlorian Wehner        switch ($state) {
88937e5910SFlorian Wehner            case DOKU_LEXER_SPECIAL:
89937e5910SFlorian Wehner                if (preg_match('/~~(.*?)~~/', $match, $matches)) {
90937e5910SFlorian Wehner                    $data = $matches[1];
91937e5910SFlorian Wehner
92937e5910SFlorian Wehner                    if (!empty($data)) {
93937e5910SFlorian Wehner                        // Search for EXPLICIT counter ID
94937e5910SFlorian Wehner                        if (preg_match('/@(' . $this->COUNTER_ID_PATTERN . ')/', $data, $matches)) {
95937e5910SFlorian Wehner                            $counterID = $matches[1];
96937e5910SFlorian Wehner                            // Remove counter ID from $data
97937e5910SFlorian Wehner                            $data = str_replace('@' . $counterID, '', $data);
98937e5910SFlorian Wehner                        } else {    // Search for IMPLICIT counter ID
99937e5910SFlorian Wehner                            $alpha = preg_replace('/[^a-zA-Z]/', '', $data);
100*55913da9SDaniel Hofer                            if (!empty($alpha)) {
101937e5910SFlorian Wehner                                $counterID = $alpha;
102937e5910SFlorian Wehner                            }
103*55913da9SDaniel Hofer                        }
104937e5910SFlorian Wehner
105937e5910SFlorian Wehner                        // Separate levels
106937e5910SFlorian Wehner                        $dataTab = explode('.', $data);
107937e5910SFlorian Wehner
108937e5910SFlorian Wehner                        // Get levels quantity
109937e5910SFlorian Wehner                        $levelsQty = count($dataTab);
110937e5910SFlorian Wehner                        $currentLevel = $levelsQty - 1;
111937e5910SFlorian Wehner
112937e5910SFlorian Wehner                        // Check if parent level exist
113937e5910SFlorian Wehner                        for ($i = 0; $i < $levelsQty; ++$i) {
114937e5910SFlorian Wehner                            // Check if level contain text
115bbc4fb60SJan Kończak                            if (ctype_alpha($dataTab[$i])) {
116937e5910SFlorian Wehner                                $COUNTER[$counterID][$i] = $dataTab[$i];
117bbc4fb60SJan Kończak                                $class .= '_' . $dataTab[$i];
118*55913da9SDaniel Hofer                            } elseif (preg_match('/(' . $this->NUMBER_PATTERN . ')/', $dataTab[$i], $matches)) {
119937e5910SFlorian Wehner                                // Search for a forced value
120*55913da9SDaniel Hofer                                if ($i == $currentLevel) {
121937e5910SFlorian Wehner                                    $COUNTER[$counterID][$i] = $matches[1] - 1;
122*55913da9SDaniel Hofer                                } else {
123937e5910SFlorian Wehner                                    $COUNTER[$counterID][$i] = $matches[1];
124*55913da9SDaniel Hofer                                }
125*55913da9SDaniel Hofer                            } elseif ((!isset($COUNTER[$counterID][$i])) || ($COUNTER[$counterID][$i] == 0)) {
126937e5910SFlorian Wehner                                // initialize if needed
127*55913da9SDaniel Hofer                                if ($i == $currentLevel) {
128937e5910SFlorian Wehner                                    $COUNTER[$counterID][$i] = 0;
129*55913da9SDaniel Hofer                                } else {
130937e5910SFlorian Wehner                                    $COUNTER[$counterID][$i] = 1;
131937e5910SFlorian Wehner                                }
132*55913da9SDaniel Hofer                            }
133*55913da9SDaniel Hofer                        }
134937e5910SFlorian Wehner
135937e5910SFlorian Wehner                        // Check if child level exist, and initialize
136937e5910SFlorian Wehner                        $counter_levelsQty = count($COUNTER[$counterID]);
137*55913da9SDaniel Hofer                        for ($i = $currentLevel + 1; $i < $counter_levelsQty; ++$i) {
138937e5910SFlorian Wehner                            $COUNTER[$counterID][$i] = 0;
139*55913da9SDaniel Hofer                        }
140937e5910SFlorian Wehner
141937e5910SFlorian Wehner                        // Increment current level
142937e5910SFlorian Wehner                        ++$COUNTER[$counterID][$currentLevel];
143937e5910SFlorian Wehner
144937e5910SFlorian Wehner                        // Return the number, according the level asked
145bbc4fb60SJan Kończak                        $number = "<span class=\"$class\">";
146937e5910SFlorian Wehner                        $period = '';
147937e5910SFlorian Wehner                        for ($i = 0; $i < $levelsQty; ++$i) {
148937e5910SFlorian Wehner                            $number .= $period . $COUNTER[$counterID][$i];
149698cdb17SJan Kończak                            if (ctype_alpha($COUNTER[$counterID][$i])) {
150*55913da9SDaniel Hofer                                if ($period != '.') {
151698cdb17SJan Kończak                                    $period = ' ';
152*55913da9SDaniel Hofer                                }
153*55913da9SDaniel Hofer                            } else {
154937e5910SFlorian Wehner                                $period = '.';
155937e5910SFlorian Wehner                            }
156*55913da9SDaniel Hofer                        }
157bbc4fb60SJan Kończak                        $number .= '</span>';
158*55913da9SDaniel Hofer                        return array($number, null);
159937e5910SFlorian Wehner                    } else {
160*55913da9SDaniel Hofer                        return array($match, null);
161937e5910SFlorian Wehner                    }
162937e5910SFlorian Wehner                }
163937e5910SFlorian Wehner                break;
164937e5910SFlorian Wehner        }
165937e5910SFlorian Wehner        return array();
166937e5910SFlorian Wehner    }
167937e5910SFlorian Wehner
168*55913da9SDaniel Hofer    public function render($mode, Doku_Renderer $renderer, $data)
169*55913da9SDaniel Hofer    {
170937e5910SFlorian Wehner        if (($mode == 'xhtml') && (!empty($data))) {
171937e5910SFlorian Wehner            list($number, $null) = $data;
172937e5910SFlorian Wehner            $renderer->doc .= $number;
173937e5910SFlorian Wehner            return true;
174937e5910SFlorian Wehner        }
175937e5910SFlorian Wehner        return false;
176937e5910SFlorian Wehner    }
177937e5910SFlorian Wehner
178937e5910SFlorian Wehner    // To work with the plugin « reproduce », who needs to do
179937e5910SFlorian Wehner    // the numbering prior to reproducing the code.
180*55913da9SDaniel Hofer    public function doNumbering($pageContent)
181*55913da9SDaniel Hofer    {
182937e5910SFlorian Wehner        $qtyOccurrences = preg_match_all('/~~(.*?)~~/', $pageContent, $matches);
183937e5910SFlorian Wehner        if ($qtyOccurrences > 0) {
184937e5910SFlorian Wehner            for ($i = 0; $i < $qtyOccurrences; $i++) {
185*55913da9SDaniel Hofer                list($number, $null) = $this->handle($matches[0][$i], DOKU_LEXER_SPECIAL, null, $handler);
186937e5910SFlorian Wehner                $pageContent = preg_replace('(' . $matches[0][$i] . ')', $number, $pageContent, 1);
187937e5910SFlorian Wehner            }
188937e5910SFlorian Wehner        }
189937e5910SFlorian Wehner        return $pageContent;
190937e5910SFlorian Wehner    }
191937e5910SFlorian Wehner}
192