xref: /dokuwiki/inc/Parsing/ParserMode/Footnote.php (revision fe58309edafb067d90f3f40ef3d416100d558a04)
1<?php
2
3namespace dokuwiki\Parsing\ParserMode;
4
5use dokuwiki\Parsing\Handler;
6use dokuwiki\Parsing\Handler\Nest;
7use dokuwiki\Parsing\ModeRegistry;
8
9class Footnote extends AbstractMode
10{
11    /** @inheritdoc */
12    protected function allowedCategories(): array
13    {
14        return [
15            ModeRegistry::CATEGORY_CONTAINER,
16            ModeRegistry::CATEGORY_FORMATTING,
17            ModeRegistry::CATEGORY_SUBSTITUTION,
18            ModeRegistry::CATEGORY_PROTECTED,
19            ModeRegistry::CATEGORY_DISABLED,
20        ];
21    }
22
23    /**
24     * Footnotes cannot nest, so footnote is excluded from its own content.
25     *
26     * @inheritdoc
27     */
28    protected function filterAllowedModes(array $modes): array
29    {
30        return array_values(array_filter($modes, static fn($m) => $m !== 'footnote'));
31    }
32
33    /** @inheritdoc */
34    public function getSort()
35    {
36        return 150;
37    }
38
39    /** @inheritdoc */
40    public function connectTo($mode)
41    {
42        $this->Lexer->addEntryPattern('\x28\x28', $mode, 'footnote');
43    }
44
45    /** @inheritdoc */
46    public function postConnect()
47    {
48        $this->Lexer->addExitPattern('\x29\x29', 'footnote');
49        $this->Lexer->addCloserPattern('\x29\x29', 'footnote');
50    }
51
52    /** @inheritdoc */
53    public function handle($match, $state, $pos, Handler $handler)
54    {
55        switch ($state) {
56            case DOKU_LEXER_ENTER:
57                // footnotes can not be nested - however due to limitations in lexer it can't be prevented
58                // we will still enter a new footnote mode, we just do nothing
59                if ($handler->getStatus('footnote')) {
60                    $handler->addCall('cdata', [$match], $pos);
61                    break;
62                }
63                $handler->setStatus('footnote', true);
64
65                $handler->setCallWriter(new Nest($handler->getCallWriter(), 'footnote_close'));
66                $handler->addCall('footnote_open', [], $pos);
67                break;
68            case DOKU_LEXER_EXIT:
69                // check whether we have already exited the footnote mode, can happen if the modes were nested
70                if (!$handler->getStatus('footnote')) {
71                    $handler->addCall('cdata', [$match], $pos);
72                    break;
73                }
74
75                $handler->setStatus('footnote', false);
76                $handler->addCall('footnote_close', [], $pos);
77
78                /** @var Nest $reWriter */
79                $reWriter = $handler->getCallWriter();
80                $handler->setCallWriter($reWriter->process());
81                break;
82            case DOKU_LEXER_UNMATCHED:
83                $handler->addCall('cdata', [$match], $pos);
84                break;
85        }
86        return true;
87    }
88}
89