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