xref: /dokuwiki/inc/Parsing/ParserMode/Footnote.php (revision 71096e46fcbfaeaa808667aba794e77fe2780169)
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    /**
12     * Footnote constructor.
13     */
14    public function __construct()
15    {
16        $this->allowedModes = ModeRegistry::getInstance()->getModesForCategories([
17            ModeRegistry::CATEGORY_CONTAINER,
18            ModeRegistry::CATEGORY_FORMATTING,
19            ModeRegistry::CATEGORY_SUBSTITION,
20            ModeRegistry::CATEGORY_PROTECTED,
21            ModeRegistry::CATEGORY_DISABLED,
22        ]);
23
24        unset($this->allowedModes[array_search('footnote', $this->allowedModes)]);
25    }
26
27    /** @inheritdoc */
28    public function getSort()
29    {
30        return 150;
31    }
32
33    /** @inheritdoc */
34    public function connectTo($mode)
35    {
36        $this->Lexer->addEntryPattern(
37            '\x28\x28(?=.*\x29\x29)',
38            $mode,
39            'footnote'
40        );
41    }
42
43    /** @inheritdoc */
44    public function postConnect()
45    {
46        $this->Lexer->addExitPattern(
47            '\x29\x29',
48            'footnote'
49        );
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