UNPKG

mume-with-litvis

Version:

Fork of mume with added http://litvis.org/

969 lines 104 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MarkdownEngine = void 0; // tslint:disable no-var-requires member-ordering const block_attributes_1 = require("block-attributes"); const block_info_1 = require("block-info"); const cheerio = require("cheerio"); const child_process_1 = require("child_process"); const fs = require("fs"); const litvis_integration_mume_1 = require("litvis-integration-mume"); const path = require("path"); const request = require("request"); const slash = require("slash"); const toVFile = require("to-vfile"); const YAML = require("yamljs"); const admonition_1 = require("./custom-markdown-it-features/admonition"); const code_fences_1 = require("./custom-markdown-it-features/code-fences"); const critic_markup_1 = require("./custom-markdown-it-features/critic-markup"); const emoji_1 = require("./custom-markdown-it-features/emoji"); const html5_embed_1 = require("./custom-markdown-it-features/html5-embed"); const math_1 = require("./custom-markdown-it-features/math"); const wikilink_1 = require("./custom-markdown-it-features/wikilink"); const ebook_convert_1 = require("./ebook-convert"); const heading_id_generator_1 = require("./heading-id-generator"); const markdown_convert_1 = require("./markdown-convert"); const markdown_engine_config_1 = require("./markdown-engine-config"); const pandoc_convert_1 = require("./pandoc-convert"); const prince_convert_1 = require("./prince-convert"); const code_block_styling_1 = require("./render-enhancers/code-block-styling"); const embedded_local_images_1 = require("./render-enhancers/embedded-local-images"); const embedded_svgs_1 = require("./render-enhancers/embedded-svgs"); // import enhanceWithEmojiToSvg from "./render-enhancers/emoji-to-svg"; const extended_table_syntax_1 = require("./render-enhancers/extended-table-syntax"); const fenced_code_chunks_1 = require("./render-enhancers/fenced-code-chunks"); const fenced_diagrams_1 = require("./render-enhancers/fenced-diagrams"); const fenced_math_1 = require("./render-enhancers/fenced-math"); const resolved_image_paths_1 = require("./render-enhancers/resolved-image-paths"); const toc_1 = require("./toc"); const transformer_1 = require("./transformer"); const utility = require("./utility"); const utility_1 = require("./utility"); const extensionDirectoryPath = utility.extensionDirectoryPath; const MarkdownIt = require(path.resolve(extensionDirectoryPath, "./dependencies/markdown-it/markdown-it.min.js")); const CryptoJS = require(path.resolve(extensionDirectoryPath, "./dependencies/crypto-js/crypto-js.js")); const defaults = { html: true, xhtmlOut: false, breaks: true, langPrefix: "language-", linkify: true, linkTarget: "", typographer: true, // Enable smartypants and other sweet transforms }; let MODIFY_SOURCE = null; const dependentLibraryConfigs = [ { libraryName: "vega", libraryVersion: "5", buildPathForWebview: "build/vega.min.js", }, { libraryName: "vega-lite", libraryVersion: "5", buildPathForWebview: "build/vega-lite.min.js", }, { libraryName: "vega-embed", libraryVersion: "6", buildPathForWebview: "build/vega-embed.min.js", }, { libraryName: "apache-arrow", libraryVersion: "4", buildPathForWebview: "Arrow.es2015.min.js", }, { libraryName: "vega-loader-arrow", libraryVersion: "0.0", buildPathForWebview: "build/vega-loader-arrow.min.js", }, ]; let UPDATE_LINTING_REPORT = null; /** * The markdown engine that can be used to parse markdown and export files */ class MarkdownEngine { /** * Modify markdown source, append `result` after corresponding code chunk. * @param codeChunkData * @param result */ static modifySource(codeChunkData, result, filePath) { return __awaiter(this, void 0, void 0, function* () { if (MODIFY_SOURCE) { yield MODIFY_SOURCE(codeChunkData, result, filePath); } else { // TODO: directly modify the local file. } codeChunkData.running = false; return result; }); } /** * Bind cb to MODIFY_SOURCE * @param cb */ static onModifySource(cb) { MODIFY_SOURCE = cb; } static updateLintingReport(vFiles) { return __awaiter(this, void 0, void 0, function* () { if (UPDATE_LINTING_REPORT) { yield UPDATE_LINTING_REPORT(vFiles); } }); } static onUpdateLintingReport(cb) { UPDATE_LINTING_REPORT = cb; } constructor(args) { // caches this.graphsCache = {}; // code chunks this.codeChunksData = {}; // files cache this.filesCache = {}; /** * cachedHTML is the cache of html generated from the markdown file. */ // private cachedHTML:string = ''; /** * Check whether the preview is in presentation mode. */ this.isPreviewInPresentationMode = false; this.filePath = args.filePath; this.fileDirectoryPath = path.dirname(this.filePath); this.projectDirectoryPath = args.projectDirectoryPath || this.fileDirectoryPath; this.originalConfig = args.config; this.resetConfig(); this.headings = []; this.tocHTML = ""; this.md = new MarkdownIt(Object.assign(Object.assign({}, defaults), { typographer: this.enableTypographer, breaks: this.breakOnSingleNewLine, linkify: this.enableLinkify })); // markdown-it extensions const extensions = [ "./dependencies/markdown-it/extensions/markdown-it-footnote.min.js", "./dependencies/markdown-it/extensions/markdown-it-sub.min.js", "./dependencies/markdown-it/extensions/markdown-it-sup.min.js", "./dependencies/markdown-it/extensions/markdown-it-deflist.min.js", "./dependencies/markdown-it/extensions/markdown-it-abbr.min.js", "./dependencies/markdown-it/extensions/markdown-it-mark.min.js", ]; for (const js of extensions) { const fullPath = path.resolve(extensionDirectoryPath, js); const plugin = require(fullPath); this.md.use(plugin); } (0, code_fences_1.default)(this.md, this.config); (0, critic_markup_1.default)(this.md, this.config); (0, emoji_1.default)(this.md, this.config); (0, litvis_integration_mume_1.useMarkdownItLitvisFeatures)(this.md, this.config); (0, html5_embed_1.default)(this.md, this.config); (0, math_1.default)(this.md, this.config); (0, wikilink_1.default)(this.md, this.config); (0, admonition_1.default)(this.md); this.clearCaches(); } /** * Reset config */ resetConfig() { // Please notice that ~/.config/mume/config.json has the highest priority. this.config = Object.assign(Object.assign(Object.assign({}, markdown_engine_config_1.defaultMarkdownEngineConfig), (this.originalConfig || {})), (utility.configs.config || {})); this.initConfig(); } /** * Set default values */ initConfig() { this.interpolateConfig(this.config, this.projectDirectoryPath); // break on single newline this.breakOnSingleNewLine = this.config.breakOnSingleNewLine; // enable typographer this.enableTypographer = this.config.enableTypographer; // enable linkify this.enableLinkify = this.config.enableLinkify; // protocal whitelist const protocolsWhiteList = (this.config.protocolsWhiteList || markdown_engine_config_1.defaultMarkdownEngineConfig.protocolsWhiteList) .split(",") .map((x) => x.trim()); this.protocolsWhiteListRegExp = new RegExp("^(" + protocolsWhiteList.join("|") + ")"); // eg /^(http:\/\/|https:\/\/|atom:\/\/|file:\/\/|mailto:|tel:)/ } interpolateConfig(config, projectDirectoryPath) { var _a, _b, _c, _d; const pattern = /\${\s*(\w+?)\s*}/g; // Replace ${property} const replacements = { projectDir: projectDirectoryPath, workspaceFolder: projectDirectoryPath, // vscode abreviation }; // Replace certains paths config.configPath = (_a = config.configPath) === null || _a === void 0 ? void 0 : _a.replace(pattern, (match, token) => replacements[token] || match); config.imageFolderPath = (_b = config.imageFolderPath) === null || _b === void 0 ? void 0 : _b.replace(pattern, (match, token) => replacements[token] || match); config.imageMagickPath = (_c = config.imageMagickPath) === null || _c === void 0 ? void 0 : _c.replace(pattern, (match, token) => replacements[token] || match); config.chromePath = (_d = config.chromePath) === null || _d === void 0 ? void 0 : _d.replace(pattern, (match, token) => replacements[token] || match); } updateConfiguration(config) { this.config = Object.assign(Object.assign({}, this.config), config); this.initConfig(); this.md.set({ breaks: this.breakOnSingleNewLine, typographer: this.enableTypographer, linkify: this.enableLinkify, }); } /* public cacheSVG(code:string, svg:string) { svg = CryptoJS.AES.decrypt(svg, 'markdown-preview-enhanced').toString(CryptoJS.enc.Utf8) // const base64 = new Buffer(svg).toString('base64') // const img = `<img src="data:image/svg+xml;charset=utf-8;base64,${base64}">` this.graphsCache[md5(code)] = svg } */ cacheCodeChunkResult(id, result) { const codeChunkData = this.codeChunksData[id]; if (!codeChunkData) { return; } codeChunkData.result = CryptoJS.AES.decrypt(result, "mume").toString(CryptoJS.enc.Utf8); } /** * Generate scripts string for preview usage. */ generateScriptsForPreview(isForPresentation = false, yamlConfig = {}, vscodePreviewPanel = null) { let scripts = ""; // prevent `id="exports"` element from linked to `window` object. scripts += `<script>var exports = undefined</script>`; // jquery scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/jquery/jquery.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; // jquery contextmenu scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/jquery-contextmenu/jquery.ui.position.min.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/jquery-contextmenu/jquery.contextMenu.min.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; // jquery modal scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/jquery-modal/jquery.modal.min.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; // crpto-js scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/crypto-js/crypto-js.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; // mermaid scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, `./dependencies/mermaid/mermaid.min.js`), vscodePreviewPanel)}" charset="UTF-8"></script>`; // zenuml scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/sequence-diagram/vue.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/sequence-diagram/sequence-diagram.min.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; // wavedrome scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/wavedrom/default.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; scripts += `<script type="text/javascript" src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/wavedrom/wavedrom.min.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; // math if (this.config.mathRenderingOption === "MathJax" || this.config.usePandocParser) { const mathJaxConfig = utility.configs.mathjaxConfig; mathJaxConfig["tex2jax"] = mathJaxConfig["tex2jax"] || {}; mathJaxConfig["tex2jax"]["inlineMath"] = this.config.mathInlineDelimiters; mathJaxConfig["tex2jax"]["displayMath"] = this.config.mathBlockDelimiters; mathJaxConfig["HTML-CSS"]["imageFont"] = null; // Disable image font, otherwise the preview will only display black color image. mathJaxConfig["root"] = utility.addFileProtocol(slash(path.resolve(utility.extensionDirectoryPath, "./dependencies/mathjax")), vscodePreviewPanel); scripts += `<script type="text/javascript" async src="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/mathjax/MathJax.js"), vscodePreviewPanel)}" charset="UTF-8"></script>`; scripts += `<script type="text/x-mathjax-config"> MathJax.Hub.Config(${JSON.stringify(mathJaxConfig)}); </script>`; } // reveal.js if (isForPresentation) { scripts += `<script src='${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/reveal/lib/js/head.min.js"), vscodePreviewPanel)}'></script>`; scripts += `<script src='${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/reveal/js/reveal.js"), vscodePreviewPanel)}'></script>`; let presentationConfig = yamlConfig["presentation"] || {}; if (typeof presentationConfig !== "object") { presentationConfig = {}; } let dependencies = presentationConfig["dependencies"] || []; if (!(dependencies instanceof Array)) { dependencies = []; } presentationConfig["dependencies"] = dependencies; scripts += ` <script> Reveal.initialize(${JSON.stringify(Object.assign({ margin: 0.1 }, presentationConfig))}) </script> `; } // mermaid init scripts += `<script> ${utility.configs.mermaidConfig} if (window['MERMAID_CONFIG']) { window['MERMAID_CONFIG'].startOnLoad = false window['MERMAID_CONFIG'].cloneCssStyles = false window['MERMAID_CONFIG'].theme = "${this.config.mermaidTheme}" } mermaid.initialize(window['MERMAID_CONFIG'] || {}) if (typeof(window['Reveal']) !== 'undefined') { function mermaidRevealHelper(event) { var currentSlide = event.currentSlide var diagrams = currentSlide.querySelectorAll('.mermaid') for (var i = 0; i < diagrams.length; i++) { var diagram = diagrams[i] if (!diagram.hasAttribute('data-processed')) { mermaid.init(null, diagram, ()=> { Reveal.slide(event.indexh, event.indexv) }) } } } Reveal.addEventListener('slidechanged', mermaidRevealHelper) Reveal.addEventListener('ready', mermaidRevealHelper) } else { // The line below will cause mermaid bug in preview. // mermaid.init(null, document.querySelectorAll('.mermaid')) } </script>`; // wavedrom init script if (isForPresentation) { scripts += `<script> WaveDrom.ProcessAll() </script>`; } // flowchart.js scripts += `<script src='${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/raphael/raphael.js"), vscodePreviewPanel)}'></script>`; scripts += `<script src='${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/flowchart/flowchart.min.js"), vscodePreviewPanel)}'></script>`; // flowchart init script if (isForPresentation) { scripts += `<script> var flowcharts = document.getElementsByClassName('flow') for (var i = 0; i < flowcharts.length; i++) { var flow = flowcharts[i] try { var diagram = flowchart.parse(flow.textContent) flow.id = 'flow_' + i flow.innerHTML = '' diagram.drawSVG(flow.id) } catch (error) { flow.innerHTML = '<pre class="language-text">' + error.toString() + '</pre>' } } </script>`; } dependentLibraryConfigs.forEach(({ libraryName, buildPathForWebview }) => { scripts += `<script src="${utility.addFileProtocol(utility.resolveBuildPathForWebview(libraryName, buildPathForWebview), vscodePreviewPanel)}" charset="UTF-8"></script>`; }); if (isForPresentation) { scripts += `<script> var vegaEls = document.querySelectorAll('.vega, .vega-lite'); function reportVegaError(el, error) { el.innerHTML = '<pre class="language-text">' + error.toString() + '</pre>' } for (var i = 0; i < vegaEls.length; i++) { const vegaEl = vegaEls[i] try { var spec = JSON.parse(vegaEl.textContent); vegaEmbed(vegaEl, spec, { actions: false, renderer: 'svg' }) .catch(function(error) { reportVegaError(vegaEl, error); }) } catch (error) { reportVegaError(vegaEl, error); } } </script>`; } // sequence diagram scripts += `<script src='${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/webfont/webfontloader.js"), vscodePreviewPanel)}'></script>`; scripts += `<script src='${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/underscore/underscore.js"), vscodePreviewPanel)}'></script>`; scripts += `<script src='${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/js-sequence-diagrams/sequence-diagram-min.js"), vscodePreviewPanel)}'></script>`; // sequence diagram init script if (isForPresentation) { scripts += `<script> var sequenceDiagrams = document.getElementsByClassName('sequence') for (var i = 0; i < sequenceDiagrams.length; i++) { var sequence = sequenceDiagrams[i] try { var diagram = Diagram.parse(sequence.textContent) var theme = sequence.getAttribute('theme') || 'simple' sequence.id = 'sequence_' + i sequence.innerHTML = '' diagram.drawSVG(sequence.id, {theme: theme}) } catch (error) { sequence.innerHTML = '<pre class="language-text">' + error.toString() + '</pre>' } } </script>`; } return scripts; } /** * Automatically pick code block theme for preview. */ getPrismTheme(isPresentationMode = false, yamlConfig = {}) { if (this.config.codeBlockTheme === "auto.css") { /** * Automatically pick code block theme for preview. */ if (isPresentationMode) { const presentationTheme = yamlConfig["presentation"] && typeof yamlConfig["presentation"] === "object" && yamlConfig["presentation"]["theme"] ? yamlConfig["presentation"]["theme"] : this.config.revealjsTheme; return (MarkdownEngine.AutoPrismThemeMapForPresentation[presentationTheme] || "default.css"); } else { return (MarkdownEngine.AutoPrismThemeMap[this.config.previewTheme] || "default.css"); } } else { return this.config.codeBlockTheme; } } /** * Generate styles string for preview usage. */ generateStylesForPreview(isPresentationMode = false, yamlConfig = {}, vscodePreviewPanel = null) { let styles = ""; // loading.css styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./styles/loading.css"), vscodePreviewPanel)}">`; // jquery-contextmenu styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, `./dependencies/jquery-contextmenu/jquery.contextMenu.min.css`), vscodePreviewPanel)}">`; // jquery-modal styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, `./dependencies/jquery-modal/jquery.modal.min.css`), vscodePreviewPanel)}">`; // check math if (this.config.mathRenderingOption === "KaTeX" && !this.config.usePandocParser) { styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./dependencies/katex/katex.min.css"), vscodePreviewPanel)}">`; } // check sequence diagram styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, `./dependencies/js-sequence-diagrams/sequence-diagram-min.css`), vscodePreviewPanel)}">`; // check font-awesome styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, `./dependencies/font-awesome/css/font-awesome.min.css`), vscodePreviewPanel)}">`; // check preview theme and revealjs theme if (!isPresentationMode) { styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, `./styles/preview_theme/${this.config.previewTheme}`), vscodePreviewPanel)}">`; } else { styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(extensionDirectoryPath, "./dependencies/reveal/css/reveal.css"), vscodePreviewPanel)}" >`; styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(extensionDirectoryPath, `./dependencies/reveal/css/theme/${yamlConfig["presentation"] && typeof yamlConfig["presentation"] === "object" && yamlConfig["presentation"]["theme"] ? yamlConfig["presentation"]["theme"] : this.config.revealjsTheme}`), vscodePreviewPanel)}" >`; } // check prism styles += `<link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, `./styles/prism_theme/${this.getPrismTheme(isPresentationMode, yamlConfig)}`), vscodePreviewPanel)}">`; // style template styles += `<link rel="stylesheet" media="screen" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./styles/style-template.css"), vscodePreviewPanel)}">`; // style markdown-it-admonition styles += `<link rel="stylesheet" media="screen" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./styles/markdown-it-admonition.css"), vscodePreviewPanel)}">`; // global styles styles += `<style>${utility.configs.globalStyle}</style>`; return styles; } /** * Generate <style> and <link> string from an array of file paths. * @param JSAndCssFiles */ generateJSAndCssFilesForPreview(JSAndCssFiles = [], vscodePreviewPanel = null) { let output = ""; JSAndCssFiles.forEach((sourcePath) => { let absoluteFilePath = sourcePath; if (sourcePath[0] === "/") { absoluteFilePath = utility.addFileProtocol(path.resolve(this.projectDirectoryPath, "." + sourcePath), vscodePreviewPanel); } else if (sourcePath.match(/^file:\/\//) || sourcePath.match(/^https?\:\/\//)) { // do nothing } else { absoluteFilePath = utility.addFileProtocol(path.resolve(this.fileDirectoryPath, sourcePath), vscodePreviewPanel); } if (absoluteFilePath.endsWith(".js")) { output += `<script type="text/javascript" src="${absoluteFilePath}"></script>`; } else { // css output += `<link rel="stylesheet" href="${absoluteFilePath}">`; } }); return output; } /** * Generate html template for preview. */ generateHTMLTemplateForPreview({ inputString = "", body = "", webviewScript = "", scripts = "", styles = "", head = `<base href="${this.filePath}">`, config = {}, vscodePreviewPanel = null, contentSecurityPolicy = "", }) { return __awaiter(this, void 0, void 0, function* () { if (!inputString) { inputString = fs.readFileSync(this.filePath, { encoding: "utf-8" }); } if (!webviewScript) { webviewScript = utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./out/src/webview.js"), vscodePreviewPanel); } if (!body) { // default body body = ` <div class="refreshing-icon"></div> <div id="md-toolbar"> <div class="back-to-top-btn btn"><span>⬆︎</span></div> <div class="refresh-btn btn"><span>⟳︎</span></div> <div class="sidebar-toc-btn btn"><span>§</span></div> </div> <div id="image-helper-view"> <h4>Image Helper</h4> <div class="upload-div"> <label>Link</label> <input type="text" class="url-editor" placeholder="enter image URL here, then press \'Enter\' to insert."> <div class="splitter"></div> <label class="copy-label">Copy image to root /assets folder</label> <div class="drop-area paster"> <p class="paster"> Click me to browse image file </p> <input class="file-uploader paster" type="file" style="display:none;" multiple="multiple" > </div> <div class="splitter"></div> <label>Upload</label> <div class="drop-area uploader"> <p class="uploader">Click me to browse image file</p> <input class="file-uploader uploader" type="file" style="display:none;" multiple="multiple" > </div> <div class="uploader-choice"> <span>use</span> <select class="uploader-select"> <option>imgur</option> <option>sm.ms</option> <option>qiniu</option> </select> <span> to upload images</span> </div> <a href="#" id="show-uploaded-image-history">Show history</a> </div> </div> <!-- <div class="markdown-spinner"> Loading Markdown\u2026 </div> --> `; } const { yamlConfig, JSAndCssFiles, html } = yield this.parseMD(inputString, { isForPreview: true, useRelativeFilePath: false, hideFrontMatter: false, vscodePreviewPanel, }); const isPresentationMode = yamlConfig["isPresentationMode"]; const htmlTemplate = `<!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> <meta id="mume-data" data-config="${utility.escapeString(JSON.stringify(Object.assign(Object.assign({}, this.config), config)))}" data-time="${Date.now()}"> <meta charset="UTF-8"> ${contentSecurityPolicy ? `<meta http-equiv="Content-Security-Policy" content="${contentSecurityPolicy}" />` : ""} ${this.generateStylesForPreview(isPresentationMode, yamlConfig, vscodePreviewPanel)} ${styles} <link rel="stylesheet" href="${utility.addFileProtocol(path.resolve(utility.extensionDirectoryPath, "./styles/preview.css"), vscodePreviewPanel)}"> ${this.generateJSAndCssFilesForPreview(JSAndCssFiles, vscodePreviewPanel)} ${head} </head> <body class="preview-container"> <div class="mume markdown-preview" for="preview" ${isPresentationMode ? "data-presentation-mode" : ""}> ${html} </div> ${body} </body> ${this.generateScriptsForPreview(isPresentationMode, yamlConfig, vscodePreviewPanel)} ${scripts} <script src="${webviewScript}"></script> </html>`; return htmlTemplate; }); } /** * Generate HTML content * @param html: this is the final content you want to put. * @param yamlConfig: this is the front matter. * @param option: HTMLTemplateOption */ generateHTMLTemplateForExport(html, yamlConfig = {}, options) { return __awaiter(this, void 0, void 0, function* () { // get `id` and `class` const elementId = yamlConfig["id"] || ""; let elementClass = yamlConfig["class"] || []; if (typeof elementClass === "string") { elementClass = [elementClass]; } elementClass = elementClass.join(" "); // math style and script let mathStyle = ""; if (this.config.mathRenderingOption === "MathJax" || this.config.usePandocParser) { // TODO const mathJaxConfig = yield utility.getMathJaxConfig(this.config.configPath); mathJaxConfig["tex2jax"]["inlineMath"] = this.config.mathInlineDelimiters; mathJaxConfig["tex2jax"]["displayMath"] = this.config.mathBlockDelimiters; if (options.offline) { mathStyle = ` <script type="text/x-mathjax-config"> MathJax.Hub.Config(${JSON.stringify(mathJaxConfig)}); </script> <script type="text/javascript" async src="file:///${path.resolve(extensionDirectoryPath, "./dependencies/mathjax/MathJax.js")}" charset="UTF-8"></script> `; } else { mathStyle = ` <script type="text/x-mathjax-config"> MathJax.Hub.Config(${JSON.stringify(mathJaxConfig)}); </script> <script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js"></script> `; } } else if (this.config.mathRenderingOption === "KaTeX") { if (options.offline) { mathStyle = `<link rel="stylesheet" href="file:///${path.resolve(extensionDirectoryPath, "./dependencies/katex/katex.min.css")}">`; } else { mathStyle = `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css">`; } } else { mathStyle = ""; } // font-awesome let fontAwesomeStyle = ""; if (html.indexOf('<i class="fa ') >= 0) { if (options.offline) { fontAwesomeStyle = `<link rel="stylesheet" href="file:///${path.resolve(extensionDirectoryPath, `./dependencies/font-awesome/css/font-awesome.min.css`)}">`; } else { fontAwesomeStyle = `<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">`; } } // mermaid let mermaidScript = ""; let mermaidInitScript = ""; if (html.indexOf(' class="mermaid') >= 0) { if (options.offline) { mermaidScript = `<script type="text/javascript" src="file:///${path.resolve(extensionDirectoryPath, "./dependencies/mermaid/mermaid.min.js")}" charset="UTF-8"></script>`; } else { mermaidScript = `<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/mermaid@9.4.0/dist/mermaid.min.js"></script>`; } const mermaidConfig = yield utility.getMermaidConfig(this.config.configPath); mermaidInitScript += `<script> ${mermaidConfig} if (window['MERMAID_CONFIG']) { window['MERMAID_CONFIG'].startOnLoad = false window['MERMAID_CONFIG'].cloneCssStyles = false window['MERMAID_CONFIG'].theme = "${this.config.mermaidTheme}" } mermaid.initialize(window['MERMAID_CONFIG'] || {}) if (typeof(window['Reveal']) !== 'undefined') { function mermaidRevealHelper(event) { var currentSlide = event.currentSlide var diagrams = currentSlide.querySelectorAll('.mermaid') for (var i = 0; i < diagrams.length; i++) { var diagram = diagrams[i] if (!diagram.hasAttribute('data-processed')) { mermaid.init(null, diagram, ()=> { Reveal.slide(event.indexh, event.indexv) }) } } } Reveal.addEventListener('slidechanged', mermaidRevealHelper) Reveal.addEventListener('ready', mermaidRevealHelper) } else { mermaid.init(null, document.querySelectorAll('.mermaid')) } </script>`; } // zenuml let zenumlScript = ``; if (html.indexOf(' class="zenuml') >= 0) { if (options.offline) { zenumlScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/sequence-diagram/vue.js")}" charset="UTF-8"></script>`; zenumlScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/sequence-diagram/sequence-diagram.min.js")}" charset="UTF-8"></script>`; } else { zenumlScript += `<script type="text/javascript" src="https://unpkg.com/vue"></script>`; zenumlScript += `<script type="text/javascript" src="https://unpkg.com/sequence-diagram"></script>`; } } // wavedrom let wavedromScript = ``; let wavedromInitScript = ``; if (html.indexOf(' class="wavedrom') >= 0) { if (options.offline) { wavedromScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/wavedrom/default.js")}" charset="UTF-8"></script>`; wavedromScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/wavedrom/wavedrom.min.js")}" charset="UTF-8"></script>`; } else { wavedromScript += `<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/wavedrom/2.9.1/skins/default.js"></script>`; wavedromScript += `<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/wavedrom/2.9.1/wavedrom.min.js"></script>`; } wavedromInitScript = `<script>WaveDrom.ProcessAll()</script>`; } // vega and vega-lite with vega-embed // https://vega.github.io/vega/usage/#embed let vegaScript = ``; let vegaInitScript = ``; if (html.indexOf(' class="vega') >= 0 || html.indexOf(' class="vega-lite') >= 0) { dependentLibraryConfigs.forEach(({ libraryName, libraryVersion, buildPathForWebview }) => { vegaScript += options.offline ? `<script type="text/javascript" src="file:///${utility.resolveBuildPathForWebview(libraryName, buildPathForWebview)}" charset="UTF-8"></script>` : `<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/${libraryName}@${libraryVersion}/${buildPathForWebview}"></script>`; }); vegaInitScript += `<script> var vegaEls = document.querySelectorAll('.vega, .vega-lite'); function reportVegaError(el, error) { el.innerHTML = '<pre class="language-text">' + error.toString() + '</pre>' } for (var i = 0; i < vegaEls.length; i++) { const vegaEl = vegaEls[i] try { var spec = JSON.parse(vegaEl.textContent); vegaEmbed(vegaEl, spec, { actions: false, renderer: 'svg' }) .catch(function(error) { reportVegaError(vegaEl, error); }) } catch (error) { reportVegaError(vegaEl, error); } } </script>`; } // flowchart let flowchartScript = ``; let flowchartInitScript = ``; if (html.indexOf(' class="flow') >= 0) { if (options.offline) { flowchartScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/raphael/raphael.js")}" charset="UTF-8"></script>`; flowchartScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/flowchart/flowchart.min.js")}" charset="UTF-8"></script>`; } else { flowchartScript += `<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.2.7/raphael.min.js"></script>`; flowchartScript += `<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/flowchart/1.7.0/flowchart.min.js"></script>`; } flowchartInitScript = `<script> var flowcharts = document.getElementsByClassName('flow') for (var i = 0; i < flowcharts.length; i++) { var flow = flowcharts[i] try { var diagram = flowchart.parse(flow.textContent) flow.id = 'flow_' + i flow.innerHTML = '' diagram.drawSVG(flow.id) } catch (error) { flow.innerHTML = '<pre class="language-text">' + error.toString() + '</pre>' } } </script>`; } // sequence diagrams let sequenceDiagramScript = ``; let sequenceDiagramStyle = ``; let sequenceDiagramInitScript = ``; if (html.indexOf(' class="sequence') >= 0) { if (options.offline) { sequenceDiagramScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/webfont/webfontloader.js")}" charset="UTF-8"></script>`; sequenceDiagramScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/raphael/raphael.js")}" charset="UTF-8"></script>`; sequenceDiagramScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/underscore/underscore.js")}" charset="UTF-8"></script>`; sequenceDiagramScript += `<script type="text/javascript" src="file:///${path.resolve(utility.extensionDirectoryPath, "./dependencies/js-sequence-diagrams/sequence-diagram-min.js")}" charset="UTF-8"></script>`; sequenceDiagramStyle = `<link rel="stylesheet" href="file:///${path.resolve(extensionDirectoryPath, `./dependencies/js-sequence-diagrams/sequence-diagram-min.css`)}">`; } else { sequenceDiagramScript += `<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/webfont/1.6.28/webfontloader.js"></script>`; sequenceDiagramScript += `<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.2.7/raphael.min.js"></script>`; sequenceDiagramScript += `<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>`; sequenceDiagramScript += `<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/js-sequence-diagram@2.0.1/dist/sequence-diagram-min.js"></script>`; sequenceDiagramStyle = `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/js-sequence-diagram@2.0.1/dist/sequence-diagram-min.css">`; } sequenceDiagramInitScript = `<script> var sequenceDiagrams = document.getElementsByClassName('sequence') for (var i = 0; i < sequenceDiagrams.length; i++) { var sequence = sequenceDiagrams[i] try { var diagram = Diagram.parse(sequence.textContent) var theme = sequence.getAttribute('theme') || 'simple' sequence.id = 'sequence_' + i sequence.innerHTML = '' diagram.drawSVG(sequence.id, {theme: theme}) } catch (error) { sequence.innerHTML = '<pre class="language-text">' + error.toString() + '</pre>' } } </script>`; } // presentation let presentationScript = ""; let presentationStyle = ""; let presentationInitScript = ""; if (yamlConfig["isPresentationMode"]) { if (options.offline) { presentationScript = ` <script src='file:///${path.resolve(extensionDirectoryPath, "./dependencies/reveal/lib/js/head.min.js")}'></script> <script src='file:///${path.resolve(extensionDirectoryPath, "./dependencies/reveal/js/reveal.js")}'></script>`; } else { presentationScript = ` <script src='https://cdn.jsdelivr.net/npm/reveal.js@4.1.0/dist/reveal.js'></script>`; } const presentationConfig = yamlConfig["presentation"] || {}; const dependencies = presentationConfig["dependencies"] || []; if (presentationConfig["enableSpeakerNotes"]) { if (options.offline) { dependencies.push({ src: path.resolve(extensionDirectoryPath, "./dependencies/reveal/plugin/notes/notes.js"), async: true, }); } else { dependencies.push({ src: "revealjs_deps/notes.js", async: true }); // TODO: copy notes.js file to corresponding folder } } presentationConfig["dependencies"] = dependencies; presentationStyle = ` <style> ${fs.readFileSync(path.resolve(extensionDirectoryPath, "./dependencies/reveal/css/reveal.css"))} ${options.isForPrint ? fs.readFileSync(path.resolve(extensionDirectoryPath, "./dependencies/reveal/css/print/pdf.css")) : ""} </style> `; presentationInitScript = ` <script> Reveal.initialize(${JSON.stringify(Object.assign({ margin: 0.1 }, presentationConfig))}) </script> `; } // prince let princeClass = ""; if (options.isForPrince) { princeClass = "prince"; } let title = path.basename(this.filePath); title = title.slice(0, title.length - path.extname(title).length); // remove '.md' if (yamlConfig["title"]) { title = yamlConfig["title"]; } // prism and preview theme let styleCSS = ""; try { // prism *.css styleCSS += !this.config.printBackground && !yamlConfig["print_background"] && !yamlConfig["isPresentationMode"] ? yield utility.readFile(path.resolve(extensionDirectoryPath, `./styles/prism_theme/github.css`), { encoding: "utf-8" }) : yield utility.readFile(path.resolve(extensionDirectoryPath, `./styles/prism_theme/${this.getPrismTheme(yamlConfig["isPresentationMode"], yamlConfig)}`), { encoding: "utf-8" }); if (yamlConfig["isPresentationMode"]) { const theme = yamlConfig["presentation"] && typeof yamlConfig["presentation"] === "object" && yamlConfig["presentation"]["theme"] ? yamlConfig["presentation"]["theme"] : this.config.revealjsTheme; if (options.offline) { presentationStyle += `<link rel="stylesheet" href="file:///${path.resolve(extensionDirectoryPath, `./dependencies/reveal/css/theme/${theme}`)}">`; } else { presentationStyle += `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@4.1.0/dist/theme/${theme}">`; } } else { // preview theme styleCSS += !this.config.printBackground && !yamlConfig["print_background"] ? yield utility.readFile(path.resolve(extensionDirectoryPath, `./styles/preview_theme/github-light.css`), { encoding: "utf-8" }) : yield utility.readFile(path.resolve(extensionDirectoryPath, `./styles/preview_theme/${this.config.previewTheme}`), { encoding: "utf-8" }); } // style template styleCSS += yield utility.readFile(path.resolve(extensionDirectoryPath, "./styles/style-template.css"), { encoding: "utf-8" }); // markdown-it-admonition if (html.indexOf("admonition") > 0) { styleCSS += yield utility.readFile(path.resolve(extensionDirectoryPath, "./styles/markdown-it-admonition.css"), { encoding: "utf-8" }); } } catch (e) { styleCSS = ""; } // global styles let globalStyles = ""; try { globalStyles = yield utility.getGlobalStyles(this.config.configPath); } catch (error) { // ignore it } // sidebar toc let sidebarTOC = ""; let sidebarTOCScript = ""; let sidebarTOCBtn = ""; if (this.config.enableScriptExecution && !yamlConfig["isPresentationMode"] && !options.isForPrint && (!("html" in yamlConfig) || (yamlConfig["html"] && yamlConfig["html"]["toc"] !== false))) { // enable sidebar toc by default sidebarTOC = `<div class="md-sidebar-toc">${this.tocHTML}</div>`; sidebarTOCBtn = '<a id="sidebar-toc-btn">≡</a>'; // toggle sidebar toc // If yamlConfig['html']['toc'], then display sidebar TOC on startup. sidebarTOCScript = ` <script> ${yamlConfig["html"] && yamlConfig["html"]["toc"] ? `document.body.setAttribute('html-show-sidebar-toc', true)` : ""} var sidebarTOCBtn = document.getElementById('sidebar-toc-btn') sidebarTOCBtn.addEventListener('click', function(event) { event.stopPropagation() if (document.body.hasAttribute('html-show-sidebar-toc')) { document.body.removeAttribute('html-show-sidebar-toc') } else { document.body.setAttribute('html-show-sidebar-toc', true) } }) </script> `; } // task list script if (html.indexOf("task-list-item-checkbox") >= 0) { const $ = cheerio.load("<div>" + html + "</div>"); $(".task-list-item-checkbox").each((index, elem) => { const $elem = $(elem); let $li = $elem.parent(); if (!$li[0].name.match(/^li$/i)) { $li = $li.parent(); } if ($li[0].name.match(/^li$/i)) { $li.addClass("task-list-item"); } }); html = $.html(); } // process styles // move @import ''; to the very start. let styles = styleCSS + "\n" + globalStyles; let imports = ""; styles = styles.replace(/\@import\s+url\(([^)]+)\)\s*;/g, (whole, url) => { imports += whole + "\n"; return ""; }); styles = imports + styles; html = ` <!DOCTYPE html> <html> <head> <title>${title}</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> ${presentationStyle} ${mathStyle} ${sequenceDiagramStyle} ${fontAwesomeStyle} ${presentationScript} ${mer