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