Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
declare(strict_types=1);
4
 
5
/*
6
 * This file is part of the league/commonmark package.
7
 *
8
 * (c) Colin O'Dell <colinodell@gmail.com>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
 
14
namespace League\CommonMark\Extension\TableOfContents;
15
 
16
use League\CommonMark\Event\DocumentParsedEvent;
17
use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
18
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalink;
19
use League\CommonMark\Extension\TableOfContents\Node\TableOfContents;
20
use League\CommonMark\Extension\TableOfContents\Node\TableOfContentsPlaceholder;
21
use League\CommonMark\Node\Block\Document;
22
use League\CommonMark\Node\NodeIterator;
23
use League\Config\ConfigurationAwareInterface;
24
use League\Config\ConfigurationInterface;
25
use League\Config\Exception\InvalidConfigurationException;
26
 
27
final class TableOfContentsBuilder implements ConfigurationAwareInterface
28
{
29
    public const POSITION_TOP             = 'top';
30
    public const POSITION_BEFORE_HEADINGS = 'before-headings';
31
    public const POSITION_PLACEHOLDER     = 'placeholder';
32
 
33
    /** @psalm-readonly-allow-private-mutation */
34
    private ConfigurationInterface $config;
35
 
36
    public function onDocumentParsed(DocumentParsedEvent $event): void
37
    {
38
        $document = $event->getDocument();
39
 
40
        $generator = new TableOfContentsGenerator(
41
            (string) $this->config->get('table_of_contents/style'),
42
            (string) $this->config->get('table_of_contents/normalize'),
43
            (int) $this->config->get('table_of_contents/min_heading_level'),
44
            (int) $this->config->get('table_of_contents/max_heading_level'),
45
            (string) $this->config->get('heading_permalink/fragment_prefix'),
46
        );
47
 
48
        $toc = $generator->generate($document);
49
        if ($toc === null) {
50
            // No linkable headers exist, so no TOC could be generated
51
            return;
52
        }
53
 
54
        // Add custom CSS class(es), if defined
55
        $class = $this->config->get('table_of_contents/html_class');
56
        if ($class !== null) {
57
            $toc->data->append('attributes/class', $class);
58
        }
59
 
60
        // Add the TOC to the Document
61
        $position = $this->config->get('table_of_contents/position');
62
        if ($position === self::POSITION_TOP) {
63
            $document->prependChild($toc);
64
        } elseif ($position === self::POSITION_BEFORE_HEADINGS) {
65
            $this->insertBeforeFirstLinkedHeading($document, $toc);
66
        } elseif ($position === self::POSITION_PLACEHOLDER) {
67
            $this->replacePlaceholders($document, $toc);
68
        } else {
69
            throw InvalidConfigurationException::forConfigOption('table_of_contents/position', $position);
70
        }
71
    }
72
 
73
    private function insertBeforeFirstLinkedHeading(Document $document, TableOfContents $toc): void
74
    {
75
        foreach ($document->iterator(NodeIterator::FLAG_BLOCKS_ONLY) as $node) {
76
            if (! $node instanceof Heading) {
77
                continue;
78
            }
79
 
80
            foreach ($node->children() as $child) {
81
                if ($child instanceof HeadingPermalink) {
82
                    $node->insertBefore($toc);
83
 
84
                    return;
85
                }
86
            }
87
        }
88
    }
89
 
90
    private function replacePlaceholders(Document $document, TableOfContents $toc): void
91
    {
92
        foreach ($document->iterator(NodeIterator::FLAG_BLOCKS_ONLY) as $node) {
93
            // Add the block once we find a placeholder
94
            if (! $node instanceof TableOfContentsPlaceholder) {
95
                continue;
96
            }
97
 
98
            $node->replaceWith(clone $toc);
99
        }
100
    }
101
 
102
    public function setConfiguration(ConfigurationInterface $configuration): void
103
    {
104
        $this->config = $configuration;
105
    }
106
}