1<?php 2 3 4use ComboStrap\CallStack; 5use ComboStrap\HeadingTag; 6use ComboStrap\LogUtility; 7use ComboStrap\PluginUtility; 8use ComboStrap\TagAttributes; 9 10 11if (!defined('DOKU_INC')) die(); 12 13/** 14 * Atx headings 15 * https://github.github.com/gfm/#atx-headings 16 * https://spec.commonmark.org/0.29/#atx-heading 17 * http://www.aaronsw.com/2002/atx/intro 18 */ 19class syntax_plugin_combo_headingatx extends DokuWiki_Syntax_Plugin 20{ 21 22 23 const TAG = "headingatx"; 24 const EXIT_PATTERN = "\r??\n"; 25 26 27 function getType(): string 28 { 29 return 'formatting'; 30 } 31 32 /** 33 * 34 * How Dokuwiki will add P element 35 * 36 * * 'normal' - The plugin can be used inside paragraphs (inline) 37 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 38 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 39 * 40 * @see DokuWiki_Syntax_Plugin::getPType() 41 * 42 */ 43 function getPType(): string 44 { 45 return 'block'; 46 } 47 48 /** 49 * @return array 50 * Allow which kind of plugin inside 51 * 52 * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 53 * because we manage self the content and we call self the parser 54 * 55 * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 56 */ 57 function getAllowedTypes(): array 58 { 59 return array('formatting', 'substition', 'protected', 'disabled'); 60 } 61 62 /** 63 * 64 * @return int 65 */ 66 function getSort(): int 67 { 68 return 49; 69 } 70 71 72 function connectTo($mode) 73 { 74 75 $pattern = '\r??\n\s*#{1,6}\s?(?=.*' . self::EXIT_PATTERN . ')'; 76 $this->Lexer->addSpecialPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 77 78 } 79 80 81 function handle($match, $state, $pos, Doku_Handler $handler): array 82 { 83 84 if ($state == DOKU_LEXER_SPECIAL) { 85 $attributes = [HeadingTag::LEVEL => strlen(trim($match))]; 86 $callStack = CallStack::createFromHandler($handler); 87 88 // Determine the type 89 $context = HeadingTag::getContext($callStack); 90 91 /** 92 * The context is needed: 93 * * to add the bootstrap class if it's a card title for instance 94 * * and to delete {@link HeadingTag::TYPE_OUTLINE} call 95 * in the {@link action_plugin_combo_headingpostprocess} (The rendering is done via Dokuwiki, 96 * see the exit processing for more info on the handling of outline headings) 97 * 98 */ 99 return array( 100 PluginUtility::STATE => $state, 101 PluginUtility::ATTRIBUTES => $attributes, 102 PluginUtility::CONTEXT => $context, 103 PluginUtility::POSITION => $pos 104 ); 105 } 106 return array(); 107 108 } 109 110 /** 111 * Render the output 112 * @param string $format 113 * @param Doku_Renderer $renderer 114 * @param array $data - what the function handle() return'ed 115 * @return boolean - rendered correctly? (however, returned value is not used at the moment) 116 * @see DokuWiki_Syntax_Plugin::render() 117 * 118 * 119 */ 120 function render($format, Doku_Renderer $renderer, $data): bool 121 { 122 123 /** 124 * 125 * The atx special call is transformed by the {@link action_plugin_combo_headingpostprocess} 126 * into enter and exit call 127 */ 128 if ($format == 'xhtml') { 129 130 /** @var Doku_Renderer_xhtml $renderer */ 131 $state = $data[PluginUtility::STATE]; 132 $context = $data[PluginUtility::CONTEXT]; 133 switch ($state) { 134 135 case DOKU_LEXER_ENTER: 136 137 $attributes = $data[PluginUtility::ATTRIBUTES]; 138 139 $tagAttributes = TagAttributes::createFromCallStackArray($attributes, HeadingTag::HEADING_TAG); 140 $pos = $data[PluginUtility::POSITION]; 141 HeadingTag::processRenderEnterXhtml($context, $tagAttributes, $renderer, $pos); 142 return true; 143 144 145 case DOKU_LEXER_EXIT: 146 147 $attributes = $data[PluginUtility::ATTRIBUTES]; 148 $tagAttributes = TagAttributes::createFromCallStackArray($attributes); 149 $renderer->doc .= HeadingTag::renderClosingTag($tagAttributes, $context); 150 return true; 151 152 } 153 } else if ($format == renderer_plugin_combo_analytics::RENDERER_FORMAT) { 154 155 /** 156 * @var renderer_plugin_combo_analytics $renderer 157 */ 158 HeadingTag::processMetadataAnalytics($data, $renderer); 159 160 } else if ($format == "metadata") { 161 162 /** 163 * @var Doku_Renderer_metadata $renderer 164 */ 165 HeadingTag::processHeadingEnterMetadata($data, $renderer); 166 167 } 168 169 return false; 170 } 171 172 173} 174 175