Fix TOC links that are escaped, also handle uniqueness, fixes #461
This commit is contained in:
parent
171a8b2baa
commit
885cc1f5ee
@ -42,6 +42,7 @@ class Processor implements DocumentProcessorInterface
|
|||||||
|
|
||||||
$headings = [];
|
$headings = [];
|
||||||
|
|
||||||
|
$document->heading_ids = [];
|
||||||
$walker = $document->walker();
|
$walker = $document->walker();
|
||||||
while ($event = $walker->next()) {
|
while ($event = $walker->next()) {
|
||||||
$node = $event->getNode();
|
$node = $event->getNode();
|
||||||
@ -55,7 +56,7 @@ class Processor implements DocumentProcessorInterface
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->ensureHeadingHasId($node);
|
$this->ensureHeadingHasId($document, $node);
|
||||||
$headings[] = new Entry($node);
|
$headings[] = new Entry($node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,21 +73,49 @@ class Processor implements DocumentProcessorInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function escaped($url) {
|
||||||
|
$url = trim($url);
|
||||||
|
$url = preg_replace('~[^\\pL0-9_]+~u', '-', $url);
|
||||||
|
$url = trim($url, "-");
|
||||||
|
$url = iconv("utf-8", "us-ascii//TRANSLIT", $url);
|
||||||
|
$url = preg_replace('~[^-a-zA-Z0-9_]+~', '', $url);
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getUniqueId(Document $document, $proposed) {
|
||||||
|
if ($proposed == "page_") {
|
||||||
|
$proposed = "page_section_" . (count($document->heading_ids) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick path, it's a unique ID
|
||||||
|
if (!in_array($proposed, $document->heading_ids)) {
|
||||||
|
$document->heading_ids[] = $proposed;
|
||||||
|
return $proposed;
|
||||||
|
}
|
||||||
|
|
||||||
|
$extension = 1; // Initialize the variable at one, so on the first iteration we have 2
|
||||||
|
do {
|
||||||
|
$extension++;
|
||||||
|
} while (in_array("$proposed-$extension", $document->heading_ids));
|
||||||
|
|
||||||
|
return "$proposed-$extension";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Heading $node
|
* @param Heading $node
|
||||||
*/
|
*/
|
||||||
protected function ensureHeadingHasId(Heading $node)
|
protected function ensureHeadingHasId(Document $document, Heading $node)
|
||||||
{
|
{
|
||||||
// If the node has an ID, no need to generate it
|
// If the node has an ID, no need to generate it, just check it's unique
|
||||||
$attributes = $node->getData('attributes', []);
|
$attributes = $node->getData('attributes', []);
|
||||||
if (array_key_exists('id', $attributes) && !empty($attributes['id'])) {
|
if (array_key_exists('id', $attributes) && !empty($attributes['id'])) {
|
||||||
// TODO :: check for uniqueness
|
$node->data['attributes']['id'] = $this->getUniqueId($document, $attributes['id']);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Well, seems we have to generate an ID
|
// Well, seems we have to generate an ID
|
||||||
|
|
||||||
$walker = $node->walker();
|
$walker = $node->walker();
|
||||||
$inside = [];
|
$inside = [];
|
||||||
while ($event = $walker->next()) {
|
while ($event = $walker->next()) {
|
||||||
@ -106,10 +135,7 @@ class Processor implements DocumentProcessorInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$text = 'page_' . urlencode(trim($text));
|
$node->data['attributes']['id'] = $this->getUniqueId($document,'page_'. $this->escaped($text));
|
||||||
|
|
||||||
// TODO :: check for uniqueness
|
|
||||||
$node->data['attributes']['id'] = $text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,14 +31,56 @@ EXPECTED;
|
|||||||
function testUnicodeTOC() {
|
function testUnicodeTOC() {
|
||||||
$converter = new CommonMarkConverter(['daux' => new MainConfig]);
|
$converter = new CommonMarkConverter(['daux' => new MainConfig]);
|
||||||
|
|
||||||
$source = "[TOC]\n# 基础操作";
|
$source = "[TOC]\n# 基础操作\n# 操作基础";
|
||||||
$expected = <<<EXPECTED
|
$expected = <<<EXPECTED
|
||||||
<ul class="TableOfContents">
|
<ul class="TableOfContents">
|
||||||
<li>
|
<li>
|
||||||
<p><a href="#page_%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C">基础操作</a></p>
|
<p><a href="#page_section_1">基础操作</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#page_section_2">操作基础</a></p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h1 id="page_%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C">基础操作</h1>
|
<h1 id="page_section_1">基础操作</h1>
|
||||||
|
<h1 id="page_section_2">操作基础</h1>
|
||||||
|
|
||||||
|
EXPECTED;
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $converter->convertToHtml($source));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testDuplicatedTOC() {
|
||||||
|
$converter = new CommonMarkConverter(['daux' => new MainConfig]);
|
||||||
|
|
||||||
|
$source = "[TOC]\n# Test\n# Test";
|
||||||
|
$expected = <<<EXPECTED
|
||||||
|
<ul class="TableOfContents">
|
||||||
|
<li>
|
||||||
|
<p><a href="#page_Test">Test</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#page_Test-2">Test</a></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h1 id="page_Test">Test</h1>
|
||||||
|
<h1 id="page_Test-2">Test</h1>
|
||||||
|
|
||||||
|
EXPECTED;
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $converter->convertToHtml($source));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testEscapedTOC() {
|
||||||
|
$converter = new CommonMarkConverter(['daux' => new MainConfig]);
|
||||||
|
|
||||||
|
$source = "[TOC]\n# TEST : Test";
|
||||||
|
$expected = <<<EXPECTED
|
||||||
|
<ul class="TableOfContents">
|
||||||
|
<li>
|
||||||
|
<p><a href="#page_TEST-Test">TEST : Test</a></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h1 id="page_TEST-Test">TEST : Test</h1>
|
||||||
|
|
||||||
EXPECTED;
|
EXPECTED;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user