public function patternTable($parser, $matches) { list(, $mMod) = $matches; $tx = $this->texy; $el = TexyHtml::el('table'); $mod = new TexyModifier($mMod); $mod->decorate($tx, $el); $parser->moveBackward(); if ($parser->next('#^\\|(\\#|\\=){2,}(?![|\\#=+])(.+)\\1*\\|? *' . TEXY_MODIFIER_H . '?()$#Um', $matches)) { list(, , $mContent, $mMod) = $matches; $caption = $el->create('caption'); $mod = new TexyModifier($mMod); $mod->decorate($tx, $caption); $caption->parseLine($tx, $mContent); } $isHead = FALSE; $colModifier = array(); $prevRow = array(); $rowCounter = 0; $colCounter = 0; $elPart = NULL; $lineMode = FALSE; while (TRUE) { if ($parser->next('#^\\|([=-])[+|=-]{2,}$#Um', $matches)) { if ($lineMode) { if ($matches[1] === '=') { $isHead = !$isHead; } } else { $isHead = !$isHead; $lineMode = $matches[1] === '='; } $prevRow = array(); continue; } if ($parser->next('#^\\|(.*)(?:|\\|\\ *' . TEXY_MODIFIER_HV . '?)()$#U', $matches)) { if ($rowCounter === 0 && !$isHead && $parser->next('#^\\|[=-][+|=-]{2,}$#Um', $foo)) { $isHead = TRUE; $parser->moveBackward(); } if ($elPart === NULL) { $elPart = $el->create($isHead ? 'thead' : 'tbody'); } elseif (!$isHead && $elPart->getName() === 'thead') { $this->finishPart($elPart); $elPart = $el->create('tbody'); } list(, $mContent, $mMod) = $matches; $elRow = TexyHtml::el('tr'); $mod = new TexyModifier($mMod); $mod->decorate($tx, $elRow); $rowClass = $rowCounter % 2 === 0 ? $this->oddClass : $this->evenClass; if ($rowClass && !isset($mod->classes[$this->oddClass]) && !isset($mod->classes[$this->evenClass])) { $elRow->attrs['class'][] = $rowClass; } $col = 0; $elCell = NULL; $mContent = str_replace('\\|', '|', $mContent); foreach (explode('|', $mContent) as $cell) { if (isset($prevRow[$col]) && ($lineMode || preg_match('#\\^\\ *$|\\*??(.*)\\ +\\^$#AU', $cell, $matches))) { $prevRow[$col]->rowSpan++; if (!$lineMode) { $cell = isset($matches[1]) ? $matches[1] : ''; } $prevRow[$col]->text .= "\n" . $cell; $col += $prevRow[$col]->colSpan; $elCell = NULL; continue; } if ($cell === '' && $elCell) { $elCell->colSpan++; unset($prevRow[$col]); $col++; continue; } if (!preg_match('#(\\*??)\\ *' . TEXY_MODIFIER_HV . '??(.*)' . TEXY_MODIFIER_HV . '?\\ *()$#AU', $cell, $matches)) { continue; } list(, $mHead, $mModCol, $mContent, $mMod) = $matches; if ($mModCol) { $colModifier[$col] = new TexyModifier($mModCol); } if (isset($colModifier[$col])) { $mod = clone $colModifier[$col]; } else { $mod = new TexyModifier(); } $mod->setProperties($mMod); $elCell = new TexyTableCellElement(); $elCell->setName($isHead || $mHead === '*' ? 'th' : 'td'); $mod->decorate($tx, $elCell); $elCell->text = $mContent; $elRow->add($elCell); $prevRow[$col] = $elCell; $col++; } while ($col < $colCounter) { if (isset($prevRow[$col]) && $lineMode) { $prevRow[$col]->rowSpan++; $prevRow[$col]->text .= "\n"; } else { $elCell = new TexyTableCellElement(); $elCell->setName($isHead ? 'th' : 'td'); if (isset($colModifier[$col])) { $colModifier[$col]->decorate($tx, $elCell); } $elRow->add($elCell); $prevRow[$col] = $elCell; } $col++; } $colCounter = $col; if ($elRow->count()) { $elPart->add($elRow); $rowCounter++; } else { foreach ($prevRow as $elCell) { $elCell->rowSpan--; } } continue; } break; } if ($elPart === NULL) { return FALSE; } if ($elPart->getName() === 'thead') { $elPart->setName('tbody'); } $this->finishPart($elPart); $tx->invokeHandlers('afterTable', array($parser, $el, $mod)); return $el; }
/** * Callback for:. * * .(title)[class]{style}> * |------------------ * | xxx | xxx | xxx | .(..){..}[..] * |------------------ * | aa | bb | cc | * * @param TexyBlockParser * @param array regexp matches * @param string pattern name * @return TexyHtml|string|FALSE */ public function patternTable($parser, $matches) { list(, $mMod) = $matches; // [1] => .(title)[class]{style}<>_ $tx = $this->texy; $el = TexyHtml::el('table'); $mod = new TexyModifier($mMod); $mod->decorate($tx, $el); $parser->moveBackward(); if ($parser->next('#^\\|(\\#|\\=){2,}(?![|\\#=+])(.+)\\1*\\|? *' . TEXY_MODIFIER_H . '?()$#Um', $matches)) { list(, , $mContent, $mMod) = $matches; // [1] => # / = // [2] => .... // [3] => .(title)[class]{style}<> $caption = $el->create('caption'); $mod = new TexyModifier($mMod); $mod->decorate($tx, $caption); $caption->parseLine($tx, $mContent); } $isHead = FALSE; $colModifier = array(); $prevRow = array(); // rowSpan building helper $rowCounter = 0; $colCounter = 0; $elPart = NULL; $lineMode = FALSE; // rows must be separated by lines while (TRUE) { if ($parser->next('#^\\|([=-])[+|=-]{2,}$#Um', $matches)) { // line if ($lineMode) { if ($matches[1] === '=') { $isHead = !$isHead; } } else { $isHead = !$isHead; $lineMode = $matches[1] === '='; } $prevRow = array(); continue; } if ($parser->next('#^\\|(.*)(?:|\\|\\ *' . TEXY_MODIFIER_HV . '?)()$#U', $matches)) { // smarter head detection if ($rowCounter === 0 && !$isHead && $parser->next('#^\\|[=-][+|=-]{2,}$#Um', $foo)) { $isHead = TRUE; $parser->moveBackward(); } if ($elPart === NULL) { $elPart = $el->create($isHead ? 'thead' : 'tbody'); } elseif (!$isHead && $elPart->getName() === 'thead') { $this->finishPart($elPart); $elPart = $el->create('tbody'); } // PARSE ROW list(, $mContent, $mMod) = $matches; // [1] => .... // [2] => .(title)[class]{style}<>_ $elRow = TexyHtml::el('tr'); $mod = new TexyModifier($mMod); $mod->decorate($tx, $elRow); $rowClass = $rowCounter % 2 === 0 ? $this->oddClass : $this->evenClass; if ($rowClass && !isset($mod->classes[$this->oddClass]) && !isset($mod->classes[$this->evenClass])) { $elRow->attrs['class'][] = $rowClass; } $col = 0; $elCell = NULL; // special escape sequence \| $mContent = str_replace('\\|', '|', $mContent); foreach (explode('|', $mContent) as $cell) { // rowSpan if (isset($prevRow[$col]) && ($lineMode || preg_match('#\\^\\ *$|\\*??(.*)\\ +\\^$#AU', $cell, $matches))) { $prevRow[$col]->rowSpan++; if (!$lineMode) { $cell = isset($matches[1]) ? $matches[1] : ''; } $prevRow[$col]->text .= "\n" . $cell; $col += $prevRow[$col]->colSpan; $elCell = NULL; continue; } // colSpan if ($cell === '' && $elCell) { $elCell->colSpan++; unset($prevRow[$col]); $col++; continue; } // common cell if (!preg_match('#(\\*??)\\ *' . TEXY_MODIFIER_HV . '??(.*)' . TEXY_MODIFIER_HV . '?\\ *()$#AU', $cell, $matches)) { continue; } list(, $mHead, $mModCol, $mContent, $mMod) = $matches; // [1] => * ^ // [2] => .(title)[class]{style}<>_ // [3] => .... // [4] => .(title)[class]{style}<>_ if ($mModCol) { $colModifier[$col] = new TexyModifier($mModCol); } if (isset($colModifier[$col])) { $mod = clone $colModifier[$col]; } else { $mod = new TexyModifier(); } $mod->setProperties($mMod); $elCell = new TexyTableCellElement(); $elCell->setName($isHead || $mHead === '*' ? 'th' : 'td'); $mod->decorate($tx, $elCell); $elCell->text = $mContent; $elRow->add($elCell); $prevRow[$col] = $elCell; $col++; } // even up with empty cells while ($col < $colCounter) { if (isset($prevRow[$col]) && $lineMode) { $prevRow[$col]->rowSpan++; $prevRow[$col]->text .= "\n"; } else { $elCell = new TexyTableCellElement(); $elCell->setName($isHead ? 'th' : 'td'); if (isset($colModifier[$col])) { $colModifier[$col]->decorate($tx, $elCell); } $elRow->add($elCell); $prevRow[$col] = $elCell; } $col++; } $colCounter = $col; if ($elRow->count()) { $elPart->add($elRow); $rowCounter++; } else { // redundant row foreach ($prevRow as $elCell) { $elCell->rowSpan--; } } continue; } break; } if ($elPart === NULL) { // invalid table return FALSE; } if ($elPart->getName() === 'thead') { // thead is optional, tbody is required $elPart->setName('tbody'); } $this->finishPart($elPart); // event listener $tx->invokeHandlers('afterTable', array($parser, $el, $mod)); return $el; }