From 717277d8688a19485ad33f4b986a5db4049bef67 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Thu, 4 May 2023 21:10:27 +0200 Subject: [PATCH] Unwrap and strip trailing `
` --- .../output/node/HtmlOutputNodeBr.class.php | 91 +++++++++++++++++++ .../install/files/lib/util/DOMUtil.class.php | 16 ++++ 2 files changed, 107 insertions(+) create mode 100644 wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBr.class.php diff --git a/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBr.class.php b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBr.class.php new file mode 100644 index 0000000000..2afc6bec9a --- /dev/null +++ b/wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeBr.class.php @@ -0,0 +1,91 @@ + and strips trailing
. + * + * @author Alexander Ebert + * @copyright 2001-2023 WoltLab GmbH + * @license GNU Lesser General Public License + * @since 6.0 + */ +final class HtmlOutputNodeBr extends AbstractHtmlOutputNode +{ + /** + * @inheritDoc + */ + protected $tagName = 'br'; + + /** + * @inheritDoc + */ + public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) + { + /** @var \DOMElement $element */ + foreach ($elements as $element) { + $this->unwrap($element); + $this->removeTrailingBr($element); + } + } + + private function unwrap(DOMElement $br): void + { + if ($br->previousSibling || $br->nextSibling) { + return; + } + + $parent = $br; + while (($parent = $parent->parentNode) !== null) { + switch ($parent->nodeName) { + case "b": + case "em": + case "i": + case "strong": + case "sub": + case "sup": + case "span": + case "u": + if ($br->previousSibling || $br->nextSibling) { + return; + } + + $parent->parentNode->insertBefore($br, $parent); + $parent->parentNode->removeChild($parent); + $parent = $br; + + break; + + default: + return; + } + } + } + + private function removeTrailingBr(DOMElement $br): void + { + if ($br->getAttribute("data-cke-filler") === "true") { + return; + } + + $paragraph = DOMUtil::closest($br, "p"); + if ($paragraph === null) { + return; + } + + if (!DOMUtil::isLastNode($br, $paragraph)) { + return; + } + + if ($paragraph->childNodes->length === 1 && $paragraph->childNodes->item(0) === $br) { + $paragraph->parentNode->removeChild($paragraph); + } else { + $br->remove(); + } + } +} diff --git a/wcfsetup/install/files/lib/util/DOMUtil.class.php b/wcfsetup/install/files/lib/util/DOMUtil.class.php index cbda410b58..f730bad668 100644 --- a/wcfsetup/install/files/lib/util/DOMUtil.class.php +++ b/wcfsetup/install/files/lib/util/DOMUtil.class.php @@ -232,6 +232,22 @@ final class DOMUtil return false; } + /** + * Finds the closest parent matching the tag name. + * + * @since 6.0 + */ + public static function closest(\DOMNode $node, string $tagName): \DOMNode|null + { + while ($node = $node->parentNode) { + if ($node->nodeName === $tagName) { + return $node; + } + } + + return null; + } + /** * Inserts given DOM node after the reference node. */ -- 2.20.1