1<?php 2 3use ComboStrap\BrandingColors; 4use ComboStrap\ColorRgb; 5use ComboStrap\ColorSystem; 6use ComboStrap\ExceptionCompile; 7use ComboStrap\ExceptionNotFound; 8use ComboStrap\ExecutionContext; 9use ComboStrap\LogUtility; 10use ComboStrap\PluginUtility; 11use ComboStrap\Site; 12use ComboStrap\SiteConfig; 13use ComboStrap\TagAttributes; 14 15 16/** 17 * 18 * Taking over {@link \dokuwiki\Parsing\ParserMode\Formatting monospace} 19 * 20 * Known as code 21 * https://spec.commonmark.org/0.30/#code-spans 22 * 23 * note supported but specific highlight is done with two `==` 24 * in some processor 25 * https://www.markdownguide.org/extended-syntax/#highlight 26 * 27 */ 28class syntax_plugin_combo_highlightwiki extends DokuWiki_Syntax_Plugin 29{ 30 31 32 const TAG = "highlightwiki"; 33 // Only on one line 34 const ENTRY_PATTERN = "\x27\x27(?=[^\n]*\x27\x27)(?!\n)"; 35 36 37 const CONF_HIGHLIGHT_WIKI_ENABLE = "highlightWikiEnable"; 38 const CONF_DEFAULT_HIGHLIGHT_WIKI_ENABLE_VALUE = 1; 39 const EXIT_PATTERN = "\x27\x27"; 40 41 const CANONICAL = self::TAG; 42 43 const HTML_TAG = "mark"; 44 45 public static function getOpenTagHighlight(string $tag): string 46 { 47 $config = ExecutionContext::getActualOrCreateFromEnv()->getConfig(); 48 $htmlTag = self::HTML_TAG; 49 if (!$config->isBrandingColorInheritanceEnabled()) { 50 return "<$htmlTag>"; 51 } 52 try { 53 $primaryColor = $config->getPrimaryColor(); 54 } catch (ExceptionNotFound $e) { 55 return "<$htmlTag>"; 56 } 57 $tagAttributes = TagAttributes::createEmpty($tag); 58 try { 59 $colorRgb = ColorSystem::toBackgroundColor($primaryColor); 60 $tagAttributes->addComponentAttributeValue(ColorRgb::BACKGROUND_COLOR, $colorRgb 61 ->toRgbHex()); 62 } catch (ExceptionCompile $e) { 63 LogUtility::msg("Error on highlight color calculation", self::CANONICAL, $e); 64 } 65 66 return $tagAttributes->toHtmlEnterTag($htmlTag); 67 } 68 69 public function getSort(): int 70 { 71 /** 72 * It's 49 (on less than the original of 100) named monospace 73 * {@link \dokuwiki\Parsing\ParserMode\Formatting} 74 */ 75 return 49; 76 } 77 78 public function getType(): string 79 { 80 return 'formatting'; 81 } 82 83 84 /** 85 * 86 * How Dokuwiki will add P element 87 * 88 * * 'normal' - The plugin can be used inside paragraphs (inline) 89 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 90 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 91 * 92 * @see DokuWiki_Syntax_Plugin::getPType() 93 * 94 * This is the equivalent of inline or block for css 95 */ 96 public function getPType(): string 97 { 98 return 'normal'; 99 } 100 101 /** 102 * @return array 103 * Allow which kind of plugin inside 104 * 105 * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 106 * because we manage self the content and we call self the parser 107 * 108 * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 109 */ 110 function getAllowedTypes(): array 111 { 112 return array('formatting', 'substition', 'protected', 'disabled'); 113 } 114 115 116 public function connectTo($mode) 117 { 118 $enabled = SiteConfig::getConfValue(self::CONF_HIGHLIGHT_WIKI_ENABLE, self::CONF_DEFAULT_HIGHLIGHT_WIKI_ENABLE_VALUE); 119 if ($enabled) { 120 $this->Lexer->addEntryPattern(self::ENTRY_PATTERN, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 121 } 122 123 } 124 125 public function postConnect() 126 { 127 128 $this->Lexer->addExitPattern(self::EXIT_PATTERN, PluginUtility::getModeFromTag($this->getPluginComponent())); 129 130 } 131 132 133 /** 134 * Handle the syntax 135 * 136 * At the end of the parser, the `section_open` and `section_close` calls 137 * are created in {@link action_plugin_combo_instructionspostprocessing} 138 * and the text inside for the toc is captured 139 * 140 * @param string $match 141 * @param int $state 142 * @param int $pos 143 * @param Doku_Handler $handler 144 * @return array 145 */ 146 public function handle($match, $state, $pos, Doku_Handler $handler): array 147 { 148 switch ($state) { 149 150 case DOKU_LEXER_EXIT: 151 case DOKU_LEXER_ENTER: 152 return array( 153 PluginUtility::STATE => $state 154 ); 155 case DOKU_LEXER_UNMATCHED : 156 157 return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 158 159 } 160 return array(); 161 } 162 163 public function render($format, $renderer, $data): bool 164 { 165 166 switch ($format) { 167 case "xhtml": 168 { 169 /** 170 * @var Doku_Renderer_xhtml $renderer 171 */ 172 $state = $data[PluginUtility::STATE]; 173 switch ($state) { 174 175 case DOKU_LEXER_ENTER: 176 $renderer->doc .= self::getOpenTagHighlight(self::TAG); 177 return true; 178 case DOKU_LEXER_UNMATCHED: 179 $renderer->doc .= PluginUtility::renderUnmatched($data); 180 return true; 181 case DOKU_LEXER_EXIT: 182 $htmlTag = self::HTML_TAG; 183 $renderer->doc .= "</$htmlTag>"; 184 return true; 185 186 } 187 break; 188 } 189 case "metadata": 190 /** 191 * @var Doku_Renderer_metadata $renderer 192 */ 193 $state = $data[PluginUtility::STATE]; 194 switch ($state) { 195 case DOKU_LEXER_UNMATCHED: 196 $renderer->doc .= PluginUtility::renderUnmatched($data); 197 } 198 break; 199 } 200 201 return false; 202 } 203 204 205} 206