From bf29661eaa6d083436cd2e1b1461690fa8dd5e81 Mon Sep 17 00:00:00 2001 From: undefined Date: Thu, 16 Jul 2020 20:00:48 +0800 Subject: [PATCH] upgrade katex to 0.12, wiki load --- TODO | 3 +- hydro/entry/common.ts | 10 +-- hydro/entry/unzip.ts | 3 - hydro/entry/worker.ts | 1 - hydro/handler/record.ts | 5 +- hydro/handler/wiki.ts | 3 +- hydro/lib/markdown.ts | 2 +- hydro/markdown/katex.ts | 137 +++++++++++++++++++++++++++++ package.json | 5 +- templates/components/home.html | 12 +-- templates/components/sidemenu.html | 3 +- templates/domain_base.html | 10 +-- templates/manage_base.html | 8 +- templates/record_main.html | 4 +- templates/wiki.html | 7 +- ui/package.json | 2 +- ui/yarn.lock | 8 +- yarn.lock | 20 ++--- 18 files changed, 189 insertions(+), 54 deletions(-) create mode 100644 hydro/markdown/katex.ts diff --git a/TODO b/TODO index 8c9e71d4d..7a7cf97fb 100644 --- a/TODO +++ b/TODO @@ -8,4 +8,5 @@ web端运行脚本似乎异常 SETTINGS_PRIVACY.allowRegisteredUsers model.setting.ui.name pdoc.secretConfig? -在线IDE 更换颜色主题 +在线IDE 更换颜色主题, fix resize + diff --git a/hydro/entry/common.ts b/hydro/entry/common.ts index ebca95532..b5f728627 100644 --- a/hydro/entry/common.ts +++ b/hydro/entry/common.ts @@ -218,21 +218,22 @@ export async function wiki(pending: string[], fail: string[]) { const p = path.resolve(i, 'wiki'); if (fs.existsSync(p) && fs.statSync(p).isDirectory() && !fail.includes(i)) { try { - const r = {}; const categories = fs.readdirSync(p); for (const category of categories) { + console.log('category', category); if (!fs.statSync(p).isDirectory()) return; const pages = fs.readdirSync(path.join(p, category)); - const res = {}; + if (!global.Hydro.wiki[category]) global.Hydro.wiki[category] = {}; + console.log(pages); for (const page of pages) { const c = fs.readFileSync(path.join(p, category, page)).toString().split('\n'); const pagename = page.split('.')[0]; - res[pagename] = []; + global.Hydro.wiki[category][pagename] = []; let content = null; for (let j = 0; j < c.length; j++) { const line = c[j]; if (line.startsWith('# ')) { - if (content) res[pagename].push(content); + if (content) global.Hydro.wiki[category][pagename].push(content); content = {}; const t = line.split('# ')[1].split('|'); [content.title, content.id] = t.map((q) => q.trim()); @@ -242,7 +243,6 @@ export async function wiki(pending: string[], fail: string[]) { } } } - r[category] = res; } console.log(`Wiki init: ${i}`); } catch (e) { diff --git a/hydro/entry/unzip.ts b/hydro/entry/unzip.ts index 132da7be0..e58a01f36 100644 --- a/hydro/entry/unzip.ts +++ b/hydro/entry/unzip.ts @@ -44,9 +44,6 @@ export async function load() { const files = fs.readdirSync(moduleRoot); for (const file of files) { try { - // This fixs a mistake. - // Markdown-it-katex is not a hydro module but a dependency. - if (file === 'markdown-it-katex') continue; const modulePath = path.join(moduleRoot, file); const packagejson = path.join(modulePath, 'package.json'); if (fs.statSync(modulePath).isFile() && file.endsWith('.hydro')) { diff --git a/hydro/entry/worker.ts b/hydro/entry/worker.ts index 6e80ab353..bdf241b15 100644 --- a/hydro/entry/worker.ts +++ b/hydro/entry/worker.ts @@ -56,7 +56,6 @@ export async function load() { } } for (const i of builtinScript) require(`../script/${i}`); - await wiki(pending, fail); await script(pending, fail, active); for (const postInit of global.Hydro.postInit) { await postInit(); diff --git a/hydro/handler/record.ts b/hydro/handler/record.ts index 60e75d9ca..0831b2425 100644 --- a/hydro/handler/record.ts +++ b/hydro/handler/record.ts @@ -35,9 +35,10 @@ class RecordListHandler extends RecordHandler { page, await system.get('RECORD_PER_PAGE'), ); + const canViewProblemHidden = this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN); const [udict, pdict] = await Promise.all([ user.getList(domainId, rdocs.map((rdoc) => rdoc.uid)), - problem.getList(domainId, rdocs.map((rdoc) => rdoc.pid), false, false), + problem.getList(domainId, rdocs.map((rdoc) => rdoc.pid), canViewProblemHidden, false), ]); const path = [ ['Hydro', 'homepage'], @@ -100,7 +101,7 @@ class RecordRejudgeHandler extends Handler { const RecordConnectionHandler = contest.ContestHandlerMixin(ConnectionHandler); class RecordMainConnectionHandler extends RecordConnectionHandler { - @param('tid', Types.ObjectID) + @param('tid', Types.ObjectID, true) async prepare(domainId: string, tid: ObjectID) { this.domainId = domainId; if (tid) { diff --git a/hydro/handler/wiki.ts b/hydro/handler/wiki.ts index f7d4377aa..e3772d026 100644 --- a/hydro/handler/wiki.ts +++ b/hydro/handler/wiki.ts @@ -10,13 +10,14 @@ class WikiHandler extends Handler { if (!global.Hydro.wiki[category]) throw new NotFoundError(category); if (!global.Hydro.wiki[category][page]) throw new NotFoundError(category, page); const contents = global.Hydro.wiki[category][page]; + const pages = Object.keys(global.Hydro.wiki[category]); const path = [ ['Hydro', 'homepage'], [`wiki_${category}`, null], [`wiki_${category}_${page}`, null], ]; this.response.body = { - path, contents, page_name: `wiki_${category}_${page}`, + path, contents, pages, page_name: `wiki_${category}_${page}`, }; this.response.template = 'wiki.html'; } diff --git a/hydro/lib/markdown.ts b/hydro/lib/markdown.ts index 7cb3e5c3d..fbc9349c2 100644 --- a/hydro/lib/markdown.ts +++ b/hydro/lib/markdown.ts @@ -2,7 +2,6 @@ import MarkdownIt from 'markdown-it'; import Prism from 'prismjs'; // For math: $a\times b\eq 10$ -import katex from '@hydrooj/markdown-it-katex'; // Specific image size: ![image](image.png =100x100) import Imsize from 'markdown-it-imsize'; /* Footnote support. @@ -25,6 +24,7 @@ import Container from 'markdown-it-container'; import TOC from 'markdown-it-table-of-contents'; import Anchor from 'markdown-it-anchor'; +import katex from '../markdown/katex'; const md = MarkdownIt(); diff --git a/hydro/markdown/katex.ts b/hydro/markdown/katex.ts new file mode 100644 index 000000000..a581c23d5 --- /dev/null +++ b/hydro/markdown/katex.ts @@ -0,0 +1,137 @@ +// https://github.com/hydro-dev/markdown-it-katex/blob/master/index.js +import katex from 'katex'; +import MarkdownIt from 'markdown-it'; + +function isValidDelim(state, pos: number) { + const max = state.posMax; + const prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1; + const nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1; + let canOpen = true; + let canClose = true; + if (prevChar === 0x20/* " " */ || prevChar === 0x09 + ||/* \t */ (nextChar >= 0x30/* "0" */ && nextChar <= 0x39/* "9" */)) { + canClose = false; + } + if (nextChar === 0x20/* " " */ || nextChar === 0x09/* \t */) { + canOpen = false; + } + return { canOpen, canClose }; +} + +function mathInline(state, silent: boolean) { + let match; + let res; + let pos; + if (state.src[state.pos] !== '$') return false; + res = isValidDelim(state, state.pos); + if (!res.canOpen) { + if (!silent) state.pending += '$'; + state.pos += 1; + return true; + } + const start = state.pos + 1; + match = start; + // eslint-disable-next-line no-cond-assign + while ((match = state.src.indexOf('$', match)) !== -1) { + pos = match - 1; + while (state.src[pos] === '\\') pos -= 1; + if (((match - pos) % 2) === 1) break; + match += 1; + } + if (match === -1) { + if (!silent) state.pending += '$'; + state.pos = start; + return true; + } + if (match - start === 0) { + if (!silent) state.pending += '$$'; + state.pos = start + 1; + return true; + } + res = isValidDelim(state, match); + if (!res.can_close) { + if (!silent) state.pending += '$'; + state.pos = start; + return true; + } + if (!silent) { + const token = state.push('math_inline', 'math', 0); + token.markup = '$'; + token.content = state.src.slice(start, match); + } + state.pos = match + 1; + return true; +} + +function mathBlock(state, start, end, silent) { + let lastLine; + let next; + let lastPos; + let found = false; + let pos = state.bMarks[start] + state.tShift[start]; + let max = state.eMarks[start]; + if (pos + 2 > max) return false; + if (state.src.slice(pos, pos + 2) !== '$$') return false; + pos += 2; + let firstLine = state.src.slice(pos, max); + if (silent) return true; + if (firstLine.trim().slice(-2) === '$$') { + firstLine = firstLine.trim().slice(0, -2); + found = true; + } + for (next = start; !found;) { + next++; + if (next >= end) break; + pos = state.bMarks[next] + state.tShift[next]; + max = state.eMarks[next]; + if (pos < max && state.tShift[next] < state.blkIndent) break; + if (state.src.slice(pos, max).trim().slice(-2) === '$$') { + lastPos = state.src.slice(0, max).lastIndexOf('$$'); + lastLine = state.src.slice(pos, lastPos); + found = true; + } + } + state.line = next + 1; + const token = state.push('math_block', 'math', 0); + token.block = true; + token.content = (firstLine && firstLine.trim() ? `${firstLine}\n` : '') + + state.getLines(start + 1, next, state.tShift[start], true) + + (lastLine && lastLine.trim() ? lastLine : ''); + token.map = [start, state.line]; + token.markup = '$$'; + return true; +} + +export default function plugin(md: MarkdownIt, options) { + options = options || {}; + function katexInline(latex: string) { + options.displayMode = false; + try { + return katex.renderToString(latex, options); + } catch (error) { + if (options.throwOnError) console.log(error); + return latex; + } + } + function inlineRenderer(tokens, idx) { + return katexInline(tokens[idx].content); + } + function katexBlock(latex: string) { + options.displayMode = true; + try { + return `

${katex.renderToString(latex, options)}

`; + } catch (error) { + if (options.throwOnError) console.log(error); + return latex; + } + } + function blockRenderer(tokens, idx) { + return `${katexBlock(tokens[idx].content)}\n`; + } + md.inline.ruler.after('escape', 'math_inline', mathInline); + md.block.ruler.after('blockquote', 'math_block', mathBlock, { + alt: ['paragraph', 'reference', 'blockquote', 'list'], + }); + md.renderer.rules.math_inline = inlineRenderer; + md.renderer.rules.math_block = blockRenderer; +} diff --git a/package.json b/package.json index 6a1ecc512..dd357d3b0 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,12 @@ "node": ">=10.10" }, "dependencies": { - "@hydrooj/markdown-it-katex": "^2.1.1", "adm-zip": "^0.4.16", "ansi_up": "^4.0.4", "detect-browser": "^5.1.1", "fs-extra": "^9.0.1", "js-yaml": "^3.13.1", + "katex": "^0.12.0", "koa": "^2.13.0", "koa-body": "^4.2.0", "koa-morgan": "^1.0.1", @@ -45,6 +45,7 @@ "devDependencies": { "@types/adm-zip": "^0.4.33", "@types/fs-extra": "^9.0.1", + "@types/katex": "^0.11.0", "@types/koa": "^2.11.3", "@types/koa-morgan": "^1.0.4", "@types/koa-router": "^7.4.1", @@ -95,4 +96,4 @@ ] }, "snyk": true -} \ No newline at end of file +} diff --git a/templates/components/home.html b/templates/components/home.html index 2bc7c23b7..1fe07eed8 100644 --- a/templates/components/home.html +++ b/templates/components/home.html @@ -2,14 +2,14 @@ {% macro render_sidebar() %}
{% endmacro %} diff --git a/templates/components/sidemenu.html b/templates/components/sidemenu.html index efe3723f7..f09110e10 100644 --- a/templates/components/sidemenu.html +++ b/templates/components/sidemenu.html @@ -1,4 +1,5 @@ -{% macro render_item(icon_name, page_name, target_url, label=none) %} +{% macro render_item(icon_name, page_name, args={}, label=none) %} +{% set target_url = url(page_name, args) %} diff --git a/templates/manage_base.html b/templates/manage_base.html index d261d0da9..4e142e20a 100644 --- a/templates/manage_base.html +++ b/templates/manage_base.html @@ -12,10 +12,10 @@ {{ _('Properties') }} diff --git a/templates/record_main.html b/templates/record_main.html index 69e8f971b..7ee75ec6f 100644 --- a/templates/record_main.html +++ b/templates/record_main.html @@ -47,7 +47,7 @@
{% if not rdocs %} - {% if not filter_uidOrName and not filter_pid and not filter_tid %} + {% if not filterUidOrName and not filterPid and not filterTid %} {{ nothing.render('Oh, there is no task in the queue!') }} {% else %} {{ nothing.render('Oh, there is no task that matches the filter!') }} @@ -82,7 +82,7 @@ {% endfor %} - {% if handler.user.hasPerm(perm.PERM_VIEW_JUDGE_STATISTICS) %} + {% if handler.user.hasPriv(PRIV.PRIV_VIEW_JUDGE_STATISTICS) %}
  • diff --git a/templates/wiki.html b/templates/wiki.html index f584b3d62..a0b719be7 100644 --- a/templates/wiki.html +++ b/templates/wiki.html @@ -17,10 +17,9 @@
    diff --git a/ui/package.json b/ui/package.json index 74b58d70b..5435d77f9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -75,7 +75,7 @@ "jquery-scroll-lock": "^3.1.3", "jquery.easing": "^1.4.1", "jquery.transit": "^0.9.12", - "katex": "^0.11.1", + "katex": "^0.12.0", "lodash": "^4.17.19", "mini-css-extract-plugin": "^0.9.0", "moment": "^2.27.0", diff --git a/ui/yarn.lock b/ui/yarn.lock index 1fd944076..0b3d486dc 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -5424,10 +5424,10 @@ just-debounce@^1.0.0: resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo= -katex@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.11.1.tgz#df30ca40c565c9df01a466a00d53e079e84ffaa2" - integrity sha512-5oANDICCTX0NqYIyAiFCCwjQ7ERu3DQG2JFHLbYOf+fXaMoH8eg/zOq5WSYJsKMi/QebW+Eh3gSM+oss1H/bww== +katex@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.12.0.tgz#2fb1c665dbd2b043edcf8a1f5c555f46beaa0cb9" + integrity sha512-y+8btoc/CK70XqcHqjxiGWBOeIL8upbS0peTPXTvgrh21n1RiWWcIpSWM+4uXq+IAgNh9YYQWdc7LVDPDAEEAg== dependencies: commander "^2.19.0" diff --git a/yarn.lock b/yarn.lock index f1fec7627..e2f018a93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30,13 +30,6 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@hydrooj/markdown-it-katex@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@hydrooj/markdown-it-katex/-/markdown-it-katex-2.1.1.tgz#0b656483b912593e2a927360592462770e329f25" - integrity sha512-uOinvM64Y8XPxbsLLPHcOYt0A6eBqnZQUkN6ynWu/pLwD+a3pPnKvBhBi+BHETMGPMJpxXiAWGgs5qqnVN8Hvg== - dependencies: - katex "^0.11.1" - "@nodelib/fs.scandir@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" @@ -470,6 +463,11 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/katex@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.11.0.tgz#b16c54ee670925ffef0616beae9e90c557e17334" + integrity sha512-27BfE8zASRLYfSBNMk5/+KIjr2CBBrH0i5lhsO04fca4TGirIIMay73v3zNkzqmsaeIa/Mi5kejWDcxPLAmkvA== + "@types/keygrip@*": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" @@ -3819,10 +3817,10 @@ jszip@^3.2.2: readable-stream "~2.3.6" set-immediate-shim "~1.0.1" -katex@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.11.1.tgz#df30ca40c565c9df01a466a00d53e079e84ffaa2" - integrity sha512-5oANDICCTX0NqYIyAiFCCwjQ7ERu3DQG2JFHLbYOf+fXaMoH8eg/zOq5WSYJsKMi/QebW+Eh3gSM+oss1H/bww== +katex@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.12.0.tgz#2fb1c665dbd2b043edcf8a1f5c555f46beaa0cb9" + integrity sha512-y+8btoc/CK70XqcHqjxiGWBOeIL8upbS0peTPXTvgrh21n1RiWWcIpSWM+4uXq+IAgNh9YYQWdc7LVDPDAEEAg== dependencies: commander "^2.19.0"