[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package s9e\TextFormatter 5 * @copyright Copyright (c) 2010-2022 The s9e authors 6 * @license http://www.opensource.org/licenses/mit-license.php The MIT License 7 */ 8 namespace s9e\TextFormatter\Plugins\PipeTables; 9 10 use s9e\TextFormatter\Plugins\ParserBase; 11 12 class Parser extends ParserBase 13 { 14 /** 15 * @var integer Position of the cursor while parsing tables or adding tags 16 */ 17 protected $pos; 18 19 /** 20 * @var array Current table being parsed 21 */ 22 protected $table; 23 24 /** 25 * @var \s9e\TextFormatter\Parser\Tag 26 */ 27 protected $tableTag; 28 29 /** 30 * @var array[] List of tables 31 */ 32 protected $tables; 33 34 /** 35 * @var string Text being parsed 36 */ 37 protected $text; 38 39 /** 40 * {@inheritdoc} 41 */ 42 public function parse($text, array $matches) 43 { 44 $this->text = $text; 45 if ($this->config['overwriteMarkdown']) 46 { 47 $this->overwriteMarkdown(); 48 } 49 if ($this->config['overwriteEscapes']) 50 { 51 $this->overwriteEscapes(); 52 } 53 54 $this->captureTables(); 55 $this->processTables(); 56 57 unset($this->tables); 58 unset($this->text); 59 } 60 61 /** 62 * Add current line to a table 63 * 64 * @param string $line Line of text 65 * @return void 66 */ 67 protected function addLine($line) 68 { 69 $ignoreLen = 0; 70 71 if (!isset($this->table)) 72 { 73 $this->table = []; 74 75 // Make the table start at the first non-space character 76 preg_match('/^ */', $line, $m); 77 $ignoreLen = strlen($m[0]); 78 $line = substr($line, $ignoreLen); 79 } 80 81 // Overwrite the outermost pipes 82 $line = preg_replace('/^( *)\\|/', '$1 ', $line); 83 $line = preg_replace('/\\|( *)$/', ' $1', $line); 84 85 $this->table['rows'][] = ['line' => $line, 'pos' => $this->pos + $ignoreLen]; 86 } 87 88 /** 89 * Process current table's body 90 * 91 * @return void 92 */ 93 protected function addTableBody() 94 { 95 $i = 1; 96 $cnt = count($this->table['rows']); 97 while (++$i < $cnt) 98 { 99 $this->addTableRow('TD', $this->table['rows'][$i]); 100 } 101 102 $this->createBodyTags($this->table['rows'][2]['pos'], $this->pos); 103 } 104 105 /** 106 * Add a cell's tags for current table at current position 107 * 108 * @param string $tagName Either TD or TH 109 * @param string $align Either "left", "center", "right" or "" 110 * @param string $content Cell's text content 111 * @return void 112 */ 113 protected function addTableCell($tagName, $align, $content) 114 { 115 $startPos = $this->pos; 116 $endPos = $startPos + strlen($content); 117 $this->pos = $endPos; 118 119 preg_match('/^( *).*?( *)$/', $content, $m); 120 if ($m[1]) 121 { 122 $ignoreLen = strlen($m[1]); 123 $this->createIgnoreTag($startPos, $ignoreLen); 124 $startPos += $ignoreLen; 125 } 126 if ($m[2]) 127 { 128 $ignoreLen = strlen($m[2]); 129 $this->createIgnoreTag($endPos - $ignoreLen, $ignoreLen); 130 $endPos -= $ignoreLen; 131 } 132 133 $this->createCellTags($tagName, $startPos, $endPos, $align); 134 } 135 136 /** 137 * Process current table's head 138 * 139 * @return void 140 */ 141 protected function addTableHead() 142 { 143 $this->addTableRow('TH', $this->table['rows'][0]); 144 $this->createHeadTags($this->table['rows'][0]['pos'], $this->pos); 145 } 146 147 /** 148 * Process given table row 149 * 150 * @param string $tagName Either TD or TH 151 * @param array $row 152 * @return void 153 */ 154 protected function addTableRow($tagName, $row) 155 { 156 $this->pos = $row['pos']; 157 foreach (explode('|', $row['line']) as $i => $str) 158 { 159 if ($i > 0) 160 { 161 $this->createIgnoreTag($this->pos, 1); 162 ++$this->pos; 163 } 164 165 $align = (empty($this->table['cols'][$i])) ? '' : $this->table['cols'][$i]; 166 $this->addTableCell($tagName, $align, $str); 167 } 168 169 $this->createRowTags($row['pos'], $this->pos); 170 } 171 172 /** 173 * Capture all pipe tables in current text 174 * 175 * @return void 176 */ 177 protected function captureTables() 178 { 179 unset($this->table); 180 $this->tables = []; 181 182 $this->pos = 0; 183 foreach (explode("\n", $this->text) as $line) 184 { 185 if (strpos($line, '|') === false) 186 { 187 $this->endTable(); 188 } 189 else 190 { 191 $this->addLine($line); 192 } 193 $this->pos += 1 + strlen($line); 194 } 195 $this->endTable(); 196 } 197 198 /** 199 * Create a pair of TBODY tags for given text span 200 * 201 * @param integer $startPos 202 * @param integer $endPos 203 * @return void 204 */ 205 protected function createBodyTags($startPos, $endPos) 206 { 207 $this->parser->addTagPair('TBODY', $startPos, 0, $endPos, 0, -103); 208 } 209 210 /** 211 * Create a pair of TD or TH tags for given text span 212 * 213 * @param string $tagName Either TD or TH 214 * @param integer $startPos 215 * @param integer $endPos 216 * @param string $align Either "left", "center", "right" or "" 217 * @return void 218 */ 219 protected function createCellTags($tagName, $startPos, $endPos, $align) 220 { 221 if ($startPos === $endPos) 222 { 223 $tag = $this->parser->addSelfClosingTag($tagName, $startPos, 0, -101); 224 } 225 else 226 { 227 $tag = $this->parser->addTagPair($tagName, $startPos, 0, $endPos, 0, -101); 228 } 229 if ($align) 230 { 231 $tag->setAttribute('align', $align); 232 } 233 } 234 235 /** 236 * Create a pair of THEAD tags for given text span 237 * 238 * @param integer $startPos 239 * @param integer $endPos 240 * @return void 241 */ 242 protected function createHeadTags($startPos, $endPos) 243 { 244 $this->parser->addTagPair('THEAD', $startPos, 0, $endPos, 0, -103); 245 } 246 247 /** 248 * Create an ignore tag for given text span 249 * 250 * @param integer $pos 251 * @param integer $len 252 * @return void 253 */ 254 protected function createIgnoreTag($pos, $len) 255 { 256 $this->tableTag->cascadeInvalidationTo($this->parser->addIgnoreTag($pos, $len, 1000)); 257 } 258 259 /** 260 * Create a pair of TR tags for given text span 261 * 262 * @param integer $startPos 263 * @param integer $endPos 264 * @return void 265 */ 266 protected function createRowTags($startPos, $endPos) 267 { 268 $this->parser->addTagPair('TR', $startPos, 0, $endPos, 0, -102); 269 } 270 271 /** 272 * Create an ignore tag for given separator row 273 * 274 * @param array $row 275 * @return void 276 */ 277 protected function createSeparatorTag(array $row) 278 { 279 $this->createIgnoreTag($row['pos'] - 1, 1 + strlen($row['line'])); 280 } 281 282 /** 283 * Create a pair of TABLE tags for given text span 284 * 285 * @param integer $startPos 286 * @param integer $endPos 287 * @return void 288 */ 289 protected function createTableTags($startPos, $endPos) 290 { 291 $this->tableTag = $this->parser->addTagPair('TABLE', $startPos, 0, $endPos, 0, -104); 292 } 293 294 /** 295 * End current buffered table 296 * 297 * @return void 298 */ 299 protected function endTable() 300 { 301 if ($this->hasValidTable()) 302 { 303 $this->table['cols'] = $this->parseColumnAlignments($this->table['rows'][1]['line']); 304 $this->tables[] = $this->table; 305 } 306 unset($this->table); 307 } 308 309 /** 310 * Test whether a valid table is currently buffered 311 * 312 * @return bool 313 */ 314 protected function hasValidTable() 315 { 316 return (isset($this->table) && count($this->table['rows']) > 2 && $this->isValidSeparator($this->table['rows'][1]['line'])); 317 } 318 319 /** 320 * Test whether given line is a valid separator 321 * 322 * @param string $line 323 * @return bool 324 */ 325 protected function isValidSeparator($line) 326 { 327 return (bool) preg_match('/^ *:?-+:?(?:(?:\\+| *\\| *):?-+:?)+ *$/', $line); 328 } 329 330 /** 331 * Overwrite right angle brackets in given match 332 * 333 * @param string[] $m 334 * @return string 335 */ 336 protected function overwriteBlockquoteCallback(array $m) 337 { 338 return strtr($m[0], '!>', ' '); 339 } 340 341 /** 342 * Overwrite escape sequences in current text 343 * 344 * @return void 345 */ 346 protected function overwriteEscapes() 347 { 348 if (strpos($this->text, '\\|') !== false) 349 { 350 $this->text = preg_replace('/\\\\[\\\\|]/', '..', $this->text); 351 } 352 } 353 354 /** 355 * Overwrite backticks in given match 356 * 357 * @param string[] $m 358 * @return string 359 */ 360 protected function overwriteInlineCodeCallback(array $m) 361 { 362 return strtr($m[0], '|', '.'); 363 } 364 365 /** 366 * Overwrite Markdown-style markup in current text 367 * 368 * @return void 369 */ 370 protected function overwriteMarkdown() 371 { 372 // Overwrite inline code spans 373 if (strpos($this->text, '`') !== false) 374 { 375 $this->text = preg_replace_callback('/`[^`]*`/', [$this, 'overwriteInlineCodeCallback'], $this->text); 376 } 377 378 // Overwrite blockquotes 379 if (strpos($this->text, '>') !== false) 380 { 381 $this->text = preg_replace_callback('/^(?:>!? ?)+/m', [$this, 'overwriteBlockquoteCallback'], $this->text); 382 } 383 } 384 385 /** 386 * Parse and return column alignments in given separator line 387 * 388 * @param string $line 389 * @return string[] 390 */ 391 protected function parseColumnAlignments($line) 392 { 393 // Use a bitfield to represent the colons' presence and map it to the CSS value 394 $align = [ 395 0b00 => '', 396 0b01 => 'right', 397 0b10 => 'left', 398 0b11 => 'center' 399 ]; 400 401 $cols = []; 402 preg_match_all('/(:?)-+(:?)/', $line, $matches, PREG_SET_ORDER); 403 foreach ($matches as $m) 404 { 405 $key = (!empty($m[1]) ? 2 : 0) + (!empty($m[2]) ? 1 : 0); 406 $cols[] = $align[$key]; 407 } 408 409 return $cols; 410 } 411 412 /** 413 * Process current table declaration 414 * 415 * @return void 416 */ 417 protected function processCurrentTable() 418 { 419 $firstRow = $this->table['rows'][0]; 420 $lastRow = end($this->table['rows']); 421 $this->createTableTags($firstRow['pos'], $lastRow['pos'] + strlen($lastRow['line'])); 422 423 $this->addTableHead(); 424 $this->createSeparatorTag($this->table['rows'][1]); 425 $this->addTableBody(); 426 } 427 428 /** 429 * Process all the captured tables 430 * 431 * @return void 432 */ 433 protected function processTables() 434 { 435 foreach ($this->tables as $table) 436 { 437 $this->table = $table; 438 $this->processCurrentTable(); 439 } 440 } 441 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |