Add mathjax

This commit is contained in:
Ben Visness 2021-06-20 14:06:22 -05:00
parent 4d9ef5917e
commit 085bd46440
8 changed files with 164 additions and 5 deletions

1
public/mathjax.js Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

136
src/parsing/mathjax.go Normal file
View File

@ -0,0 +1,136 @@
package parsing
import (
gohtml "html"
"strings"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
gast "github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
// ----------------------
// Parser and delimiters
// ----------------------
type mathjaxParser struct{}
var _ parser.BlockParser = mathjaxParser{}
func (s mathjaxParser) Trigger() []byte {
return []byte{'$'}
}
func (s mathjaxParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) {
line, _ := reader.PeekLine()
lineStr := strings.TrimSpace(string(line))
if lineStr == "$$" {
return NewMathjax(), parser.NoChildren
} else {
return nil, parser.NoChildren
}
}
func (s mathjaxParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State {
line, _ := reader.PeekLine()
lineStr := strings.TrimSpace(string(line))
if lineStr == "$$" {
reader.Advance(len(line))
return parser.Close
}
node.(*MathjaxNode).Source += string(line)
return parser.Continue | parser.NoChildren
}
func (s mathjaxParser) Close(node ast.Node, reader text.Reader, pc parser.Context) {}
func (s mathjaxParser) CanInterruptParagraph() bool {
return true
}
func (s mathjaxParser) CanAcceptIndentedLine() bool {
return false
}
// ----------------------
// AST node
// ----------------------
type MathjaxNode struct {
gast.BaseBlock
Source string
}
var _ gast.Node = &MathjaxNode{}
func (n *MathjaxNode) Dump(source []byte, level int) {
gast.DumpHelper(n, source, level, nil, nil)
}
var KindMathjax = gast.NewNodeKind("Mathjax")
func (n *MathjaxNode) Kind() gast.NodeKind {
return KindMathjax
}
func NewMathjax() *MathjaxNode {
return &MathjaxNode{}
}
// ----------------------
// Renderer
// ----------------------
type MathjaxHTMLRenderer struct {
html.Config
}
func NewMathjaxHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
r := &MathjaxHTMLRenderer{
Config: html.NewConfig(),
}
for _, opt := range opts {
opt.SetHTMLOption(&r.Config)
}
return r
}
func (r *MathjaxHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(KindMathjax, r.renderMathjax)
}
func (r *MathjaxHTMLRenderer) renderMathjax(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) {
if entering {
w.WriteString("<div>\n")
w.WriteString("$$\n")
w.WriteString(gohtml.EscapeString(n.(*MathjaxNode).Source))
w.WriteString("$$\n")
w.WriteString("</div>\n")
}
return gast.WalkSkipChildren, nil
}
// ----------------------
// Extension
// ----------------------
type MathjaxExtension struct {
Preview bool
}
func (e MathjaxExtension) Extend(m goldmark.Markdown) {
m.Parser().AddOptions(parser.WithBlockParsers(
util.Prioritized(mathjaxParser{}, 500),
))
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(NewMathjaxHTMLRenderer(), 500),
))
}

View File

@ -97,6 +97,7 @@ var previewMarkdown = goldmark.New(
EmbedExtension{ EmbedExtension{
Preview: true, Preview: true,
}, },
MathjaxExtension{},
bTag{}, bTag{},
), ),
) )
@ -105,6 +106,7 @@ var realMarkdown = goldmark.New(
extension.GFM, extension.GFM,
SpoilerExtension{}, SpoilerExtension{},
EmbedExtension{}, EmbedExtension{},
MathjaxExtension{},
bTag{}, bTag{},
), ),
) )

View File

@ -49,7 +49,7 @@
<input type="submit" class="button ml2" name="preview" value="{{ .PreviewLabel }}" /> <input type="submit" class="button ml2" name="preview" value="{{ .PreviewLabel }}" />
</div> </div>
<div class="post post-preview mv3"> <div class="post post-preview mv3 mathjax">
<div id="preview" class="body contents"></div> <div id="preview" class="body contents"></div>
</div> </div>
@ -111,6 +111,7 @@
function updatePreview() { function updatePreview() {
const previewHtml = parseMarkdown(tf.value); const previewHtml = parseMarkdown(tf.value);
preview.innerHTML = previewHtml; preview.innerHTML = previewHtml;
MathJax.typeset();
} }
tf.addEventListener('input', () => { tf.addEventListener('input', () => {

View File

@ -38,7 +38,7 @@
{{ end }} {{ end }}
} }
</style> </style>
{{ block "extrahead" . }}{{ end }}
<link rel="stylesheet" href="{{ statictheme .Theme "theme.css" }}" /> <link rel="stylesheet" href="{{ statictheme .Theme "theme.css" }}" />
<link rel="stylesheet" href="{{ .ProjectCSSUrl }}" /> <link rel="stylesheet" href="{{ .ProjectCSSUrl }}" />
<link rel="apple-touch-icon" sizes="57x57" href="{{ static "apple-icon-57x57.png" }}"> <link rel="apple-touch-icon" sizes="57x57" href="{{ static "apple-icon-57x57.png" }}">
@ -58,6 +58,23 @@
<meta name="msapplication-TileColor" content="#ffffff"> <meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="{{ static "ms-icon-144x144.png" }}"> <meta name="msapplication-TileImage" content="{{ static "ms-icon-144x144.png" }}">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
{{ if .MathjaxEnabled }}
<script>
MathJax = {
tex: {
inlineMath: [['$', '$']],
displayMath: [['$$', '$$']],
},
svg: {
fontCache: 'global',
}
};
</script>
<script async src="{{ static "mathjax.js" }}"></script>
{{ end }}
{{ block "extrahead" . }}{{ end }}
</head> </head>
<body class="{{ join " " .BodyClasses }}"> <body class="{{ join " " .BodyClasses }}">

View File

@ -22,9 +22,10 @@ type BaseData struct {
User *User User *User
Session *Session Session *Session
IsProjectPage bool IsProjectPage bool
Header Header Header Header
Footer Footer Footer Footer
MathjaxEnabled bool
} }
type Header struct { type Header struct {

View File

@ -531,6 +531,7 @@ func ForumNewThread(c *RequestContext) ResponseData {
baseData := getBaseData(c) baseData := getBaseData(c)
baseData.Title = "Create New Thread" baseData.Title = "Create New Thread"
baseData.MathjaxEnabled = true
// TODO(ben): Set breadcrumbs // TODO(ben): Set breadcrumbs
var res ResponseData var res ResponseData