move docs, remove katex

This commit is contained in:
undefined committed 2020-07-20 16:03:22 +08:00
1 parent da6002278d
commit c4a13f2e27
27 files changed
+190 -550

No files matched your search

+1 -40
View File
@@ -21,7 +21,7 @@ export const builtinModel = [
export const builtinHandler = [
'home', 'problem', 'record', 'judge', 'user',
'contest', 'training', 'discussion', 'manage', 'import',
'misc', 'homework', 'domain', 'wiki',
'misc', 'homework', 'domain',
];
export const builtinScript = [
@@ -212,42 +212,3 @@ export async function script(pending: string[], fail: string[], active: string[]
active.push(i);
}
}
export async function wiki(pending: string[], fail: string[]) {
for (const i of pending) {
const p = path.resolve(i, 'wiki');
if (fs.existsSync(p) && fs.statSync(p).isDirectory() && !fail.includes(i)) {
try {
const categories = fs.readdirSync(p);
for (const category of categories) {
if (!fs.statSync(p).isDirectory()) return;
const pages = fs.readdirSync(path.join(p, category));
if (!global.Hydro.wiki[category]) global.Hydro.wiki[category] = {};
for (const page of pages) {
const c = fs.readFileSync(path.join(p, category, page)).toString().split('\n');
const pagename = page.split('.')[0];
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) global.Hydro.wiki[category][pagename].push(content);
content = {};
const t = line.split('# ')[1].split('|');
[content.title, content.id] = t.map((q) => q.trim());
content.content = '';
} else {
content.content = `${content.content}${line}\n`;
}
}
}
}
console.log(`Wiki init: ${i}`);
} catch (e) {
fail.push(i);
console.error(`Wiki Load Fail: ${i}`);
console.error(e);
}
}
}
}
+1 -4
View File
@@ -8,9 +8,6 @@ import Router from 'koa-router';
import cache from 'koa-static-cache';
import nunjucks from 'nunjucks';
import mongodb from 'mongodb';
import parse from 'yargs-parser';
const argv = parse(process.argv.slice(2));
class Loader {
getSource(name: string) { // eslint-disable-line class-methods-use-this
@@ -110,7 +107,7 @@ export function load() {
ctx.body = await render('setup.html');
ctx.response.type = 'text/html';
});
const listenPort = argv.port || 8888;
const listenPort = global.argv.port || 8888;
router.post('/', async (ctx) => {
const {
host, port, name, username, password,
+1 -2
View File
@@ -1,7 +1,7 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable import/no-dynamic-require */
import {
locale, template, lib, service, model, handler, script, setting, wiki, uistatic,
locale, template, lib, service, model, handler, script, setting, uistatic,
builtinLib, builtinScript, builtinHandler, builtinModel,
} from './common';
@@ -17,7 +17,6 @@ export async function load(call, args) {
locale(pending, fail),
template(pending, fail),
uistatic(pending, fail),
wiki(pending, fail),
]);
const bus = require('../service/bus');
await new Promise((resolve) => {
+5 -4
View File
@@ -103,10 +103,11 @@ class SwitchLanguageHandler extends Handler {
}
class MarkdownHandler extends Handler {
async post({ text, safe = true }) {
this.response.body = safe
? markdown.safe.render(text)
: markdown.unsafe.render(text);
async post({ text, html = false, inline = false }) {
this.response.body = inline
? markdown.renderInline(text, html)
: markdown.render(text, html);
this.response.type = 'text/html';
}
}
+1 -1
View File
@@ -355,7 +355,7 @@ class ProblemEditHandler extends ProblemManageHandler {
const pid = checkPid(this.request.body.pid);
const pdoc = await problem.get(domainId, this.request.params.pid);
await problem.edit(domainId, pdoc.docId, { title, content, pid });
this.back();
this.response.redirect = this.url('problem_detail', this.request.params.pid);
}
}
-31
View File
@@ -1,31 +0,0 @@
import { NotFoundError } from '../error';
import {
Route, Handler, Types, param,
} from '../service/server';
class WikiHandler extends Handler {
@param('category', Types.String, true)
@param('page', Types.String)
async get(domainId: string, category = 'wiki', page: string) {
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, pages, page_name: `wiki_${category}_${page}`,
};
this.response.template = 'wiki.html';
}
}
export async function apply() {
Route('wiki', '/wiki/:page', WikiHandler);
Route('wiki_with_category', '/wiki/:category/:page', WikiHandler);
}
global.Hydro.handler.wiki = apply;
-1
View File
@@ -281,7 +281,6 @@ declare global {
[key: string]: any
},
stat: any,
wiki: { [category: string]: { [page: string]: any } },
ui: {
manifest: Dict<string>,
nav: any,
+19 -37
View File
@@ -17,21 +17,15 @@ belong to the previous footnote.
import Footnote from 'markdown-it-footnote';
// ==Highlight==
import Mark from 'markdown-it-mark';
// :::warn This page requires javascript. :::
// :::record-pass Accepted :::
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();
require('prismjs/components/index');
type Plugin = MarkdownIt.PluginSimple | MarkdownIt.PluginWithOptions | MarkdownIt.PluginWithParams;
class Markdown extends MarkdownIt {
constructor(safe) {
constructor() {
super({
linkify: true,
highlight(str, lang) {
@@ -42,44 +36,32 @@ class Markdown extends MarkdownIt {
}
return '';
},
html: !safe,
});
this.linkify.tlds('.py', false);
this.use(katex);
this.use(Imsize);
this.use(Footnote);
this.use(Mark);
this.use(Anchor);
this.use(TOC);
const RE_CONTAINER = /^(note|warn|record-pending|record-progress|record-fail|record-pass|record-ignored)\s+(.*?):::(.*)$/;
const CONTAINER_MAP = {
note: ['<blockquote class="note">', '</blockquote>'],
warn: ['<blockquote class="warn">', '</blockquote>'],
'record-pending': ['<span class="record-status--text pending">', '</span>'],
'record-progress': ['<span class="record-status--text progress">', '</span>'],
'record-fail': ['<span class="record-status--text fail">', '</span>'],
'record-pass': ['<span class="record-status--text pass">', '</span>'],
'record-ignored': ['<span class="record-status--text ignored">', '</span>'],
};
this.use(Container, 'blockquote', {
validate(params) {
return params.trim().match(RE_CONTAINER);
},
render(tokens, idx) {
const m = tokens[idx].info.trim().match(RE_CONTAINER);
if (!m) return '';
if (CONTAINER_MAP[m[1]]) {
return `${CONTAINER_MAP[m[1]][0]}${md.utils.escapeHtml(m[2])}\n${CONTAINER_MAP[m[1]][1]}\n${md.utils.escapeHtml(m[3])}`;
}
return `[${m[1]}]\n${md.utils.escapeHtml(m[2])}\n[/${m[1]}]\n${md.utils.escapeHtml(m[3])}`;
},
});
}
}
export const safe = new Markdown(true);
export const unsafe = new Markdown(false);
export const md = new Markdown();
export function plugin(func: Plugin, ...args: any[]) {
md.use(func, ...args);
}
export function render(text: string, html = false) {
md.set({ html: !!html });
return md.render(text);
}
export function renderInline(text: string, html = false) {
md.set({ html: !!html });
return md.renderInline(text);
}
global.Hydro.lib.markdown = {
safe, unsafe,
md, plugin, render, renderInline,
};
+1 -4
View File
@@ -35,10 +35,7 @@ class Nunjucks extends nunjucks.Environment {
this.addFilter('json', (self) => JSON.stringify(self), false);
this.addFilter('serialize', (self, ignoreFunction = true) => serialize(self, { ignoreFunction }));
this.addFilter('assign', (self, data) => Object.assign(self, data));
this.addFilter('markdown', (self, safe = true) => {
if (safe) return markdown.safe.render(self);
return markdown.unsafe.render(self);
});
this.addFilter('markdown', (self, html = false) => markdown.render(self, html));
this.addFilter('ansi', (self) => misc.ansiToHtml(self));
this.addFilter('base64_encode', (s) => Buffer.from(s).toString('base64'));
this.addFilter('bitand', (self, val) => self & val);
+2 -4
View File
@@ -8,11 +8,10 @@ import os from 'os';
import path from 'path';
import cluster from 'cluster';
import fs from 'fs-extra';
import parse from 'yargs-parser';
import { argv } from 'yargs';
import AdmZip from 'adm-zip';
global.argv = parse(process.argv.slice(2));
global.argv = argv;
global.Hydro = {
stat: { reqCount: 0 },
handler: {},
@@ -23,7 +22,6 @@ global.Hydro = {
script: {},
// @ts-ignore
lib: {},
wiki: {},
ui: {
manifest: {},
nav: [],
-137
View File
@@ -1,137 +0,0 @@
// 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 `<p>${katex.renderToString(latex, options)}</p>`;
} 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;
}
+11 -11
View File
@@ -131,17 +131,17 @@ SystemSetting(
Setting('setting_oauth', 'oauth.googleappid', null, null, 'text', 'Google Oauth ClientID', null),
Setting('setting_oauth', 'oauth.googlesecret', null, null, 'text', 'Google Oauth Secret', null, FLAG_SECRET),
Setting('setting_proxy', 'proxy', null, null, 'text', 'Proxy Server URL'),
Setting('setting_constant', 'PROBLEM_PER_PAGE', null, 100, 'number', 'Problems per Page'),
Setting('setting_constant', 'CONTEST_PER_PAGE', null, 20, 'number', 'Contests per Page'),
Setting('setting_constant', 'DISCUSSION_PER_PAGE', null, 50, 'number', 'Discussion per Page'),
Setting('setting_constant', 'RECORD_PER_PAGE', null, 100, 'number', 'Record per Page'),
Setting('setting_constant', 'SOLUTION_PER_PAGE', null, 20, 'number', 'Solutions per Page'),
Setting('setting_constant', 'TRAINING_PER_PAGE', null, 10, 'number', 'Training per Page'),
Setting('setting_constant', 'REPLY_PER_PAGE', null, 50, 'number', 'Reply per Page'),
Setting('setting_constant', 'HOMEWORK_ON_MAIN', null, 5, 'number', 'HOMEWORK_ON_MAIN'),
Setting('setting_constant', 'DISCUSSION_ON_MAIN', null, 20, 'number', 'DISCUSSION_ON_MAIN'),
Setting('setting_constant', 'CONTEST_ON_MAIN', null, 10, 'number', 'CONTEST_ON_MAIN'),
Setting('setting_constant', 'TRAINING_ON_MAIN', null, 10, 'number', 'TRAINING_ON_MAIN'),
Setting('setting_constant', 'PROBLEM_PER_PAGE', null, 100, 'number', 'Problems per Page', null, FLAG_HIDDEN),
Setting('setting_constant', 'CONTEST_PER_PAGE', null, 20, 'number', 'Contests per Page', null, FLAG_HIDDEN),
Setting('setting_constant', 'DISCUSSION_PER_PAGE', null, 50, 'number', 'Discussion per Page', null, FLAG_HIDDEN),
Setting('setting_constant', 'RECORD_PER_PAGE', null, 100, 'number', 'Record per Page', null, FLAG_HIDDEN),
Setting('setting_constant', 'SOLUTION_PER_PAGE', null, 20, 'number', 'Solutions per Page', null, FLAG_HIDDEN),
Setting('setting_constant', 'TRAINING_PER_PAGE', null, 10, 'number', 'Training per Page', null, FLAG_HIDDEN),
Setting('setting_constant', 'REPLY_PER_PAGE', null, 50, 'number', 'Reply per Page', null, FLAG_HIDDEN),
Setting('setting_constant', 'HOMEWORK_ON_MAIN', null, 5, 'number', 'HOMEWORK_ON_MAIN', null, FLAG_HIDDEN),
Setting('setting_constant', 'DISCUSSION_ON_MAIN', null, 20, 'number', 'DISCUSSION_ON_MAIN', null, FLAG_HIDDEN),
Setting('setting_constant', 'CONTEST_ON_MAIN', null, 10, 'number', 'CONTEST_ON_MAIN', null, FLAG_HIDDEN),
Setting('setting_constant', 'TRAINING_ON_MAIN', null, 10, 'number', 'TRAINING_ON_MAIN', null, FLAG_HIDDEN),
Setting('setting_storage', 'db.ver', null, 1, 'number', 'Database version', null, FLAG_DISABLED | FLAG_HIDDEN),
Setting('setting_storage', 'user', null, 1, 'number', 'User Counter', null, FLAG_DISABLED | FLAG_HIDDEN),
);
+2 -4
View File
@@ -13,7 +13,6 @@ import Router from 'koa-router';
import cache from 'koa-static-cache';
import sockjs from 'sockjs';
import serialize, { SerializeJSOptions } from 'serialize-javascript';
import parse from 'yargs-parser';
import { lrucache } from '../utils';
import { User, DomainDoc } from '../interface';
import {
@@ -32,7 +31,6 @@ import * as blacklist from '../model/blacklist';
import * as token from '../model/token';
import * as opcount from '../model/opcount';
const argv = parse(process.argv.slice(2));
const app = new Koa();
let server;
const router = new Router();
@@ -774,8 +772,8 @@ export async function start() {
}
app.use(router.routes()).use(router.allowedMethods());
Route('notfound_handler', '*', Handler);
server.listen(argv.port || port);
console.log('Server listening at: %s', argv.port || port);
server.listen(global.argv.port || port);
console.log('Server listening at: %s', global.argv.port || port);
}
global.Hydro.service.server = {