1<?php 2 3 4namespace ComboStrap\Tag; 5 6 7use ComboStrap\CallStack; 8use ComboStrap\ExceptionBadArgument; 9use ComboStrap\ExceptionBadSyntax; 10use ComboStrap\LogUtility; 11use ComboStrap\PluginUtility; 12use ComboStrap\Web\Sanitizer; 13use ComboStrap\TagAttributes; 14 15class MermaidTag 16{ 17 18 19 const CANONICAL = "mermaid"; 20 public const CLASS_NAME = "mermaid"; 21 const LOGICAL_TAG = "mermaid"; 22 public const MARKUP_MERMAID = 'mermaid'; 23 public const MARKUP_SEQUENCE_DIAGRAM = 'sequence-diagram'; 24 const MARKUP_CONTENT_ATTRIBUTE = "mermaid-markup"; 25 const MERMAID_CODE = "mermaid"; 26 public const MARKUP_CLASS_DIAGRAM = 'class-diagram'; 27 public const MARKUP_FLOWCHART = 'flowchart'; 28 public const MARKUP_GANTT = 'gantt'; 29 public const MARKUP_ERD = 'erd'; 30 public const MARKUP_JOURNEY = 'journey'; 31 public const MARKUP_PIECHART = 'piechart'; 32 public const MARKUP_STATE_DIAGRAM = 'state-diagram'; 33 34 public static function addSnippet() 35 { 36 $snippetManager = PluginUtility::getSnippetManager(); 37 $snippetId = self::CANONICAL; 38 $snippetManager->attachJavascriptFromComponentId($snippetId); 39 try { 40 $snippetManager->attachRemoteJavascriptLibrary( 41 $snippetId, 42 "https://cdn.jsdelivr.net/npm/mermaid@10.2.3/dist/mermaid.min.js", 43 "sha256-JFptYy4KzJ5OQP+Q9fubNf3cxpPPmZKqUOovyEONKrQ=" 44 ); 45 } catch (ExceptionBadArgument|ExceptionBadSyntax $e) { 46 LogUtility::internalError("The url should be good", self::CANONICAL,$e); 47 } 48 } 49 50 /** 51 * The enter tag 52 * @param TagAttributes $tagAttributes 53 * @return string 54 */ 55 public static function renderEnter(TagAttributes $tagAttributes): string 56 { 57 58 $content = $tagAttributes->getValueAndRemoveIfPresent(self::MARKUP_CONTENT_ATTRIBUTE); 59 60 $tagAttributes->addClassName(MermaidTag::CLASS_NAME); 61 $html = $tagAttributes->toHtmlEnterTag("div"); 62 /** 63 * The mermaid markup code is replaced at runtime by the diagram 64 */ 65 MermaidTag::addSnippet(); 66 67 $html .= MermaidTag::sanitize($content); 68 $html .= '</div>'; 69 return $html; 70 71 } 72 73 /** 74 * The closing tag 75 * 76 * @return string 77 * @deprecated 78 */ 79 public static function close(): string 80 { 81 return "</div>"; 82 } 83 84 /** 85 * The content cannot be HTML escaped 86 * 87 * because 88 * `->>` would become `→>` 89 * or <br/> would not work 90 * 91 * There is a parameter 92 * @param $content 93 * @return mixed 94 */ 95 public static function sanitize($content) 96 { 97 98 return Sanitizer::sanitize($content, " in a mermaid language", self::CANONICAL); 99 100 } 101 102 103 /** 104 * @param $data 105 * @param $renderer 106 * @return void 107 * @deprecated 108 */ 109 public static function render($data, &$renderer) 110 { 111 $state = $data [PluginUtility::STATE]; 112 switch ($state) { 113 case DOKU_LEXER_ENTER : 114 $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]); 115 $renderer->doc .= MermaidTag::renderEnter($tagAttributes); 116 break; 117 case DOKU_LEXER_UNMATCHED : 118 case DOKU_LEXER_EXIT : 119 break; 120 121 } 122 } 123 124 public static function handleExit($handler){ 125 126 $callStack = CallStack::createFromHandler($handler); 127 $openingCall = $callStack->moveToPreviousCorrespondingOpeningCall(); 128 $contentCall = $callStack->next(); 129 $content = $contentCall->getCapturedContent(); 130 $openingCall->setAttribute(self::MARKUP_CONTENT_ATTRIBUTE, $content); 131 $callStack->deleteAllCallsAfter($openingCall); 132 133 } 134 135 /** 136 * @param $state 137 * @param $match 138 * @param $handler 139 * @return array 140 */ 141 public static function handle($state, $match, &$handler): array 142 { 143 switch ($state) { 144 145 case DOKU_LEXER_ENTER : 146 $tagAttributes = TagAttributes::createFromTagMatch($match); 147 return array( 148 PluginUtility::STATE => $state, 149 PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray() 150 ); 151 152 case DOKU_LEXER_UNMATCHED : 153 154 return PluginUtility::handleAndReturnUnmatchedData("", $match, $handler); 155 156 157 case DOKU_LEXER_EXIT : 158 self::handleExit($handler); 159 return array( 160 PluginUtility::STATE => $state 161 ); 162 163 164 } 165 return array(); 166 } 167 168 169} 170