From 215dabda32e379054fee170a751e08274e892020 Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Tue, 20 Apr 2021 00:33:10 +0200 Subject: [PATCH] Improve markdown support and css tokens (#246) --- source/app/metrics/utils.mjs | 25 +++++++++--- .../classic/partials/stackoverflow.ejs | 4 +- source/templates/classic/style.css | 40 ++++++++----------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/source/app/metrics/utils.mjs b/source/app/metrics/utils.mjs index a4d0eed7..2884a24c 100644 --- a/source/app/metrics/utils.mjs +++ b/source/app/metrics/utils.mjs @@ -162,19 +162,34 @@ /**Markdown-html sanitizer-interpreter */ export async function markdown(text, {mode = "inline", codelines = Infinity} = {}) { - //Sanitize once user text and then apply markdown. Depending on mode, reapply stricter sanitization if required - let rendered = htmlsanitize(await marked(htmlsanitize(text), { + //Sanitize user input once to prevent injections and parse into markdown + let rendered = await marked(htmlsanitize(text).replace(/^>/gm, ">"), { highlight(code, lang) { return lang in prism.languages ? prism.highlight(code, prism.languages[lang]) : code }, silent:true, xhtml:true, - }), { - inline:{allowedTags:["br", "code", "span"], allowedAttributes:{code:["class"], span:["class"]}}, - }[mode]) + }) + //Markdown mode + switch (mode) { + case "inline":{ + rendered = htmlsanitize(htmlsanitize(rendered, { + allowedTags:["h1", "h2", "h3", "h4", "h5", "h6", "br", "blockquote", "code", "span"], + allowedAttributes:{code:["class"], span:["class"]}, + }), { + allowedAttributes:{code:["class"], span:["class"]}, + transformTags:{h1:"b", h2:"b", h3:"b", h4:"b", h5:"b", h6:"b", blockquote:"i"}, + }) + break + } + default: + break + } //Trim code snippets rendered = rendered.replace(/(?)(?[\s\S]*?)(?<\/code>)/g, (m, open, code, close) => { //eslint-disable-line max-params const lines = code.trim().split("\n") + if ((lines.length > 1)&&(!/class="[\s\S]*"/.test(open))) + open = open.replace(">", ' class="language-multiline">') return `${open}${lines.slice(0, codelines).join("\n")}${lines.length > codelines ? `\n(${lines.length-codelines} more ${lines.length-codelines === 1 ? "line was" : "lines were"} trimmed)` : ""}${close}` }) return rendered diff --git a/source/templates/classic/partials/stackoverflow.ejs b/source/templates/classic/partials/stackoverflow.ejs index 12c8e2cb..2360d196 100644 --- a/source/templates/classic/partials/stackoverflow.ejs +++ b/source/templates/classic/partials/stackoverflow.ejs @@ -76,7 +76,7 @@ <% } %> -
+
<%- entry.body %>
@@ -122,7 +122,7 @@
<% } %>
-
+
<%- entry.body %>
diff --git a/source/templates/classic/style.css b/source/templates/classic/style.css index 2f5426eb..2eddd4b8 100644 --- a/source/templates/classic/style.css +++ b/source/templates/classic/style.css @@ -939,7 +939,11 @@ overflow: hidden; } -/* Syntax highlighting */ +/* Markdown and syntax highlighting */ + .markdown b, .markdown i { + display: inline-block; + width: 97%; + } code { background-color: #7777771F; display: inline-block; @@ -954,35 +958,23 @@ width: 97%; margin-top: 4px; } - .token.comment, .token.prolog, .token.doctype, .token.cdata { - color: #6a737d; + .token.comment { + color: #669900; } .token.punctuation { - color: #24292e; + color: #8a93a8; } - .token.namespace, .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol { - color: #d73a49; + .token.namespace, .token.constant, .token.symbol, .token.keyword { + color: #b44418; } - .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { - color: #032f62; + .token.regex, .token.string, .token.char, .token.number, .token.boolean { + color: #2777AA; } - .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string, .token.variable { - color: #005cc5; + .token.property, .token.tag { + color: #48428a; } - .token.atrule, .token.attr-value, .token.keyword { - color: #6f42c1 - } - .token.regex, .token.important { - color: #e90; - } - .token.important, .token.bold { - font-weight: bold; - } - .token.italic { - font-style: italic; - } - .token.deleted { - color: red; + .token.builtin, .token.operator { + color: #106cbc; } .token.trimmed { font-style: italic;