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 $class = 'autonumberingAll autonumbering'; 81 switch ($state) { 82 case DOKU_LEXER_SPECIAL : 83 84 if (preg_match('/~~(.*?)~~/', $match, $matches)) { 85 $data = $matches[1]; 86 87 if (!empty($data)) { 88 // Search for EXPLICIT counter ID 89 if (preg_match('/@(' . $this->COUNTER_ID_PATTERN . ')/', $data, $matches)) { 90 $counterID = $matches[1]; 91 // Remove counter ID from $data 92 $data = str_replace('@' . $counterID, '', $data); 93 } else { // Search for IMPLICIT counter ID 94 $alpha = preg_replace('/[^a-zA-Z]/', '', $data); 95 if (!empty($alpha)) 96 $counterID = $alpha; 97 } 98 99 // Separate levels 100 $dataTab = explode('.', $data); 101 102 // Get levels quantity 103 $levelsQty = count($dataTab); 104 $currentLevel = $levelsQty - 1; 105 106 // Check if parent level exist 107 for ($i = 0; $i < $levelsQty; ++$i) { 108 // Check if level contain text 109 if (ctype_alpha($dataTab[$i])) { 110 $COUNTER[$counterID][$i] = $dataTab[$i]; 111 $class .= '_' . $dataTab[$i]; 112 // Search for a forced value 113 } else if (preg_match('/(' . $this->NUMBER_PATTERN . ')/', $dataTab[$i], $matches)) 114 if ($i == $currentLevel) 115 $COUNTER[$counterID][$i] = $matches[1]-1; 116 else 117 $COUNTER[$counterID][$i] = $matches[1]; 118 // initialize if needed 119 else if ((!isset($COUNTER[$counterID][$i])) || ($COUNTER[$counterID][$i] == 0)) 120 if ($i == $currentLevel) 121 $COUNTER[$counterID][$i] = 0; 122 else 123 $COUNTER[$counterID][$i] = 1; 124 } 125 126 // Check if child level exist, and initialize 127 $counter_levelsQty = count($COUNTER[$counterID]); 128 for ($i = $currentLevel+1; $i < $counter_levelsQty; ++$i) 129 $COUNTER[$counterID][$i] = 0; 130 131 // Increment current level 132 ++$COUNTER[$counterID][$currentLevel]; 133 134 // Return the number, according the level asked 135 $number = "<span class=\"$class\">"; 136 $period = ''; 137 for ($i = 0; $i < $levelsQty; ++$i) { 138 $number .= $period . $COUNTER[$counterID][$i]; 139 if (ctype_alpha($COUNTER[$counterID][$i])) { 140 if ($period != '.') 141 $period = ' '; 142 } else 143 $period = '.'; 144 } 145 $number .= '</span>'; 146 return array($number, NULL); 147 } else { 148 return array($match, NULL); 149 } 150 } 151 break; 152 } 153 return array(); 154 } 155 156 public function render($mode, Doku_Renderer $renderer, $data) { 157 if(($mode == 'xhtml') && (!empty($data))) { 158 list($number, $null) = $data; 159 $renderer->doc .= $number; 160 return true; 161 } 162 return false; 163 } 164 165 166 // To work with the plugin « reproduce », who needs to do 167 // the numbering prior to reproducing the code. 168 public function doNumbering($pageContent){ 169 $qtyOccurrences = preg_match_all('/~~(.*?)~~/', $pageContent, $matches); 170 if ($qtyOccurrences > 0) { 171 for ($i = 0; $i < $qtyOccurrences; $i++) { 172 list($number, $null) = $this->handle($matches[0][$i], DOKU_LEXER_SPECIAL, NULL, $handler); 173 $pageContent = preg_replace('(' . $matches[0][$i] . ')', $number, $pageContent, 1); 174 } 175 } 176 return $pageContent; 177 } 178} 179