$this->topLevelParent->parentNode->insertBefore($this->link, $this->topLevelParent);
DOMUtil::removeNode($this->topLevelParent);
} else {
- $replaceNode = null;
- $parent = $this->link;
- $next = $this->findBr($this->link, 'nextSibling');
- $previous = $this->findBr($this->link, 'previousSibling');
-
- // When multiple links are in the same paragraph, `topLevelParent`
- // may no longer be a valid reference.
- if ($this->topLevelParent->parentNode === null) {
- $this->topLevelParent = $this->link;
- while ($this->topLevelParent->parentNode->nodeName !== 'body') {
- $this->topLevelParent = $this->topLevelParent->parentNode;
- }
- }
-
- // Link inside other elements(u, i, b, …)
- while ($next === null && $previous === null && $parent !== $this->topLevelParent) {
- $parent = $parent->parentNode;
- $next = $this->findBr($parent, 'nextSibling');
- $previous = $this->findBr($parent, 'previousSibling');
- }
-
- // The link is the only content in the top level parent. This
- // can happen when there are multiple links within one paragraph.
- if ($next === null && $previous === null) {
- $this->topLevelParent->parentNode->insertBefore($this->link, $this->topLevelParent);
- DOMUtil::removeNode($this->topLevelParent);
- DOMUtil::replaceElement($this->link, $metacodeElement, false);
- return;
- }
-
- if ($next !== null) {
- $ancestor = $this->topLevelParent->parentNode;
- \assert($ancestor instanceof \DOMElement);
- $replaceNode = DOMUtil::splitParentsUntil(
- $parent,
- $ancestor,
- false
- );
- }
- if ($previous !== null) {
- $ancestor = $this->topLevelParent->parentNode;
- \assert($ancestor instanceof \DOMElement);
- $replaceNode = DOMUtil::splitParentsUntil(
- $parent,
- $ancestor
- );
- }
- \assert($replaceNode instanceof \DOMElement);
-
- // Remove <br> from start and end of the new block elements
- if ($next !== null) {
- DOMUtil::removeNode($next);
- }
- if ($previous !== null) {
- DOMUtil::removeNode($previous);
- }
- DOMUtil::replaceElement($replaceNode, $metacodeElement, false);
-
+ DOMUtil::replaceElement(
+ HtmlNodePlainLink::splitAtLink($this->link, $this->topLevelParent),
+ $metacodeElement,
+ false
+ );
return;
}
}
$this->pristine = false;
}
- private function findBr(?\DOMNode $node, string $property): ?\DOMNode
+ /**
+ * Split a link within a block element into its own block element.
+ *
+ * @param \DOMElement $link
+ * @param \DOMElement|null $topLevelParent
+ * @return \DOMElement
+ */
+ public static function splitAtLink(\DOMElement $link, ?\DOMElement $topLevelParent = null): \DOMElement
+ {
+ $replaceNode = null;
+ $parent = $link;
+ $next = HtmlNodePlainLink::findBr($link, 'nextSibling');
+ $previous = HtmlNodePlainLink::findBr($link, 'previousSibling');
+
+ // When multiple links are in the same paragraph, `topLevelParent`
+ // may no longer be a valid reference.
+ if ($topLevelParent === null || $topLevelParent->parentNode === null) {
+ $topLevelParent = $link;
+ while ($topLevelParent->parentNode->nodeName !== 'body') {
+ $topLevelParent = $topLevelParent->parentNode;
+ }
+ }
+
+ // Link inside other elements(u, i, b, …)
+ while ($next === null && $previous === null && $parent !== $topLevelParent) {
+ $parent = $parent->parentNode;
+ $next = HtmlNodePlainLink::findBr($parent, 'nextSibling');
+ $previous = HtmlNodePlainLink::findBr($parent, 'previousSibling');
+ }
+
+ // The link is the only content in the top level parent. This
+ // can happen when there are multiple links within one paragraph.
+ if ($next === null && $previous === null) {
+ $topLevelParent->parentNode->insertBefore($link, $topLevelParent);
+ DOMUtil::removeNode($topLevelParent);
+ return $link;
+ }
+
+ if ($next !== null) {
+ $ancestor = $topLevelParent->parentNode;
+ \assert($ancestor instanceof \DOMElement);
+ $replaceNode = DOMUtil::splitParentsUntil(
+ $parent,
+ $ancestor,
+ false
+ );
+ }
+ if ($previous !== null) {
+ $ancestor = $topLevelParent->parentNode;
+ \assert($ancestor instanceof \DOMElement);
+ $replaceNode = DOMUtil::splitParentsUntil(
+ $parent,
+ $ancestor
+ );
+ }
+ \assert($replaceNode instanceof \DOMElement);
+
+ // Remove <br> from start and end of the new block elements
+ if ($next !== null) {
+ DOMUtil::removeNode($next);
+ }
+ if ($previous !== null) {
+ DOMUtil::removeNode($previous);
+ }
+ return $replaceNode;
+ }
+
+ private static function findBr(?\DOMNode $node, string $property): ?\DOMNode
{
if ($node === null) {
return null;
return $node;
}
- return $this->findBr($node->{$property}, $property);
+ return HtmlNodePlainLink::findBr($node->{$property}, $property);
}
}
use wcf\data\unfurl\url\UnfurlUrl;
use wcf\system\html\AbstractHtmlProcessor;
use wcf\system\html\node\AbstractHtmlNodeProcessor;
+use wcf\system\html\node\HtmlNodePlainLink;
use wcf\system\html\node\HtmlNodeUnfurlLink;
use wcf\system\html\output\HtmlOutputProcessor;
use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
'enableUgc' => $enableUgc,
]);
- $parentParagraph = null;
- if ($this->getUnfurlUrl($attribute)->hasFetchedContent() && $element->parentNode->nodeName === 'p') {
- $parentParagraph = $element->parentNode;
- $parentParagraph->parentNode->insertBefore($element, $parentParagraph);
- }
-
- $htmlNodeProcessor->renameTag($element, $tagName);
-
- if ($parentParagraph !== null && !$parentParagraph->hasChildNodes()) {
- /** @var \DOMElement $parentParagraph */
- $parentParagraph->remove();
+ if ($this->getUnfurlUrl($attribute)->isPlainUrl()) {
+ $htmlNodeProcessor->renameTag($element, $tagName);
+ } else {
+ $htmlNodeProcessor->renameTag(HtmlNodePlainLink::splitAtLink($element), $tagName);
}
}
}