1*531e725cSNickeau<?php 2*531e725cSNickeau 3*531e725cSNickeauuse ComboStrap\CallStack; 4*531e725cSNickeauuse ComboStrap\LogUtility; 5*531e725cSNickeauuse ComboStrap\PluginUtility; 6*531e725cSNickeauuse ComboStrap\TagAttributes; 7*531e725cSNickeau 8*531e725cSNickeau 9*531e725cSNickeau/** 10*531e725cSNickeau * Class headingwiki 11*531e725cSNickeau * Taking over {@link \dokuwiki\Parsing\ParserMode\Header} 12*531e725cSNickeau */ 13*531e725cSNickeauclass syntax_plugin_combo_headingwiki extends DokuWiki_Syntax_Plugin 14*531e725cSNickeau{ 15*531e725cSNickeau 16*531e725cSNickeau /** 17*531e725cSNickeau * Header pattern 18*531e725cSNickeau * * Dokuwiki does not made a space mandatory after and before the opening an closing `=` character 19*531e725cSNickeau * * No line break in the look ahead 20*531e725cSNickeau * * The capture of the first spaces should be optional otherwise the {@link \dokuwiki\Parsing\ParserMode\Header} is taking over 21*531e725cSNickeau * 22*531e725cSNickeau * See also for information, 23*531e725cSNickeau * the original heading pattern of Dokuwiki {@link \dokuwiki\Parsing\ParserMode\Header} 24*531e725cSNickeau */ 25*531e725cSNickeau const ENTRY_PATTERN = '[ \t]*={1,6}(?=[^\n]*={1,6}\s*\r??\n)'; 26*531e725cSNickeau const EXIT_PATTERN = '={1,6}\s*(?=\r??\n)'; 27*531e725cSNickeau const TAG = "headingwiki"; 28*531e725cSNickeau 29*531e725cSNickeau const CONF_WIKI_HEADING_ENABLE = "headingWikiEnable"; 30*531e725cSNickeau const CONF_DEFAULT_WIKI_ENABLE_VALUE = 1; 31*531e725cSNickeau 32*531e725cSNickeau public function getSort() 33*531e725cSNickeau { 34*531e725cSNickeau /** 35*531e725cSNickeau * It's 49 (on less than the original heading) 36*531e725cSNickeau * {@link \dokuwiki\Parsing\ParserMode\Header::getSort()} 37*531e725cSNickeau */ 38*531e725cSNickeau return 49; 39*531e725cSNickeau } 40*531e725cSNickeau 41*531e725cSNickeau public function getType() 42*531e725cSNickeau { 43*531e725cSNickeau return syntax_plugin_combo_heading::SYNTAX_TYPE; 44*531e725cSNickeau } 45*531e725cSNickeau 46*531e725cSNickeau 47*531e725cSNickeau /** 48*531e725cSNickeau * 49*531e725cSNickeau * How Dokuwiki will add P element 50*531e725cSNickeau * 51*531e725cSNickeau * * 'normal' - The plugin can be used inside paragraphs (inline) 52*531e725cSNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 53*531e725cSNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 54*531e725cSNickeau * 55*531e725cSNickeau * @see DokuWiki_Syntax_Plugin::getPType() 56*531e725cSNickeau * 57*531e725cSNickeau * This is the equivalent of inline or block for css 58*531e725cSNickeau */ 59*531e725cSNickeau public function getPType() 60*531e725cSNickeau { 61*531e725cSNickeau return syntax_plugin_combo_heading::SYNTAX_PTYPE; 62*531e725cSNickeau } 63*531e725cSNickeau 64*531e725cSNickeau /** 65*531e725cSNickeau * @return array 66*531e725cSNickeau * Allow which kind of plugin inside 67*531e725cSNickeau * 68*531e725cSNickeau * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 69*531e725cSNickeau * because we manage self the content and we call self the parser 70*531e725cSNickeau * 71*531e725cSNickeau * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 72*531e725cSNickeau */ 73*531e725cSNickeau function getAllowedTypes() 74*531e725cSNickeau { 75*531e725cSNickeau return array('formatting', 'substition', 'protected', 'disabled'); 76*531e725cSNickeau } 77*531e725cSNickeau 78*531e725cSNickeau 79*531e725cSNickeau public function connectTo($mode) 80*531e725cSNickeau { 81*531e725cSNickeau if ($this->enableWikiHeading($mode)) { 82*531e725cSNickeau $this->Lexer->addEntryPattern(self::ENTRY_PATTERN, $mode, PluginUtility::getModeForComponent($this->getPluginComponent())); 83*531e725cSNickeau } 84*531e725cSNickeau } 85*531e725cSNickeau 86*531e725cSNickeau public function postConnect() 87*531e725cSNickeau { 88*531e725cSNickeau 89*531e725cSNickeau $this->Lexer->addExitPattern(self::EXIT_PATTERN, PluginUtility::getModeForComponent($this->getPluginComponent())); 90*531e725cSNickeau 91*531e725cSNickeau } 92*531e725cSNickeau 93*531e725cSNickeau 94*531e725cSNickeau /** 95*531e725cSNickeau * Handle the syntax 96*531e725cSNickeau * 97*531e725cSNickeau * At the end of the parser, the `section_open` and `section_close` calls 98*531e725cSNickeau * are created in {@link action_plugin_combo_headingpostprocessing} 99*531e725cSNickeau * and the text inside for the toc is captured 100*531e725cSNickeau * 101*531e725cSNickeau * @param string $match 102*531e725cSNickeau * @param int $state 103*531e725cSNickeau * @param int $pos 104*531e725cSNickeau * @param Doku_Handler $handler 105*531e725cSNickeau * @return array 106*531e725cSNickeau */ 107*531e725cSNickeau public function handle($match, $state, $pos, Doku_Handler $handler) 108*531e725cSNickeau { 109*531e725cSNickeau switch ($state) { 110*531e725cSNickeau 111*531e725cSNickeau case DOKU_LEXER_ENTER: 112*531e725cSNickeau /** 113*531e725cSNickeau * Title regexp 114*531e725cSNickeau */ 115*531e725cSNickeau $attributes[syntax_plugin_combo_heading::LEVEL] = $this->getLevelFromMatch($match); 116*531e725cSNickeau $callStack = CallStack::createFromHandler($handler); 117*531e725cSNickeau 118*531e725cSNickeau $parentTag = $callStack->moveToParent(); 119*531e725cSNickeau $context = syntax_plugin_combo_heading::getContext($parentTag); 120*531e725cSNickeau 121*531e725cSNickeau return array( 122*531e725cSNickeau PluginUtility::STATE => $state, 123*531e725cSNickeau PluginUtility::ATTRIBUTES => $attributes, 124*531e725cSNickeau PluginUtility::CONTEXT => $context, 125*531e725cSNickeau PluginUtility::POSITION => $pos 126*531e725cSNickeau ); 127*531e725cSNickeau case DOKU_LEXER_UNMATCHED : 128*531e725cSNickeau 129*531e725cSNickeau return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 130*531e725cSNickeau 131*531e725cSNickeau case DOKU_LEXER_EXIT : 132*531e725cSNickeau 133*531e725cSNickeau $callStack = CallStack::createFromHandler($handler); 134*531e725cSNickeau 135*531e725cSNickeau $returnedData = syntax_plugin_combo_heading::handleExit($callStack); 136*531e725cSNickeau 137*531e725cSNickeau 138*531e725cSNickeau /** 139*531e725cSNickeau * Control of the Number of `=` before and after 140*531e725cSNickeau */ 141*531e725cSNickeau $callStack->moveToEnd(); 142*531e725cSNickeau $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall(); 143*531e725cSNickeau $levelFromMatch = $this->getLevelFromMatch($match); 144*531e725cSNickeau $levelFromStartTag = $openingTag->getAttribute(syntax_plugin_combo_heading::LEVEL); 145*531e725cSNickeau if ($levelFromMatch != $levelFromStartTag) { 146*531e725cSNickeau $content = ""; 147*531e725cSNickeau while ($actualCall = $callStack->next()) { 148*531e725cSNickeau $content .= $actualCall->getCapturedContent(); 149*531e725cSNickeau } 150*531e725cSNickeau LogUtility::msg("The number of `=` character for a wiki heading is not the same before ($levelFromStartTag) and after ($levelFromMatch) the content ($content).", LogUtility::LVL_MSG_WARNING, syntax_plugin_combo_heading::CANONICAL); 151*531e725cSNickeau } 152*531e725cSNickeau 153*531e725cSNickeau return $returnedData; 154*531e725cSNickeau 155*531e725cSNickeau } 156*531e725cSNickeau return array(); 157*531e725cSNickeau } 158*531e725cSNickeau 159*531e725cSNickeau public function render($format, Doku_Renderer $renderer, $data) 160*531e725cSNickeau { 161*531e725cSNickeau 162*531e725cSNickeau if ($format == "xhtml") { 163*531e725cSNickeau /** 164*531e725cSNickeau * @var Doku_Renderer_xhtml $renderer 165*531e725cSNickeau */ 166*531e725cSNickeau $state = $data[PluginUtility::STATE]; 167*531e725cSNickeau switch ($state) { 168*531e725cSNickeau 169*531e725cSNickeau case DOKU_LEXER_ENTER: 170*531e725cSNickeau $callStackArray = $data[PluginUtility::ATTRIBUTES]; 171*531e725cSNickeau $tagAttributes = TagAttributes::createFromCallStackArray($callStackArray, syntax_plugin_combo_heading::TAG); 172*531e725cSNickeau $context = $data[PluginUtility::CONTEXT]; 173*531e725cSNickeau $pos = $data[PluginUtility::POSITION]; 174*531e725cSNickeau syntax_plugin_combo_heading::renderOpeningTag($context, $tagAttributes, $renderer, $pos); 175*531e725cSNickeau return true; 176*531e725cSNickeau case DOKU_LEXER_UNMATCHED: 177*531e725cSNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 178*531e725cSNickeau return true; 179*531e725cSNickeau case DOKU_LEXER_EXIT: 180*531e725cSNickeau $callStackArray = $data[PluginUtility::ATTRIBUTES]; 181*531e725cSNickeau $tagAttributes = TagAttributes::createFromCallStackArray($callStackArray); 182*531e725cSNickeau $renderer->doc .= syntax_plugin_combo_heading::renderClosingTag($tagAttributes); 183*531e725cSNickeau return true; 184*531e725cSNickeau 185*531e725cSNickeau } 186*531e725cSNickeau } else if ($format == renderer_plugin_combo_analytics::RENDERER_FORMAT) { 187*531e725cSNickeau 188*531e725cSNickeau /** 189*531e725cSNickeau * @var renderer_plugin_combo_analytics $renderer 190*531e725cSNickeau */ 191*531e725cSNickeau syntax_plugin_combo_heading::processMetadataAnalytics($data, $renderer); 192*531e725cSNickeau 193*531e725cSNickeau } else if ($format == "metadata") { 194*531e725cSNickeau 195*531e725cSNickeau /** 196*531e725cSNickeau * @var Doku_Renderer_metadata $renderer 197*531e725cSNickeau */ 198*531e725cSNickeau syntax_plugin_combo_heading::processHeadingMetadata($data, $renderer); 199*531e725cSNickeau 200*531e725cSNickeau } 201*531e725cSNickeau 202*531e725cSNickeau return false; 203*531e725cSNickeau } 204*531e725cSNickeau 205*531e725cSNickeau /** 206*531e725cSNickeau * @param $match 207*531e725cSNickeau * @return int 208*531e725cSNickeau */ 209*531e725cSNickeau public 210*531e725cSNickeau function getLevelFromMatch($match) 211*531e725cSNickeau { 212*531e725cSNickeau return 7 - strlen(trim($match)); 213*531e725cSNickeau } 214*531e725cSNickeau 215*531e725cSNickeau 216*531e725cSNickeau private 217*531e725cSNickeau function enableWikiHeading($mode) 218*531e725cSNickeau { 219*531e725cSNickeau 220*531e725cSNickeau 221*531e725cSNickeau /** 222*531e725cSNickeau * Basically all mode that are not `base` 223*531e725cSNickeau * To not take the dokuwiki heading 224*531e725cSNickeau */ 225*531e725cSNickeau if (!(in_array($mode, ['base', 'header', 'table']))) { 226*531e725cSNickeau return true; 227*531e725cSNickeau } else { 228*531e725cSNickeau return PluginUtility::getConfValue(self::CONF_WIKI_HEADING_ENABLE, self::CONF_DEFAULT_WIKI_ENABLE_VALUE); 229*531e725cSNickeau } 230*531e725cSNickeau 231*531e725cSNickeau 232*531e725cSNickeau } 233*531e725cSNickeau 234*531e725cSNickeau 235*531e725cSNickeau} 236