"sha256-ko4j5rn874LF8dHwW29/xabhh8YBleWfvxb8nQce4Fc=", "coy" => "sha256-0I7KRu3ythnGB35kGsiGUugMkxcKhiBPrucGSiUwMZA=", "dark" => "sha256-8G4aO4AImqFesmM5ePmFnhImR073326PFC3HTanuXoc=", "funky" => "sha256-Aggb3zTcrFLDeGFJwD0w1ZhWfGb747mqtpk364aIwqw=", "okaidia" => "sha256-nwDipdLn93O1CZGoRDor0i4CLmDQb+mdg/yaYMUCuLM=", "solarizedlight" => "sha256-278ChCYdhj8w7EmLSI3+/Z0GIaUwPzWEPIntaHH086I=", "tomorrow" => "sha256-0dkohC9ZEupqWbq0hS5cVR4QQXJ+mp6N2oJyuks6gt0=", "twilight" => "sha256-vF3CcT1ZU/pt1qw8MIUaPvse3WGu7ZarZJHCZqOnQc8=" ]; /** * The theme */ const CONF_PRISM_THEME = "prismTheme"; const PRISM_THEME_DEFAULT = "tomorrow"; const SNIPPET_ID_AUTOLOADER = self::SNIPPET_NAME . "-autoloader"; /** * * @param $theme * * Ter info: The theme of the default wiki is in the print.css file (search for code blocks) */ public static function addSnippet($theme) { $BASE_PRISM_CDN = self::BASE_PRISM_CDN; if ($theme == self::PRISM_THEME) { $themeStyleSheet = "prism.min.css"; } else { $themeStyleSheet = "prism-$theme.min.css"; } $themeIntegrity = self::THEMES_INTEGRITY[$theme]; /** * We miss a bottom margin * as a paragraph */ PluginUtility::getSnippetManager()->attachCssSnippetForBar(self::SNIPPET_NAME); /** * Javascript */ $tags = array(); $tags['script'][] = array( "src" => "$BASE_PRISM_CDN/components/prism-core.min.js", "integrity" => "sha256-vlRYHThwdq55dA+n1BKQRzzLwFtH9VINdSI68+5JhpU=", "crossorigin" => "anonymous" ); $tags['script'][] = array( "src" => "$BASE_PRISM_CDN/plugins/toolbar/prism-toolbar.min.js", "integrity" => "sha256-FyIVdIHL0+ppj4Q4Ft05K3wyCsYikpHIDGI7dcaBalU=", "crossorigin" => "anonymous" ); // https://prismjs.com/plugins/normalize-whitespace/ $tags['script'][] = array( "src" => "$BASE_PRISM_CDN/plugins/normalize-whitespace/prism-normalize-whitespace.min.js", "integrity" => "sha256-gBzABGbXfQYYnyr8xmDFjx6KGO9dBYuypG1QBjO76pY=", "crossorigin" => "anonymous" ); // https://prismjs.com/plugins/show-language/ $tags['script'][] = array( "src" => "$BASE_PRISM_CDN/plugins/show-language/prism-show-language.min.js", "integrity" => "sha256-Z3GTw2RIadLG7KyP/OYB+aAxVYzvg2PByKzYrJlA1EM=", "crossorigin" => "anonymous" ); // https://prismjs.com/plugins/command-line/ $tags['script'][] = array( "src" => "$BASE_PRISM_CDN/plugins/command-line/prism-command-line.min.js", "integrity" => "sha256-9WlakH0Upf3N8DDteHlbeKCHxSsljby+G9ucUCQNiU0=", "crossorigin" => "anonymous" ); //https://prismjs.com/plugins/line-numbers/ $tags['script'][] = array( "src" => "$BASE_PRISM_CDN/plugins/line-numbers/prism-line-numbers.min.js", "integrity" => "sha256-K837BwIyiXo5k/9fCYgqUyA14bN4/Ve9P2SIT0KmZD0=", "crossorigin" => "anonymous" ); // https://prismjs.com/plugins/download-button/--> $tags['script'][] = array( "src" => "$BASE_PRISM_CDN/plugins/download-button/prism-download-button.min.js", "integrity" => "sha256-CQyVQ5ejeTshlzOS/eCiry40br9f4fQ9jb5e4qPl7ZA=", "crossorigin" => "anonymous" ); PluginUtility::getSnippetManager()->upsertTagsForBar(self::SNIPPET_NAME, $tags); $javascriptCode = << { if (typeof self === 'undefined' || !self.Prism || !self.document) { return; } // Loading the css from https://cdnjs.com/libraries/prism const head = document.querySelector('head'); const baseCdn = "$BASE_PRISM_CDN"; const stylesheets = [ ["themes/$themeStyleSheet", "$themeIntegrity"], ["plugins/toolbar/prism-toolbar.css","sha256-kK4/JIYJUKI4Zdg9ZQ7FYyRIqeWPfYKi5QZHO2n/lJI="], /*https://prismjs.com/plugins/command-line/*/ ["plugins/command-line/prism-command-line.css","sha256-UvoA9bIYCYQkCMTYG5p2LM8ZpJmnC4G8k0oIc89nuQA="], /*https://prismjs.com/plugins/line-numbers/*/ ["plugins/line-numbers/prism-line-numbers.css","sha256-ye8BkHf2lHXUtqZ18U0KI3xjJ1Yv7P8lvdKBt9xmVJM="] ]; stylesheets.forEach(stylesheet => { let link = document.createElement('link'); link.rel="stylesheet" link.href=baseCdn+"/"+stylesheet[0]; link.integrity=stylesheet[1]; link.crossOrigin="anonymous"; head.append(link); } ) Prism.plugins.NormalizeWhitespace.setDefaults({ 'remove-trailing': true, 'remove-indent': true, 'left-trim': true, 'right-trim': true, }); if (!Prism.plugins.toolbar) { console.warn('Copy to Clipboard plugin loaded before Toolbar plugin.'); return; } let ClipboardJS = window.ClipboardJS || undefined; if (!ClipboardJS && typeof require === 'function') { ClipboardJS = require('clipboard'); } const callbacks = []; if (!ClipboardJS) { const script = document.createElement('script'); const head = document.querySelector('head'); script.onload = function() { ClipboardJS = window.ClipboardJS; if (ClipboardJS) { while (callbacks.length) { callbacks.pop()(); } } }; script.src = 'https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js'; head.appendChild(script); } Prism.plugins.toolbar.registerButton('copy-to-clipboard', function (env) { var linkCopy = document.createElement('button'); linkCopy.textContent = 'Copy'; linkCopy.setAttribute('type', 'button'); var element = env.element; if (!ClipboardJS) { callbacks.push(registerClipboard); } else { registerClipboard(); } return linkCopy; function registerClipboard() { var clip = new ClipboardJS(linkCopy, { 'text': function () { return element.textContent; } }); clip.on('success', function() { linkCopy.textContent = 'Copied!'; resetText(); }); clip.on('error', function () { linkCopy.textContent = 'Press Ctrl+C to copy'; resetText(); }); } function resetText() { setTimeout(function () { linkCopy.textContent = 'Copy'; }, 5000); } }); }); EOD; PluginUtility::getSnippetManager()->upsertJavascriptForBar(self::SNIPPET_NAME, $javascriptCode); } /** * Add the first block of prism * @param \Doku_Renderer_xhtml $renderer * @param TagAttributes $attributes * @param \DokuWiki_Syntax_Plugin $plugin */ public static function htmlEnter(\Doku_Renderer_xhtml $renderer, \DokuWiki_Syntax_Plugin $plugin, $attributes = null) { if ($attributes == null) { $attributes = TagAttributes::createEmpty(); } /** * Display none, no rendering */ $display = $attributes->getValueAndRemove("display"); if ($display != null) { if ($display == "none") { return; } } /** * Add prism theme */ $theme = $plugin->getConf(Prism::CONF_PRISM_THEME); Prism::addSnippet($theme); /** * Logical tag */ $logicalTag = $plugin->getPluginComponent(); if ($attributes->getLogicalTag() != null) { $logicalTag = $attributes->getLogicalTag(); } // for the https://combostrap.com/styling/userstyle $attributes->setLogicalTag($logicalTag . "-container"); /** * The child element (code) of the `pre` element * The container is the passed `attributes` * We can then constrained in height ... * It contains the language */ $codeAttributes = TagAttributes::createEmpty($logicalTag); $codeAttributes->setType($attributes->getType()); $language = $attributes->getValue(TagAttributes::TYPE_KEY); if ($language == null) { // Prism does not have any default language // There is a bug has it tried to download the txt javascript // but without language, there is no styling $language = "txt"; } else { $language = strtolower($language); Prism::addAutoloaderSnippet(); } if (in_array($language, \syntax_plugin_combo_webcode::MARKIS)) { // Marki is not fully markdown // because it accepts space in super set html container and // prism will highlight them as indented code $language = "html"; } /** * Language name mapping between the dokuwiki default * and prism */ if ($language == "rsplus") { $language = "r"; } if ($language == "dos") { $language = "batch"; } if ($language == "apache") { $language = "apacheconf"; } if ($language == "babel") { $language = "javascript"; } StringUtility::addEolCharacterIfNotPresent($renderer->doc); $codeAttributes->addClassName('language-' . $language); /** * Code element * Don't put a fucking EOL after it * Otherwise it fucked up the output as the text below a code tag is printed */ $codeHtml = $codeAttributes->toHtmlEnterTag('code'); $attributes->addHtmlAfterEnterTag($codeHtml); /** * Pre Element * Line numbers */ if ($attributes->hasComponentAttribute("line-numbers")) { $attributes->removeComponentAttribute("line-numbers"); $attributes->addClassName('line-numbers'); } // Command line if ($attributes->hasComponentAttribute("prompt")) { $attributes->addClassName("command-line"); $attributes->addHtmlAttributeValue("data-prompt", $attributes->getValueAndRemove("prompt")); } else { switch ($language) { case "bash": $attributes->addClassName("command-line"); $attributes->addHtmlAttributeValue("data-prompt", $plugin->getConf(self::CONF_BASH_PROMPT)); break; case "batch": $attributes->addClassName("command-line"); $batch = trim($plugin->getConf(self::CONF_BATCH_PROMPT)); if (!empty($batch)) { if (!strpos($batch, -1) == ">") { $batch .= ">"; } } $attributes->addHtmlAttributeValue("data-prompt", $batch); break; case "powershell": $attributes->addClassName("command-line"); $powerShell = trim($plugin->getConf(self::CONF_POWERSHELL_PROMPT)); if (!empty($powerShell)) { if (!strpos($powerShell, -1) == ">") { $powerShell .= ">"; } } $attributes->addHtmlAttributeValue("data-prompt", $powerShell); break; } } // Download $attributes->addHtmlAttributeValue('data-download-link', true); if ($attributes->hasComponentAttribute(syntax_plugin_combo_code::FILE_PATH_KEY)) { $fileSrc = $attributes->getValueAndRemove(syntax_plugin_combo_code::FILE_PATH_KEY); $attributes->addHtmlAttributeValue('data-src', $fileSrc); $attributes->addHtmlAttributeValue('data-download-link-label', "Download " . $fileSrc); } else { $fileName = "file." . $language; $attributes->addHtmlAttributeValue('data-src', $fileName); } /** * No end of line after the pre, please, otherwise we get a new line * in the code output */ $htmlCode = $attributes->toHtmlEnterTag("pre"); /** * Return */ $renderer->doc .= $htmlCode; } /** * @param Doku_Renderer_xhtml $renderer * @param TagAttributes $attributes */ public static function htmlExit(\Doku_Renderer_xhtml $renderer, $attributes = null) { if ($attributes != null) { /** * Display none, no rendering */ $display = $attributes->getValueAndRemove("display"); if ($display != null) { if ($display == "none") { return; } } } $renderer->doc .= '' . DOKU_LF . '' . DOKU_LF; } /** * The autoloader try to download all language * Even the one such as txt that does not exist * This function was created to add it conditionally */ private static function addAutoloaderSnippet() { $tags = []; $tags['script'][] = array("src" => self::BASE_PRISM_CDN . "/plugins/autoloader/prism-autoloader.min.js"); PluginUtility::getSnippetManager()->upsertTagsForBar(self::SNIPPET_ID_AUTOLOADER, $tags); } }