1<?php 2 3// implementation of 4// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code 5 6// must be run within Dokuwiki 7use ComboStrap\PluginUtility; 8use ComboStrap\Prism; 9use ComboStrap\Tag; 10use ComboStrap\TagAttributes; 11 12require_once(__DIR__ . '/../class/StringUtility.php'); 13require_once(__DIR__ . '/../class/Prism.php'); 14 15if (!defined('DOKU_INC')) die(); 16 17 18class syntax_plugin_combo_code extends DokuWiki_Syntax_Plugin 19{ 20 21 /** 22 * Enable or disable the code component 23 */ 24 const CONF_CODE_ENABLE = 'codeEnable'; 25 26 27 /** 28 * The tag of the ui component 29 */ 30 const CODE_TAG = "code"; 31 const FILE_PATH_KEY = "file-path"; 32 33 34 function getType() 35 { 36 /** 37 * You can't write in a code block 38 */ 39 return 'protected'; 40 } 41 42 /** 43 * How DokuWiki will add P element 44 * 45 * * 'normal' - The plugin can be used inside paragraphs 46 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 47 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 48 * 49 * @see DokuWiki_Syntax_Plugin::getPType() 50 */ 51 function getPType() 52 { 53 return 'block'; 54 } 55 56 /** 57 * @return array 58 * Allow which kind of plugin inside 59 * 60 * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 61 * because we manage self the content and we call self the parser 62 * 63 * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 64 */ 65 function getAllowedTypes() 66 { 67 return array(); 68 } 69 70 function getSort() 71 { 72 /** 73 * Should be less than the code syntax plugin 74 * which is 200 75 **/ 76 return 199; 77 } 78 79 80 function connectTo($mode) 81 { 82 83 if ($this->getConf(self::CONF_CODE_ENABLE)) { 84 $pattern = PluginUtility::getContainerTagPattern(self::CODE_TAG); 85 $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeForComponent($this->getPluginComponent())); 86 } 87 88 89 } 90 91 92 function postConnect() 93 { 94 if ($this->getConf(self::CONF_CODE_ENABLE)) { 95 $this->Lexer->addExitPattern('</' . self::CODE_TAG . '>', PluginUtility::getModeForComponent($this->getPluginComponent())); 96 } 97 98 99 } 100 101 /** 102 * 103 * The handle function goal is to parse the matched syntax through the pattern function 104 * and to return the result for use in the renderer 105 * This result is always cached until the page is modified. 106 * @param string $match 107 * @param int $state 108 * @param int $pos - byte position in the original source file 109 * @param Doku_Handler $handler 110 * @return array|bool 111 * @see DokuWiki_Syntax_Plugin::handle() 112 * 113 */ 114 function handle($match, $state, $pos, Doku_Handler $handler) 115 { 116 117 switch ($state) { 118 119 case DOKU_LEXER_ENTER : 120 $tagAttributes = PluginUtility::getQualifiedTagAttributes($match, true, self::FILE_PATH_KEY); 121 return array( 122 PluginUtility::STATE => $state, 123 PluginUtility::ATTRIBUTES => $tagAttributes 124 ); 125 126 case DOKU_LEXER_UNMATCHED : 127 128 $data = PluginUtility::handleAndReturnUnmatchedData(self::CODE_TAG, $match, $handler); 129 /** 130 * Attribute are send for the 131 * export of code functionality 132 * and display = none 133 */ 134 $tag = new Tag(self::CODE_TAG, array(), $state, $handler); 135 $tagAttributes = $tag->getParent()->getAttributes(); 136 $data[PluginUtility::ATTRIBUTES] = $tagAttributes; 137 return $data; 138 139 140 case DOKU_LEXER_EXIT : 141 /** 142 * Tag Attributes are passed 143 * because it's possible to not display a code with the display attributes = none 144 */ 145 $tag = new Tag(self::CODE_TAG, array(), $state, $handler); 146 $tagAttributes = $tag->getOpeningTag()->getAttributes(); 147 return array( 148 PluginUtility::STATE => $state, 149 PluginUtility::ATTRIBUTES => $tagAttributes 150 ); 151 152 153 } 154 return array(); 155 156 } 157 158 /** 159 * Render the output 160 * @param string $format 161 * @param Doku_Renderer $renderer 162 * @param array $data - what the function handle() return'ed 163 * @return boolean - rendered correctly? (however, returned value is not used at the moment) 164 * @see DokuWiki_Syntax_Plugin::render() 165 * 166 * 167 */ 168 function render($format, Doku_Renderer $renderer, $data) 169 { 170 171 172 if ($format == 'xhtml') { 173 174 /** @var Doku_Renderer_xhtml $renderer */ 175 $state = $data [PluginUtility::STATE]; 176 switch ($state) { 177 case DOKU_LEXER_ENTER : 178 $attributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES], self::CODE_TAG); 179 Prism::htmlEnter($renderer, $this, $attributes); 180 break; 181 182 case DOKU_LEXER_UNMATCHED : 183 184 $attributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]); 185 $display = $attributes->getValue("display"); 186 if ($display != "none") { 187 // Delete the eol at the beginning and end 188 // otherwise we get a big block 189 $payload = trim($data[PluginUtility::PAYLOAD], "\n\r"); 190 $renderer->doc .= PluginUtility::htmlEncode($payload); 191 } 192 break; 193 194 case DOKU_LEXER_EXIT : 195 $attributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]); 196 Prism::htmlExit($renderer, $attributes); 197 break; 198 199 } 200 return true; 201 } else if ($format == 'code') { 202 203 /** 204 * The renderer to download the code 205 * @var Doku_Renderer_code $renderer 206 */ 207 $state = $data [PluginUtility::STATE]; 208 if ($state == DOKU_LEXER_UNMATCHED) { 209 210 $attributes = $data[PluginUtility::ATTRIBUTES]; 211 $text = $data[PluginUtility::PAYLOAD]; 212 $filename = $attributes[self::FILE_PATH_KEY]; 213 $language = strtolower($attributes["type"]); 214 $renderer->code($text, $language, $filename); 215 216 } 217 } 218 219 // unsupported $mode 220 return false; 221 222 } 223 224 225} 226 227