From 698bbf6c41ff22c63c10f4cba964afe275335ec6 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Tue, 12 Jul 2016 18:49:15 +0200 Subject: [PATCH] Added support for table bbcode --- com.woltlab.wcf/bbcode.xml | 10 ++ .../lib/system/bbcode/TableBBCode.class.php | 75 +------- .../lib/system/bbcode/TdBBCode.class.php | 20 +++ .../lib/system/bbcode/TrBBCode.class.php | 20 +++ .../converter/ListMetacodeConverter.class.php | 7 - .../TableMetacodeConverter.class.php | 163 ++++++++++++++++++ 6 files changed, 216 insertions(+), 79 deletions(-) create mode 100644 wcfsetup/install/files/lib/system/bbcode/TdBBCode.class.php create mode 100644 wcfsetup/install/files/lib/system/bbcode/TrBBCode.class.php create mode 100644 wcfsetup/install/files/lib/system/html/metacode/converter/TableMetacodeConverter.class.php diff --git a/com.woltlab.wcf/bbcode.xml b/com.woltlab.wcf/bbcode.xml index 90931ec09f..a6e58cd98d 100644 --- a/com.woltlab.wcf/bbcode.xml +++ b/com.woltlab.wcf/bbcode.xml @@ -138,10 +138,20 @@ 1 + 1 + + + 1 + + + + 1 + + 1 diff --git a/wcfsetup/install/files/lib/system/bbcode/TableBBCode.class.php b/wcfsetup/install/files/lib/system/bbcode/TableBBCode.class.php index 60a0b59688..b283b8fe56 100644 --- a/wcfsetup/install/files/lib/system/bbcode/TableBBCode.class.php +++ b/wcfsetup/install/files/lib/system/bbcode/TableBBCode.class.php @@ -1,11 +1,10 @@ * @package WoltLabSuite\Core\System\Bbcode @@ -15,75 +14,7 @@ class TableBBCode extends AbstractBBCode { * @inheritDoc */ public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) { - if ($parser->getOutputType() == 'text/html') { - $parsedContent = Regex::compile('(?:\s|
)*(\[tr\].*\[/tr\])(?:\s|
)*', Regex::CASE_INSENSITIVE | Regex::DOT_ALL)->replace($content, '\\1'); - - // check syntax - $regex = new Regex('\[/?t[rd]\]', Regex::CASE_INSENSITIVE); - if ($regex->match($parsedContent, true)) { - $matches = $regex->getMatches(); - - $openTags = []; - $openTDs = 0; - $firstRowTDs = 0; - - // parse tags - foreach ($matches[0] as $match) { - switch ($match) { - case '[td]': - if (end($openTags) !== '[tr]') return ''; - $openTags[] = $match; - $openTDs++; - break; - case '[/td]': - if (end($openTags) !== '[td]') return ''; - array_pop($openTags); - break; - case '[tr]': - if (!empty($openTags)) return ''; - $openTags[] = $match; - break; - case '[/tr]': - if (end($openTags) !== '[tr]') return ''; - - array_pop($openTags); - - // check that every row has got the same number of tds - if ($firstRowTDs === 0) $firstRowTDs = $openTDs; - if ($openTDs !== $firstRowTDs) return ''; - - $openTDs = 0; - break; - } - } - - if (!empty($openTags)) return ''; - } - else { - return ''; - } - - // tr - $parsedContent = Regex::compile('\[tr\](?:\s|
)*', Regex::CASE_INSENSITIVE)->replace($parsedContent, ''); - // td - $parsedContent = str_ireplace('[td]', '', $parsedContent); - // /td - $parsedContent = Regex::compile('\[/td\](?:\s|
)*', Regex::CASE_INSENSITIVE)->replace($parsedContent, ''); - // /tr - $parsedContent = Regex::compile('\[/tr\](?:\s|
)*', Regex::CASE_INSENSITIVE)->replace($parsedContent, ''); - - return '
'.$parsedContent.'
'; - } - else if ($parser->getOutputType() == 'text/simplified-html') { - // remove table tags - $content = str_ireplace('[td]', '* ', $content); - $content = str_ireplace('[/td]', ' ', $content); - $content = str_ireplace('[tr]', '', $content); - $content = str_ireplace('[/tr]', '', $content); - - return $content; - } - - return ''; + // fake output + return '[table]' . $content . '[/table]'; } } diff --git a/wcfsetup/install/files/lib/system/bbcode/TdBBCode.class.php b/wcfsetup/install/files/lib/system/bbcode/TdBBCode.class.php new file mode 100644 index 0000000000..3145cbda28 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bbcode/TdBBCode.class.php @@ -0,0 +1,20 @@ + + * @package WoltLabSuite\Core\System\Bbcode + */ +class TdBBCode extends AbstractBBCode { + /** + * @inheritDoc + */ + public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) { + // ignore these tags as they occur outside of a table + return '[td]' . $content . '[/td]'; + } +} diff --git a/wcfsetup/install/files/lib/system/bbcode/TrBBCode.class.php b/wcfsetup/install/files/lib/system/bbcode/TrBBCode.class.php new file mode 100644 index 0000000000..6877256f22 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bbcode/TrBBCode.class.php @@ -0,0 +1,20 @@ + + * @package WoltLabSuite\Core\System\Bbcode + */ +class TrBBCode extends AbstractBBCode { + /** + * @inheritDoc + */ + public function getParsedTag(array $openingTag, $content, array $closingTag, BBCodeParser $parser) { + // ignore these tags as they occur outside of a table + return '[tr]' . $content . '[/tr]'; + } +} diff --git a/wcfsetup/install/files/lib/system/html/metacode/converter/ListMetacodeConverter.class.php b/wcfsetup/install/files/lib/system/html/metacode/converter/ListMetacodeConverter.class.php index 56a30a4f98..7ae0263554 100644 --- a/wcfsetup/install/files/lib/system/html/metacode/converter/ListMetacodeConverter.class.php +++ b/wcfsetup/install/files/lib/system/html/metacode/converter/ListMetacodeConverter.class.php @@ -170,13 +170,6 @@ class ListMetacodeConverter extends AbstractMetacodeConverter { return $element; } - /** - * @inheritDoc - */ - public function validateAttributes(array $attributes) { - return true; - } - /** * Returns true if provided node is within another list, prevents issues * with nested lists handled in the wrong order. diff --git a/wcfsetup/install/files/lib/system/html/metacode/converter/TableMetacodeConverter.class.php b/wcfsetup/install/files/lib/system/html/metacode/converter/TableMetacodeConverter.class.php new file mode 100644 index 0000000000..05b8cf84b3 --- /dev/null +++ b/wcfsetup/install/files/lib/system/html/metacode/converter/TableMetacodeConverter.class.php @@ -0,0 +1,163 @@ +`, `` and ``. + * + * @author Alexander Ebert + * @copyright 2001-2016 WoltLab GmbH + * @license GNU Lesser General Public License + * @package WoltLabSuite\Core\System\Html\Metacode\Converter + * @since 3.0 + */ +class TableMetacodeConverter extends AbstractMetacodeConverter { + /** + * @inheritDoc + */ + public function convert(\DOMDocumentFragment $fragment, array $attributes) { + $element = $fragment->ownerDocument->createElement('table'); + $tbody = $fragment->ownerDocument->createElement('tbody'); + $element->appendChild($tbody); + $tbody->appendChild($fragment); + + // get all table rows + $rows = []; + $nodes = $tbody->getElementsByTagName('woltlab-metacode'); + /** @var \DOMElement $node */ + foreach ($nodes as $node) { + if ($node->getAttribute('data-name') === 'tr' && !$this->isInsideTable($node)) { + $rows[] = $node; + } + } + + // fix markup for table rows + /** @var \DOMElement $row */ + foreach ($rows as $row) { + if ($row->parentNode !== $tbody) { + $parent = DOMUtil::getParentBefore($row, $tbody); + $tbody->insertBefore($row, $parent); + } + + DOMUtil::replaceElement($row, $row->ownerDocument->createElement('tr')); + } + + // drop everything except for elements + $childNodes = DOMUtil::getChildNodes($tbody); + foreach ($childNodes as $childNode) { + if ($childNode->nodeType === XML_ELEMENT_NODE && $childNode->nodeName === 'tr') { + continue; + } + + DOMUtil::removeNode($childNode); + } + + // get columns for each tr + /** @var \DOMElement $childNode */ + foreach ($tbody->childNodes as $childNode) { + $this->handleRow($childNode); + } + + return $element; + } + + protected function handleRow(\DOMElement $row) { + // get all table columns + $cols = []; + $nodes = $row->getElementsByTagName('woltlab-metacode'); + /** @var \DOMElement $node */ + foreach ($nodes as $node) { + if ($node->getAttribute('data-name') === 'td' && !$this->isInsideTable($node)) { + $cols[] = $node; + } + } + + // move tds + /** @var \DOMElement $col */ + foreach ($cols as $col) { + if (false && $col->parentNode !== $row) { + $parent = DOMUtil::getParentBefore($col, $row); + $row->insertBefore($col, $parent); + } + + DOMUtil::replaceElement($col, $row->ownerDocument->createElement('td')); + } + + // drop everything except for elements and removing + //

inside columns + $childNodes = DOMUtil::getChildNodes($row); + /** @var \DOMElement $childNode */ + foreach ($childNodes as $childNode) { + if ($childNode->nodeType === XML_ELEMENT_NODE && $childNode->nodeName === 'td') { + // convert

...

to ...

+ $nodes = DOMUtil::getChildNodes($childNode); + /** @var \DOMElement $node */ + foreach ($nodes as $node) { + if ($node->nodeName === 'p') { + for ($i = 0; $i < 2; $i++) { + DOMUtil::insertAfter($node->ownerDocument->createElement('br'), $node); + } + + DOMUtil::removeNode($node, true); + } + } + + // removing leading whitespace /
+ $nodes = DOMUtil::getChildNodes($childNode); + foreach ($nodes as $node) { + if ($node->nodeType === XML_TEXT_NODE) { + if (StringUtil::trim($node->textContent) !== '') { + break; + } + } + else if ($node->nodeType === XML_ELEMENT_NODE && $node->nodeName !== 'br') { + break; + } + + DOMUtil::removeNode($node); + } + + // removing trailing whitespace /
+ $nodes = DOMUtil::getChildNodes($childNode); + $i = count($nodes); + while ($i--) { + $node = $nodes[$i]; + if ($node->nodeType === XML_TEXT_NODE) { + if (StringUtil::trim($node->textContent) !== '') { + break; + } + } + else if ($node->nodeType === XML_ELEMENT_NODE && $node->nodeName !== 'br') { + break; + } + + DOMUtil::removeNode($node); + } + + continue; + } + + DOMUtil::removeNode($childNode); + } + } + + /** + * Returns true if provided node is within another table, prevents issues + * with nested tables handled in the wrong order. + * + * @param \DOMNode $node target node + * @return boolean true if provided node is within another table + */ + protected function isInsideTable(\DOMNode $node) { + /** @var \DOMElement $parent */ + $parent = $node; + while ($parent = $parent->parentNode) { + if ($parent->nodeName === 'woltlab-metacode' && $parent->getAttribute('data-name') === 'table') { + return true; + } + } + + return false; + } +} -- 2.20.1