1<?php 2/** 3 * DokuWiki Plugin autonumbering (Syntax Component) 4 * 5 * @description : This plugin allows the use of multiples counters 6 * with multiples levels, within the same page. 7 * 8 * @syntax (Base) : ~~#~~ 9 * --> Where ~~#~~ will be replaced by a number, 10 * auto incremented, and saved in a common 11 * counter. 12 * @syntax (ID) : ~~#@COUNTERID~~ 13 * --> Where COUNTERID is an alphanumeric 14 * identificator, including unserscore, 15 * and starting with a @. This allows 16 * the use of multiple counters. 17 * @syntax (forced) : ~~#NUM~~ 18 * --> Where NUM is a positive number that will 19 * be the begining of the auto incrementation 20 * from there. 21 * @syntax (multilevel) : ~~#.#~~ 22 * --> Where .# represent a sublevel and can be 23 * repeated as much as needed. 24 * 25 * @syntax (text) : ~~REPORT.EXAMPLE.#~~ 26 * --> Where only the third level will be an auto 27 * incremented number. The first level will 28 * be a repeated text. Here it will be REPORT. 29 * Samething for the second level with EXAMPLE. 30 * When using text in a level, it will be 31 * implicitly used as counter ID if no counter 32 * ID have been set with @COUNTERID. 33 * 34 * @example : ~~Test.#4.#6@CTR_ONE~~ 35 * --> Where the number will have three levels. 36 * First level will be the text « Test ». 37 * Second level will be an auto incremented 38 * number starting at 4. Third level will be 39 * an auto incremented number starting at 6. 40 * All this will be save in the counter 41 * « CTR_ONE ». 42 * 43 * @license : GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 44 */ 45 46 47// must be run within DokuWiki 48if (!defined('DOKU_INC')) die(); 49 50if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 51 52require_once(DOKU_PLUGIN.'syntax.php'); 53 54class syntax_plugin_autonumbering extends DokuWiki_Syntax_Plugin { 55 56 var $PLUGIN_PATTERN = "~~[a-zA-Z0-9_\.#@]*#[a-zA-Z0-9_\.#@]*~~"; 57 var $NUMBER_PATTERN = "[0-9]+"; 58 var $COUNTER_ID_PATTERN = "[a-zA-Z0-9_]+"; 59 60 61 public function getType() { 62 return 'substition'; 63 } 64 65 public function getPType() { 66 return 'normal'; 67 } 68 69 public function getSort() { 70 return 45; 71 } 72 73 public function connectTo($mode) { 74 $this->Lexer->addSpecialPattern($this->PLUGIN_PATTERN, $mode, 'plugin_autonumbering'); 75 } 76 77 public function handle($match, $state, $pos, Doku_Handler $handler){ 78 global $COUNTER; 79 $counterID = ''; 80 switch ($state) { 81 case DOKU_LEXER_SPECIAL : 82 83 if (preg_match('/~~(.*?)~~/', $match, $matches)) { 84 $data = $matches[1]; 85 86 if (!empty($data)) { 87 // Search for EXPLICIT counter ID 88 if (preg_match('/@(' . $this->COUNTER_ID_PATTERN . ')/', $data, $matches)) { 89 $counterID = $matches[1]; 90 // Remove counter ID from $data 91 $data = str_replace('@' . $counterID, '', $data); 92 } else { // Search for IMPLICIT counter ID 93 $alpha = preg_replace('/[^a-zA-Z]/', '', $data); 94 if (!empty($alpha)) 95 $counterID = $alpha; 96 } 97 98 // Separate levels 99 $dataTab = explode('.', $data); 100 101 // Get levels quantity 102 $levelsQty = count($dataTab); 103 $currentLevel = $levelsQty - 1; 104 105 // Check if parent level exist 106 for ($i = 0; $i < $levelsQty; ++$i) { 107 // Check if level contain text 108 if (ctype_alpha($dataTab[$i])) 109 $COUNTER[$counterID][$i] = $dataTab[$i]; 110 // Search for a forced value 111 else if (preg_match('/(' . $this->NUMBER_PATTERN . ')/', $dataTab[$i], $matches)) 112 if ($i == $currentLevel) 113 $COUNTER[$counterID][$i] = $matches[1]-1; 114 else 115 $COUNTER[$counterID][$i] = $matches[1]; 116 // initialize if needed 117 else if ((!isset($COUNTER[$counterID][$i])) || ($COUNTER[$counterID][$i] == 0)) 118 if ($i == $currentLevel) 119 $COUNTER[$counterID][$i] = 0; 120 else 121 $COUNTER[$counterID][$i] = 1; 122 } 123 124 // Check if child level exist, and initialize 125 $counter_levelsQty = count($COUNTER[$counterID]); 126 for ($i = $currentLevel+1; $i < $counter_levelsQty; ++$i) 127 $COUNTER[$counterID][$i] = 0; 128 129 // Increment current level 130 ++$COUNTER[$counterID][$currentLevel]; 131 132 // Return the number, according the level asked 133 $number = ''; 134 $period = ''; 135 for ($i = 0; $i < $levelsQty; ++$i) { 136 $number .= $period . $COUNTER[$counterID][$i]; 137 $period = '.'; 138 } 139 return array($number, NULL); 140 } else { 141 return array($match, NULL); 142 } 143 } 144 break; 145 } 146 return array(); 147 } 148 149 public function render($mode, Doku_Renderer $renderer, $data) { 150 if(($mode == 'xhtml') && (!empty($data))) { 151 list($number, $null) = $data; 152 $renderer->doc .= $number; 153 return true; 154 } 155 return false; 156 } 157 158 159 // To work with the plugin « reproduce », who needs to do 160 // the numbering prior to reproducing the code. 161 public function doNumbering($pageContent){ 162 $qtyOccurrences = preg_match_all('/~~(.*?)~~/', $pageContent, $matches); 163 if ($qtyOccurrences > 0) { 164 for ($i = 0; $i < $qtyOccurrences; $i++) { 165 list($number, $null) = $this->handle($matches[0][$i], DOKU_LEXER_SPECIAL, NULL, $handler); 166 $pageContent = preg_replace('(' . $matches[0][$i] . ')', $number, $pageContent, 1); 167 } 168 } 169 return $pageContent; 170 } 171} 172