1<?php 2 3require_once DOKU_INC.'inc/parser/parser.php'; 4 5/** 6 * All DokuWiki plugins to extend the parser/rendering mechanism 7 * need to inherit from this class 8 */ 9class helper_plugin_dtable extends dokuwiki_plugin 10{ 11 static $line_nr_c = array(); 12 static $file_cont = NULL; 13 14 function error($code, $json=false) 15 { 16 if($json == true) { 17 return json_encode(array('type' => 'error', 'msg' => $this->getLang($code))); 18 } else { 19 return $this->getLang($code); 20 } 21 } 22 23 static function line_nr($pos, $file_path, $start_line = 0) { 24 $line_nr = 0; 25 if (!is_array(self::$line_nr_c[$file_path] ?? null)) { 26 self::$line_nr_c[$file_path] = array(); 27 $start_pos = 0; 28 $line_nr = 0; 29 } else { 30 $start_pos = count(self::$line_nr_c[$file_path]) - 1; 31 $line_nr = self::$line_nr_c[$file_path][count(self::$line_nr_c[$file_path]) - 1]; 32 } 33 34 if ($start_line > 0) { 35 //find last pos on current line 36 if (($find = array_search($start_line, self::$line_nr_c[$file_path] ?? [])) !== false) { 37 //the new line charter from last line -> it's nessesery in order to corect work of my handler 38 $start_pos = $find; 39 $pos += $find; 40 } else { 41 if (self::$file_cont == NULL) 42 self::$file_cont = io_readFile($file_path); 43 44 for($i = $start_pos; $i < strlen(self::$file_cont) && $line_nr < $start_line; $i++) { 45 self::$line_nr_c[$file_path][$i] = $line_nr; 46 if(self::$file_cont[$i] == "\n") 47 $line_nr++; 48 } 49 self::$line_nr_c[$file_path][$i] = $line_nr; 50 51 $pos += $i; 52 $start_pos = $i; 53 } 54 $line_nr = $start_line; 55 56 } 57 if ($start_pos >= $pos) { 58 /*dbglog("TYRANOZAUR"); 59 dbglog(self::$line_nr_c);*/ 60 return self::$line_nr_c[$file_path][$pos]; 61 } else { 62 if (self::$file_cont == NULL) 63 self::$file_cont = io_readFile($file_path); 64 65 for($i=$start_pos;$i <= $pos; $i++) 66 { 67 self::$line_nr_c[$file_path][$i] = $line_nr; 68 if(self::$file_cont[$i] == "\n") 69 $line_nr++; 70 } 71 return self::$line_nr_c[$file_path][$pos]; 72 } 73 } 74 function rows($row, $page_id, $start_line) 75 { 76 $Parser = new Doku_Parser(); 77 78 $Parser->Handler = new helper_plugin_dtable_handler($page_id, $start_line); 79 80 //add modes to parser 81 $modes = p_get_parsermodes(); 82 foreach($modes as $mode) { 83 $Parser->addMode($mode['mode'], $mode['obj']); 84 } 85 86 return $Parser->parse($row); 87 88 } 89 function get_spans($start_line, $page_lines, $page_id) { 90 $table = ''; 91 for ($i = $start_line; trim($page_lines[$i]) != '</dtable>' && $i < count($page_lines); $i++) { 92 $table .= $page_lines[$i]."\n"; 93 } 94 95 $spans = array(); 96 $rows = self::rows($table, $page_id, $start_line); 97 for ($i = 0; $i < count($rows); $i++) { 98 for ($j = 0; $j < count($rows[$i][0]); $j++) { 99 $spans[$i][$j][0] = $rows[$i][0][$j][0]; 100 $spans[$i][$j][1] = $rows[$i][0][$j][1]; 101 } 102 } 103 return $spans; 104 } 105 function format_row($array_line) { 106 $line = ''; 107 foreach ($array_line as $cell) 108 { 109 if ($cell[0] == 'tableheader_open') 110 { 111 $line .= '^'.$cell[1]; 112 } else 113 { 114 $line .= '|'.$cell[1]; 115 } 116 } 117 if ($array_line[count($array_line) - 1][0] == 'tableheader_open') 118 { 119 $line .= '^'; 120 } else 121 { 122 $line .= '|'; 123 } 124 $line = str_replace("\n", '\\\\ ', $line); 125 126 return $line; 127 } 128 function parse_line($line, $page_id) 129 { 130 $line = preg_replace('/\s*:::\s*\|/', '', $line); 131 132 133 $info = array(); 134 $html = p_render('xhtml',p_get_instructions($line),$info); 135 136 $maches = array(); 137 138 preg_match('/<tr.*?>(.*?)<\/tr>/si', $html, $maches); 139 140 return trim($maches[1]); 141 } 142} 143 144class helper_plugin_dtable_handler { 145 public $calls = NULL; 146 public $row = 0; 147 public $cell = 0; 148 public $type; 149 public $file_path; 150 public $start_line; 151 152 public function __construct($page_id, $start_line) { 153 $this->file_path = wikiFN($page_id); 154 $this->start_line = $start_line; 155 } 156 157 function table($match, $state, $pos) { 158 switch ( $state ) { 159 160 case DOKU_LEXER_ENTER: 161 162 $type = trim($match); 163 164 $this->calls = array(); 165 166 $line = helper_plugin_dtable::line_nr($pos, $this->file_path, $this->start_line); 167 168 $this->calls[$this->row][0][$this->cell] = array(1, 1, $type, ''); 169 $this->calls[$this->row][1][0] = $line; 170 171 break; 172 173 case DOKU_LEXER_EXIT: 174 $line = helper_plugin_dtable::line_nr($pos, $this->file_path, $this->start_line); 175 $this->calls[$this->row][1][1] = $line - 1; 176 177 178 break; 179 180 case DOKU_LEXER_UNMATCHED: 181 if (is_array($this->calls)) { 182 $this->calls[$this->row][0][$this->cell][3] .= $match; 183 } 184 break; 185 186 case DOKU_LEXER_MATCHED: 187 if ( preg_match('/:::/',$match) ) { 188 $this->calls[$this->row][0][$this->cell][3] .= $match; 189 } else if ( trim($match) == '' ){ 190 $this->calls[$this->row][0][$this->cell][3] .= $match; 191 } else { 192 $row = $this->row; 193 while (preg_match('/^\s*:::\s*$/', $this->calls[$row][0][$this->cell][3]) && $row > 0) { 194 $row--; 195 } 196 if ($row != $this->row) 197 $this->calls[$row][0][$this->cell][1]++; 198 199 if ( $match[0] == "\n") { 200 $line = helper_plugin_dtable::line_nr($pos, $this->file_path, $this->start_line); 201 $this->calls[$this->row][1][1] = $line - 1; 202 203 //remove last cell and -- the celsapn it doesn't exist 204 array_pop($this->calls[$this->row][0]); 205 206 $this->row++; 207 $this->calls[$this->row] = array(array(), array()); 208 209 $this->cell = 0; 210 $type = $match[1]; 211 212 $this->calls[$this->row][1][0] = $line; 213 214 $this->calls[$this->row][0][$this->cell] = array(1, 1, $type, ''); 215 } else { 216 if ($this->calls[$this->row][0][$this->cell][3] == '' && $this->cell > 0) { 217 $this->calls[$this->row][0][$this->cell - 1][0]++; 218 array_pop($this->calls[$this->row][0]); 219 } else { 220 $this->cell++; 221 } 222 $type = $match[0]; 223 $this->calls[$this->row][0][$this->cell] = array(1, 1, $type, ''); 224 225 } 226 } 227 break; 228 } 229 return true; 230 } 231 /** Change // into \n during editing in textbox, can be turn off if not needed. */ 232 public function linebreak($match, $state, $pos) { 233 $this->calls[$this->row][0][$this->cell][3] .= "\n"; 234 return true; 235 } 236 /** 237 * Catchall handler for the remaining syntax 238 * 239 * @param string $name Function name that was called 240 * @param array $params Original parameters 241 * @return bool If parsing should be continue 242 */ 243 public function __call($name, $params) { 244 if($this->calls === null) $this->calls = []; 245 if(!isset($this->calls[$this->row][0][$this->cell][3])) { 246 $this->calls[$this->row][0][$this->cell][3] = ''; 247 } 248 $this->calls[$this->row][0][$this->cell][3] .= $params[0]; 249 return true; 250 } 251 public function _finalize() { 252 //remove last cell and -- the celsapn it doesn't exist 253 array_pop($this->calls[$this->row][0]); 254 $this->row = 0; 255 $this->cell = 0; 256 } 257} 258 259