xref: /plugin/combo/ComboStrap/Tag/MermaidTag.php (revision 711d6bd2c63ab43529dc0f6edfa99d8219b82228)
104fd306cSNickeau<?php
204fd306cSNickeau
304fd306cSNickeau
404fd306cSNickeaunamespace ComboStrap\Tag;
504fd306cSNickeau
604fd306cSNickeau
704fd306cSNickeauuse ComboStrap\CallStack;
804fd306cSNickeauuse ComboStrap\ExceptionBadArgument;
904fd306cSNickeauuse ComboStrap\ExceptionBadSyntax;
1004fd306cSNickeauuse ComboStrap\LogUtility;
1104fd306cSNickeauuse ComboStrap\PluginUtility;
1204fd306cSNickeauuse ComboStrap\Web\Sanitizer;
1304fd306cSNickeauuse ComboStrap\TagAttributes;
1404fd306cSNickeau
1504fd306cSNickeauclass MermaidTag
1604fd306cSNickeau{
1704fd306cSNickeau
1804fd306cSNickeau
1904fd306cSNickeau    const CANONICAL = "mermaid";
2004fd306cSNickeau    public const CLASS_NAME = "mermaid";
2104fd306cSNickeau    const LOGICAL_TAG = "mermaid";
2204fd306cSNickeau    public const MARKUP_MERMAID = 'mermaid';
2304fd306cSNickeau    public const MARKUP_SEQUENCE_DIAGRAM = 'sequence-diagram';
2404fd306cSNickeau    const MARKUP_CONTENT_ATTRIBUTE = "mermaid-markup";
2504fd306cSNickeau    const MERMAID_CODE = "mermaid";
2604fd306cSNickeau    public const MARKUP_CLASS_DIAGRAM = 'class-diagram';
2704fd306cSNickeau    public const MARKUP_FLOWCHART = 'flowchart';
2804fd306cSNickeau    public const MARKUP_GANTT = 'gantt';
2904fd306cSNickeau    public const MARKUP_ERD = 'erd';
3004fd306cSNickeau    public const MARKUP_JOURNEY = 'journey';
3104fd306cSNickeau    public const MARKUP_PIECHART = 'piechart';
3204fd306cSNickeau    public const MARKUP_STATE_DIAGRAM = 'state-diagram';
3304fd306cSNickeau
3404fd306cSNickeau    public static function addSnippet()
3504fd306cSNickeau    {
3604fd306cSNickeau        $snippetManager = PluginUtility::getSnippetManager();
3704fd306cSNickeau        $snippetId = self::CANONICAL;
3804fd306cSNickeau        $snippetManager->attachJavascriptFromComponentId($snippetId);
3904fd306cSNickeau        try {
4004fd306cSNickeau            $snippetManager->attachRemoteJavascriptLibrary(
4104fd306cSNickeau                $snippetId,
42*711d6bd2SNicolas GERARD                "https://cdn.jsdelivr.net/npm/mermaid@11.6.0/dist/mermaid.min.js",
43*711d6bd2SNicolas GERARD                "sha256-OpMBanPcgrqJDZGfm7sXbz2p2YNBZQwLUX8llcxo/vg="
4404fd306cSNickeau            );
4504fd306cSNickeau        } catch (ExceptionBadArgument|ExceptionBadSyntax $e) {
4604fd306cSNickeau            LogUtility::internalError("The url should be good", self::CANONICAL,$e);
4704fd306cSNickeau        }
4804fd306cSNickeau    }
4904fd306cSNickeau
5004fd306cSNickeau    /**
5104fd306cSNickeau     * The enter tag
5204fd306cSNickeau     * @param TagAttributes $tagAttributes
5304fd306cSNickeau     * @return string
5404fd306cSNickeau     */
5504fd306cSNickeau    public static function renderEnter(TagAttributes $tagAttributes): string
5604fd306cSNickeau    {
5704fd306cSNickeau
5804fd306cSNickeau        $content = $tagAttributes->getValueAndRemoveIfPresent(self::MARKUP_CONTENT_ATTRIBUTE);
5904fd306cSNickeau
6004fd306cSNickeau        $tagAttributes->addClassName(MermaidTag::CLASS_NAME);
6104fd306cSNickeau        $html = $tagAttributes->toHtmlEnterTag("div");
6204fd306cSNickeau        /**
6304fd306cSNickeau         * The mermaid markup code is replaced at runtime by the diagram
6404fd306cSNickeau         */
6504fd306cSNickeau        MermaidTag::addSnippet();
6604fd306cSNickeau
6704fd306cSNickeau        $html .= MermaidTag::sanitize($content);
6804fd306cSNickeau        $html .= '</div>';
6904fd306cSNickeau        return $html;
7004fd306cSNickeau
7104fd306cSNickeau    }
7204fd306cSNickeau
7304fd306cSNickeau    /**
7404fd306cSNickeau     * The closing tag
7504fd306cSNickeau     *
7604fd306cSNickeau     * @return string
7704fd306cSNickeau     * @deprecated
7804fd306cSNickeau     */
7904fd306cSNickeau    public static function close(): string
8004fd306cSNickeau    {
8104fd306cSNickeau        return "</div>";
8204fd306cSNickeau    }
8304fd306cSNickeau
8404fd306cSNickeau    /**
8504fd306cSNickeau     * The content cannot be HTML escaped
8604fd306cSNickeau     *
8704fd306cSNickeau     * because
8804fd306cSNickeau     * `->>` would become `→&gt;`
8904fd306cSNickeau     * or  <br/> would not work
9004fd306cSNickeau     *
9104fd306cSNickeau     * There is a parameter
9204fd306cSNickeau     * @param $content
9304fd306cSNickeau     * @return mixed
9404fd306cSNickeau     */
9504fd306cSNickeau    public static function sanitize($content)
9604fd306cSNickeau    {
9704fd306cSNickeau
9804fd306cSNickeau        return Sanitizer::sanitize($content, " in a mermaid language", self::CANONICAL);
9904fd306cSNickeau
10004fd306cSNickeau    }
10104fd306cSNickeau
10204fd306cSNickeau
10304fd306cSNickeau    /**
10404fd306cSNickeau     * @param $data
10504fd306cSNickeau     * @param $renderer
10604fd306cSNickeau     * @return void
10704fd306cSNickeau     * @deprecated
10804fd306cSNickeau     */
10904fd306cSNickeau    public static function render($data, &$renderer)
11004fd306cSNickeau    {
11104fd306cSNickeau        $state = $data [PluginUtility::STATE];
11204fd306cSNickeau        switch ($state) {
11304fd306cSNickeau            case DOKU_LEXER_ENTER :
11404fd306cSNickeau                $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]);
11504fd306cSNickeau                $renderer->doc .= MermaidTag::renderEnter($tagAttributes);
11604fd306cSNickeau                break;
11704fd306cSNickeau            case DOKU_LEXER_UNMATCHED :
11804fd306cSNickeau            case DOKU_LEXER_EXIT :
11904fd306cSNickeau                break;
12004fd306cSNickeau
12104fd306cSNickeau        }
12204fd306cSNickeau    }
12304fd306cSNickeau
12404fd306cSNickeau    public static function handleExit($handler){
12504fd306cSNickeau
12604fd306cSNickeau        $callStack = CallStack::createFromHandler($handler);
12704fd306cSNickeau        $openingCall = $callStack->moveToPreviousCorrespondingOpeningCall();
12804fd306cSNickeau        $contentCall = $callStack->next();
12904fd306cSNickeau        $content = $contentCall->getCapturedContent();
13004fd306cSNickeau        $openingCall->setAttribute(self::MARKUP_CONTENT_ATTRIBUTE, $content);
13104fd306cSNickeau        $callStack->deleteAllCallsAfter($openingCall);
13204fd306cSNickeau
13304fd306cSNickeau    }
13404fd306cSNickeau
13504fd306cSNickeau    /**
13604fd306cSNickeau     * @param $state
13704fd306cSNickeau     * @param $match
13804fd306cSNickeau     * @param $handler
13904fd306cSNickeau     * @return array
14004fd306cSNickeau     */
14104fd306cSNickeau    public static function handle($state, $match, &$handler): array
14204fd306cSNickeau    {
14304fd306cSNickeau        switch ($state) {
14404fd306cSNickeau
14504fd306cSNickeau            case DOKU_LEXER_ENTER :
14604fd306cSNickeau                $tagAttributes = TagAttributes::createFromTagMatch($match);
14704fd306cSNickeau                return array(
14804fd306cSNickeau                    PluginUtility::STATE => $state,
14904fd306cSNickeau                    PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray()
15004fd306cSNickeau                );
15104fd306cSNickeau
15204fd306cSNickeau            case DOKU_LEXER_UNMATCHED :
15304fd306cSNickeau
15404fd306cSNickeau                return PluginUtility::handleAndReturnUnmatchedData("", $match, $handler);
15504fd306cSNickeau
15604fd306cSNickeau
15704fd306cSNickeau            case DOKU_LEXER_EXIT :
15804fd306cSNickeau                self::handleExit($handler);
15904fd306cSNickeau                return array(
16004fd306cSNickeau                    PluginUtility::STATE => $state
16104fd306cSNickeau                );
16204fd306cSNickeau
16304fd306cSNickeau
16404fd306cSNickeau        }
16504fd306cSNickeau        return array();
16604fd306cSNickeau    }
16704fd306cSNickeau
16804fd306cSNickeau
16904fd306cSNickeau}
170