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