Fix TOC links that are escaped, also handle uniqueness, fixes #461

This commit is contained in:
Stéphane Goetz 2017-05-18 23:43:02 +02:00
parent 171a8b2baa
commit 885cc1f5ee
2 changed files with 80 additions and 12 deletions

View File

@ -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;
} }
/** /**

View File

@ -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;