Skip to content
This repository has been archived by the owner on Jan 28, 2022. It is now read-only.

Commit

Permalink
Marks inside Links produce a mess, fix #50 (#51)
Browse files Browse the repository at this point in the history
* add failing test

* improve rendering of nested marks

* refactoring, and add tests for marks inside nodes
  • Loading branch information
hanspagel authored Apr 23, 2021
1 parent 24a6124 commit 52136fb
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 8 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@
"test": "phpunit tests --colors=always --verbose --testdox",
"test-cov": "phpunit tests --colors=always --verbose --testdox --coverage-html tests/Reports"
}
}
}
51 changes: 44 additions & 7 deletions src/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function document($value)
return $this;
}

private function renderNode($node)
private function renderNode($node, $prevNode = null, $nextNode = null)
{
$html = [];

Expand All @@ -74,7 +74,7 @@ private function renderNode($node)
foreach ($this->marks as $class) {
$renderClass = new $class($mark);

if ($renderClass->matching()) {
if ($renderClass->matching() && $this->markShouldOpen($mark, $prevNode)) {
$html[] = $this->renderOpeningTag($renderClass->tag());
}
}
Expand All @@ -91,8 +91,12 @@ private function renderNode($node)
}

if (isset($node->content)) {
foreach ($node->content as $nestedNode) {
$html[] = $this->renderNode($nestedNode);
foreach ($node->content as $index => $nestedNode) {
$prevNestedNode = $node->content[$index - 1] ?? null;
$nextNestedNode = $node->content[$index + 1] ?? null;

$html[] = $this->renderNode($nestedNode, $prevNestedNode, $nextNestedNode);
$prevNode = $nestedNode;
}
} elseif (isset($node->text)) {
$html[] = htmlspecialchars($node->text, ENT_QUOTES, 'UTF-8');
Expand All @@ -117,7 +121,7 @@ private function renderNode($node)
foreach ($this->marks as $class) {
$renderClass = new $class($mark);

if ($renderClass->matching()) {
if ($renderClass->matching() && $this->markShouldClose($mark, $nextNode)) {
$html[] = $this->renderClosingTag($renderClass->tag());
}
}
Expand All @@ -127,6 +131,36 @@ private function renderNode($node)
return join($html);
}

private function markShouldOpen($mark, $prevNode)
{
return $this->nodeHasMark($prevNode, $mark);
}

private function markShouldClose($mark, $nextNode)
{
return $this->nodeHasMark($nextNode, $mark);
}

private function nodeHasMark($node, $mark)
{
if (!$node) {
return true;
}

if (!property_exists($node, 'marks')) {
return true;
}

// Other node has same mark
foreach ($node->marks as $otherMark) {
if ($mark == $otherMark) {
return false;
}
}

return true;
}

private function renderOpeningTag($tags)
{
$tags = (array) $tags;
Expand Down Expand Up @@ -177,8 +211,11 @@ public function render($value)

$content = is_array($this->document->content) ? $this->document->content : [];

foreach ($content as $node) {
$html[] = $this->renderNode($node);
foreach ($content as $index => $node) {
$prevNode = $content[$index - 1] ?? null;
$nextNode = $content[$index + 1] ?? null;

$html[] = $this->renderNode($node, $prevNode, $nextNode);
}

return join($html);
Expand Down
87 changes: 87 additions & 0 deletions tests/Marks/LinkTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,91 @@ public function link_mark_has_support_for_target()

$this->assertEquals($html, (new Renderer)->render($json));
}

/** @test */
public function link_with_marks_generates_clean_output()
{
$json = [
'type' => 'doc',
'content' => [
[
'type' => 'text',
'marks' => [
[
'type' => 'link',
'attrs' => [
'href' => 'https://example.com',
],
],
],
'text' => 'Example ',
],
[
'type' => 'text',
'marks' => [
[
'type' => 'link',
'attrs' => [
'href' => 'https://example.com',
],
],
[
'type' => 'bold',
],
],
'text' => 'Link',
],
],
];

$html = '<a href="https://example.com">Example <strong>Link</strong></a>';

$this->assertEquals($html, (new Renderer)->render($json));
}

/** @test */
public function link_with_marks_inside_node_generates_clean_output()
{
$json = [
'type' => 'doc',
'content' => [
[
'type' => 'paragraph',
'content' => [
[
'type' => 'text',
'marks' => [
[
'type' => 'link',
'attrs' => [
'href' => 'https://example.com',
],
],
],
'text' => 'Example ',
],
[
'type' => 'text',
'marks' => [
[
'type' => 'link',
'attrs' => [
'href' => 'https://example.com',
],
],
[
'type' => 'bold',
],
],
'text' => 'Link',
],
],
],
],
];

$html = '<p><a href="https://example.com">Example <strong>Link</strong></a></p>';

$this->assertEquals($html, (new Renderer)->render($json));
}
}

0 comments on commit 52136fb

Please sign in to comment.