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( 43 '\x28\x28(?=.*\x29\x29)', 44 $mode, 45 'footnote' 46 ); 47 } 48 49 /** @inheritdoc */ 50 public function postConnect() 51 { 52 $this->Lexer->addExitPattern( 53 '\x29\x29', 54 'footnote' 55 ); 56 } 57 58 /** @inheritdoc */ 59 public function handle($match, $state, $pos, Handler $handler) 60 { 61 switch ($state) { 62 case DOKU_LEXER_ENTER: 63 // footnotes can not be nested - however due to limitations in lexer it can't be prevented 64 // we will still enter a new footnote mode, we just do nothing 65 if ($handler->getStatus('footnote')) { 66 $handler->addCall('cdata', [$match], $pos); 67 break; 68 } 69 $handler->setStatus('footnote', true); 70 71 $handler->setCallWriter(new Nest($handler->getCallWriter(), 'footnote_close')); 72 $handler->addCall('footnote_open', [], $pos); 73 break; 74 case DOKU_LEXER_EXIT: 75 // check whether we have already exited the footnote mode, can happen if the modes were nested 76 if (!$handler->getStatus('footnote')) { 77 $handler->addCall('cdata', [$match], $pos); 78 break; 79 } 80 81 $handler->setStatus('footnote', false); 82 $handler->addCall('footnote_close', [], $pos); 83 84 /** @var Nest $reWriter */ 85 $reWriter = $handler->getCallWriter(); 86 $handler->setCallWriter($reWriter->process()); 87 break; 88 case DOKU_LEXER_UNMATCHED: 89 $handler->addCall('cdata', [$match], $pos); 90 break; 91 } 92 return true; 93 } 94} 95