Skip to content

Commit

Permalink
feat(vercel & client): add mathjax support with katex
Browse files Browse the repository at this point in the history
fix #58
  • Loading branch information
lizheming committed Dec 5, 2020
1 parent 41af427 commit 9518679
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 7 deletions.
5 changes: 5 additions & 0 deletions packages/client/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import App from './App';
import Context from './context';
import Visitor from './utils/visitor';
import { fetchCount } from './utils/fetch';
import mathML from './utils/mathml';
import './index.css';
import './math.css';

export default function Waline({
el,
Expand Down Expand Up @@ -49,6 +51,9 @@ export default function Waline({
});
}

//mathml
window.addEventListener('load', mathML);

//评论列表展示
const root = document.querySelector(el);
if(!root) {
Expand Down
218 changes: 218 additions & 0 deletions packages/client/src/math.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* See https://github.com/fred-wang/mathml.css */

/* math */
.mathml-polyfill math {
font-family: Cambria Math, Latin Modern Math;
display: inline;
text-indent: 0;
}
.mathml-polyfill math[display="block"] {
display: block;
text-align: center;
}

/* fraction */
.mathml-polyfill mfrac {
display: inline-block !important;
vertical-align: -50%;
border-collapse: collapse;
text-align: center;
}
.mathml-polyfill mfrac > * {
display: block !important;
}
.mathml-polyfill mfrac > * + * {
display: inline-block !important;
vertical-align: top;
}
.mathml-polyfill mfrac:not([linethickness="0"]) > *:first-child {
border-bottom: solid thin;
}

/* sub/sup scripts */
.mathml-polyfill msub > *:nth-child(2),
.mathml-polyfill msubsup > *:nth-child(2),
.mathml-polyfill mmultiscripts > *:nth-child(2n+2),
.mathml-polyfill mmultiscripts > mprescripts ~ *:nth-child(2n+3) {
font-size: 0.8em;
vertical-align: sub;
}
.mathml-polyfill msup > *:nth-child(2),
.mathml-polyfill msubsup > *:nth-child(3),
.mathml-polyfill mmultiscripts > *:nth-child(2n+3),
.mathml-polyfill mmultiscripts > mprescripts ~ *:nth-child(2n+2) {
font-size: 0.8em;
vertical-align: super;
}
.mathml-polyfill mprescripts:after {
content: ";";
}

/* under/over scripts */
.mathml-polyfill munder, mover, munderover {
display: inline-flex !important;
flex-direction: column;
}
.mathml-polyfill munder > *:nth-child(2), munderover > *:nth-child(2) {
font-size: 0.8em;
order: +1;
}
.mathml-polyfill mover > *:nth-child(2), munderover > *:nth-child(3) {
font-size: 0.8em;
order: -1;
}
.mathml-polyfill munder {
vertical-align: text-top;
}
.mathml-polyfill mover {
vertical-align: text-bottom;
}
.mathml-polyfill munderover {
vertical-align: middle;
}

/* roots */
.mathml-polyfill msqrt, mroot {
display: inline-flex !important;
margin-left: .5em;
vertical-align: middle;
border-top: solid thin;
}
.mathml-polyfill msqrt:before, mroot:before {
margin-left: -.5em;
content: "\221A";
}
.mathml-polyfill mroot > *:nth-child(2) {
margin-right: .25em;
margin-left: -.75em;
font-size: 0.8em;
order: -1;
}

/* menclose */
.mathml-polyfill menclose {
display: inline-table !important;
border-collapse: separate;
border-spacing: 0.4ex 0;
}
.mathml-polyfill menclose[notation*="top"], menclose[notation*="actuarial"] {
border-top: solid thin;
}
.mathml-polyfill menclose[notation*="bottom"], menclose[notation*="madruwb"] {
border-bottom: solid thin;
}
menclose[notation*="right"], menclose[notation*="actuarial"],
.mathml-polyfill menclose[notation*="madruwb"] {
border-right: solid thin;
}
.mathml-polyfill menclose[notation*="left"] {
border-left: solid thin;
}
menclose[notation*="box"], menclose[notation*="roundedbox"],
.mathml-polyfill menclose[notation*="circle"] {
border: solid thin;
}
.mathml-polyfill menclose[notation*="roundedbox"] {
border-radius: 15%;
}
.mathml-polyfill menclose[notation*="circle"] {
border-radius: 50%;
}
.mathml-polyfill menclose[notation*="horizontalstrike"] {
text-decoration: line-through;
}

/* table */
.mathml-polyfill mtable {
display: inline-table !important;
vertical-align: middle;
text-align: center;
}
.mathml-polyfill mtr {
display: table-row !important;
}
.mathml-polyfill mtd {
display: table-cell !important;
padding: 0 0.5ex;
}

/* token elements */
.mathml-polyfill mspace {
margin: .2em;
}
.mathml-polyfill mi {
font-style: italic;
}
.mathml-polyfill mo {
margin-right: .2em;
margin-left: .2em;
}
.mathml-polyfill ms:before, ms:after {
content:"\0022";
}
.mathml-polyfill ms[lquote]:before {
content: attr(lquote);
}
.mathml-polyfill ms[rquote]:after {
content: attr(rquote);
}

/* mathvariants */
.mathml-polyfill [mathvariant="bold"],
.mathml-polyfill [mathvariant="bold-italic"],
.mathml-polyfill [mathvariant="bold-sans-serif"], [mathvariant="sans-serif-bold-italic"] {
font-weight: bold;
font-style: normal;
}
.mathml-polyfill [mathvariant="monospace"] {
font-family: monospace;
font-style: normal;
}
.mathml-polyfill [mathvariant="sans-serif"],
.mathml-polyfill [mathvariant="bold-sans-serif"],
.mathml-polyfill [mathvariant="sans-serif-italic"],
.mathml-polyfill [mathvariant="sans-serif-bold-italic"] {
font-family: sans-serif;
font-style: normal;
}
.mathml-polyfill [mathvariant="italic"],
.mathml-polyfill [mathvariant="bold-italic"],
.mathml-polyfill [mathvariant="sans-serif-italic"], [mathvariant="sans-serif-bold-italic"] {
font-style: italic;
}
.mathml-polyfill [mathvariant="normal"] {
font-style: normal;
}

/* mphantom */
.mathml-polyfill mphantom {
visibility: hidden;
}

/* merror */
.mathml-polyfill merror {
outline: solid thin red;
}
.mathml-polyfill merror:before {
content: "Error: ";
}

/* annotations */
.mathml-polyfill semantics > *:first-child {
display: inline;
}
.mathml-polyfill annotation, annotation-xml {
font-family: monospace;
display: none !important;
}
.mathml-polyfill math:active > semantics > *:first-child,
.mathml-polyfill math:active > semantics > *:first-child {
display: none !important;
}
.mathml-polyfill math:active annotation:first-of-type {
display: inline !important;
}
15 changes: 15 additions & 0 deletions packages/client/src/utils/mathml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default function() {
// First check whether the page contains any <math> element.
const namespaceURI = "http://www.w3.org/1998/Math/MathML";

// Create a div to test mspace, using Kuma's "offscreen" CSS
document.body.insertAdjacentHTML("afterbegin", "<div style='border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px;'><math xmlns='" + namespaceURI + "'><mspace height='23px' width='77px'></mspace></math></div>");
const div = document.body.firstChild;
const box = div.firstChild.firstChild.getBoundingClientRect();
document.body.removeChild(div);

if (Math.abs(box.height - 23) > 1 || Math.abs(box.width - 77) > 1) {
document.body.className += ' mathml-polyfill';
}
}

3 changes: 2 additions & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
"@koa/cors": "^3.1.0",
"akismet": "^2.0.6",
"jsonwebtoken": "^8.5.1",
"katex": "^0.12.0",
"leancloud-storage": "^4.7.0",
"marked": "^1.2.3",
"marked": "^1.2.5",
"nodemailer": "^6.4.15",
"nunjucks": "^3.2.2",
"phpass": "^0.1.1",
Expand Down
32 changes: 26 additions & 6 deletions packages/server/src/controller/comment.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const helper = require('think-helper');
const marked = require('marked');
const katext = require('katex');
const parser = require('ua-parser-js');
const BaseRest = require('./rest');
const akismet = require('../service/akismet');
Expand All @@ -16,13 +17,30 @@ marked.setOptions({
smartypants: true
});

function formatCmt({ua, ip, ...comment}) {
async function formatCmt({ua, ip, ...comment}) {
ua = parser(ua)
comment.mail = helper.md5(comment.mail);
if(!think.config('disableUserAgent')) {
comment.browser = ua.browser.name + ' ' + ua.browser.version;
comment.os = ua.os.name + ' ' + ua.os.version;
}

const blockMathRegExp = /(^|[\r\n]+|<p>|<br>)\$\$([^$]+)\$\$([\r\n]+|<\/p>|<br>|$)/g;
const match = comment.comment.match(blockMathRegExp);
if(match) {
for(let i = 0; i < match.length; i++) {
const text = match[i]
.replace(/(^|[\r\n]+|<p>|<br>)\$\$/, '')
.replace(/\$\$([\r\n]+|<\/p>|<br>|$)/, '')
.replace(/<br>/g, '\r\n');

const math = katext.renderToString(text, {
output: 'mathml'
});
comment.comment = comment.comment.replace(match[i], math);
}
}

return comment;
}

Expand Down Expand Up @@ -121,11 +139,13 @@ module.exports = class extends BaseRest {
page,
totalPages: Math.ceil(rootCount / pageSize),
pageSize,
data: rootComments.map(comment => {
const cmt = formatCmt(comment);
cmt.children = childrenComments.filter(comment => comment.rid === cmt.objectId).map(cmt => formatCmt(cmt));
data: await Promise.all(rootComments.map(async comment => {
const cmt = await formatCmt(comment);
cmt.children = await Promise.all(childrenComments
.filter(comment => comment.rid === cmt.objectId)
.map(cmt => formatCmt(cmt)));
return cmt;
})
}))
});
}
}
Expand Down Expand Up @@ -203,7 +223,7 @@ module.exports = class extends BaseRest {
}

await this.hook('postSave', resp, pComment);
return this.success(formatCmt(resp));
return this.success(await formatCmt(resp));
}

async putAction() {
Expand Down

0 comments on commit 9518679

Please sign in to comment.