Detect links in one line alone
authorCyperghost <olaf_schmitz_1@t-online.de>
Wed, 17 Jan 2024 12:29:50 +0000 (13:29 +0100)
committerCyperghost <olaf_schmitz_1@t-online.de>
Wed, 17 Jan 2024 12:29:50 +0000 (13:29 +0100)
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeProcessor.class.php
wcfsetup/install/files/lib/system/html/node/HtmlNodePlainLink.class.php
wcfsetup/install/files/lib/system/html/node/HtmlNodeUnfurlLink.class.php

index 75c73b13405fb65f7963f8691e3bcd850538b0e8..014b8c7c275703bcbf0a2b9e51ce8497b0eac68e 100644 (file)
@@ -819,6 +819,30 @@ class HtmlInputNodeProcessor extends AbstractHtmlNodeProcessor
                     $this->plainLinks[] = $plainLink->setIsStandalone($parent);
                     continue;
                 }
+            } elseif ($parent->nodeName === 'p') {
+                $nextSibling = $this->getNoneEmptyNode($link, 'nextSibling');
+                $previousSibling = $this->getNoneEmptyNode($link, 'previousSibling');
+
+                //Check whether the link is at the beginning or end of the paragraph
+                //and whether the next or previous sibling is a line break.
+                //<p><a href="https://example.com">https://example.com</a><br>…</p>
+                //<p>…<br><a href="https://example.com">https://example.com</a></p>
+                if (
+                    ($nextSibling === null && $previousSibling !== null && $previousSibling->nodeName === 'br') ||
+                    ($previousSibling === null && $nextSibling !== null && $nextSibling->nodeName === 'br')
+                ) {
+                    $this->plainLinks[] = $plainLink->setIsStandalone();
+                    continue;
+                }
+                //If not, the previous and next sibling may be a line break.
+                //<p>…<br><a href="https://example.com">https://example.com</a><br>…</p>
+                if (
+                    $previousSibling !== null && $previousSibling->nodeName === 'br' &&
+                    $nextSibling !== null && $nextSibling->nodeName === 'br'
+                ) {
+                    $this->plainLinks[] = $plainLink->setIsStandalone();
+                    continue;
+                }
             }
 
             $this->plainLinks[] = $plainLink->setIsInline();
@@ -835,4 +859,15 @@ class HtmlInputNodeProcessor extends AbstractHtmlNodeProcessor
             }
         }
     }
+
+    private function getNoneEmptyNode(?\DOMNode $element, string $property): ?\DOMNode
+    {
+        while ($element = $element->{$property}) {
+            if (!DOMUtil::isEmpty($element)) {
+                return $element;
+            }
+        }
+
+        return null;
+    }
 }
index 7b75ccf9383915cf3811922a645050da4d0c4904..a7dca6b8dfc0d78d7048f7c1e42a18a3c7207265 100644 (file)
@@ -77,10 +77,10 @@ class HtmlNodePlainLink
     /**
      * Marks the link as standalone, which means that it is the only content in a line.
      *
-     * @param \DOMElement $topLevelParent
+     * @param \DOMElement|null $topLevelParent
      * @return $this
      */
-    public function setIsStandalone(\DOMElement $topLevelParent)
+    public function setIsStandalone(?\DOMElement $topLevelParent = null)
     {
         $this->standalone = true;
         $this->topLevelParent = $topLevelParent;
@@ -171,9 +171,11 @@ class HtmlNodePlainLink
                 throw new \LogicException('Cannot inject a block bbcode in an inline context.');
             }
 
-            // Replace the top level parent with the link itself, which will be replaced with the bbcode afterwards.
-            $this->topLevelParent->parentNode->insertBefore($this->link, $this->topLevelParent);
-            DOMUtil::removeNode($this->topLevelParent);
+            if ($this->topLevelParent !== null) {
+                // Replace the top level parent with the link itself, which will be replaced with the bbcode afterwards.
+                $this->topLevelParent->parentNode->insertBefore($this->link, $this->topLevelParent);
+                DOMUtil::removeNode($this->topLevelParent);
+            }
         }
 
         DOMUtil::replaceElement($this->link, $metacodeElement, false);
index ba65283fdbea4817caed4d44a48966215314ff2d..1c71ed2c46d6dce612bfc04465ac221c24066776 100644 (file)
@@ -57,6 +57,9 @@ class HtmlNodeUnfurlLink extends HtmlNodePlainLink
 
     private static function removeStyling(HtmlNodePlainLink $element): void
     {
+        if ($element->topLevelParent == null) {
+            return;
+        }
         foreach ($element->topLevelParent->childNodes as $child) {
             DOMUtil::removeNode($child);
         }