Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wiki-js
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
wiki-js
Commits
830f5166
Commit
830f5166
authored
Mar 06, 2020
by
NGPixel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: katex in markdown preview + xss fix for svg
parent
43985736
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
175 additions
and
2 deletions
+175
-2
katex.js
client/components/editor/common/katex.js
+140
-0
editor-markdown.vue
client/components/editor/editor-markdown.vue
+33
-0
renderer.js
server/modules/rendering/html-security/renderer.js
+2
-2
No files found.
client/components/editor/common/katex.js
0 → 100644
View file @
830f5166
// Test if potential opening or closing delimieter
// Assumes that there is a "$" at state.src[pos]
function
isValidDelim
(
state
,
pos
)
{
let
prevChar
let
nextChar
let
max
=
state
.
posMax
let
canOpen
=
true
let
canClose
=
true
prevChar
=
pos
>
0
?
state
.
src
.
charCodeAt
(
pos
-
1
)
:
-
1
nextChar
=
pos
+
1
<=
max
?
state
.
src
.
charCodeAt
(
pos
+
1
)
:
-
1
// Check non-whitespace conditions for opening and closing, and
// check that closing delimeter isn't followed by a number
if
(
prevChar
===
0x20
/* " " */
||
prevChar
===
0x09
/* \t */
||
(
nextChar
>=
0x30
/* "0" */
&&
nextChar
<=
0x39
/* "9" */
))
{
canClose
=
false
}
if
(
nextChar
===
0x20
/* " " */
||
nextChar
===
0x09
/* \t */
)
{
canOpen
=
false
}
return
{
canOpen
:
canOpen
,
canClose
:
canClose
}
}
export
default
{
katexInline
(
state
,
silent
)
{
let
start
,
match
,
token
,
res
,
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
}
// First check for and bypass all properly escaped delimieters
// This loop will assume that the first leading backtick can not
// be the first character in state.src, which is known since
// we have found an opening delimieter already.
start
=
state
.
pos
+
1
match
=
start
while
((
match
=
state
.
src
.
indexOf
(
'$'
,
match
))
!==
-
1
)
{
// Found potential $, look for escapes, pos will point to
// first non escape when complete
pos
=
match
-
1
while
(
state
.
src
[
pos
]
===
'
\
\'
) { pos -= 1 }
// Even number of escapes, potential closing delimiter found
if (((match - pos) % 2) === 1) { break }
match += 1
}
// No closing delimter found. Consume $ and continue.
if (match === -1) {
if (!silent) { state.pending += '
$
' }
state.pos = start
return true
}
// Check if we have empty content, ie: $$. Do not parse.
if (match - start === 0) {
if (!silent) { state.pending += '
$$
' }
state.pos = start + 1
return true
}
// Check for valid closing delimiter
res = isValidDelim(state, match)
if (!res.canClose) {
if (!silent) { state.pending += '
$
' }
state.pos = start
return true
}
if (!silent) {
token = state.push('
katex_inline
', '
math
', 0)
token.markup = '
$
'
token.content = state.src.slice(start, match)
}
state.pos = match + 1
return true
},
katexBlock (state, start, end, silent) {
let firstLine; let lastLine; let next; let lastPos; let found = false; let token
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
firstLine = state.src.slice(pos, max)
if (silent) { return true }
if (firstLine.trim().slice(-2) === '
$$
') {
// Single line expression
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) {
// non-empty line with negative indent should stop the list:
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
token = state.push('
katex_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
}
}
client/components/editor/editor-markdown.vue
View file @
830f5166
...
...
@@ -214,10 +214,14 @@ import mdSup from 'markdown-it-sup'
import
mdSub
from
'markdown-it-sub'
import
mdMark
from
'markdown-it-mark'
import
mdImsize
from
'markdown-it-imsize'
import
katex
from
'katex'
// Prism (Syntax Highlighting)
import
Prism
from
'prismjs'
// Helpers
import
katexHelper
from
'./common/katex'
// ========================================
// INIT
// ========================================
...
...
@@ -279,6 +283,35 @@ md.renderer.rules.heading_open = injectLineNumbers
md
.
renderer
.
rules
.
blockquote_open
=
injectLineNumbers
// ========================================
// KATEX
// ========================================
md
.
inline
.
ruler
.
after
(
'escape'
,
'katex_inline'
,
katexHelper
.
katexInline
)
md
.
renderer
.
rules
.
katex_inline
=
(
tokens
,
idx
)
=>
{
try
{
return
katex
.
renderToString
(
tokens
[
idx
].
content
,
{
displayMode
:
false
}
)
}
catch
(
err
)
{
console
.
warn
(
err
)
return
tokens
[
idx
].
content
}
}
md
.
block
.
ruler
.
after
(
'blockquote'
,
'katex_block'
,
katexHelper
.
katexBlock
,
{
alt
:
[
'paragraph'
,
'reference'
,
'blockquote'
,
'list'
]
}
)
md
.
renderer
.
rules
.
katex_block
=
(
tokens
,
idx
)
=>
{
try
{
return
`<p>`
+
katex
.
renderToString
(
tokens
[
idx
].
content
,
{
displayMode
:
true
}
)
+
`</p>`
}
catch
(
err
)
{
console
.
warn
(
err
)
return
tokens
[
idx
].
content
}
}
// ========================================
// Vue Component
// ========================================
...
...
server/modules/rendering/html-security/renderer.js
View file @
830f5166
...
...
@@ -29,10 +29,10 @@ module.exports = {
path
:
[
'd'
,
'style'
],
pre
:
[
'class'
,
'style'
],
section
:
[
'class'
,
'style'
],
span
:
[
'class'
,
'style'
],
span
:
[
'class'
,
'style'
,
'aria-hidden'
],
strong
:
[
'class'
,
'style'
],
summary
:
[
'class'
,
'style'
],
svg
:
[
'width'
,
'height'
,
'view
Box'
,
'preserveAspectR
atio'
,
'style'
],
svg
:
[
'width'
,
'height'
,
'view
box'
,
'preserveaspectr
atio'
,
'style'
],
table
:
[
'border'
,
'class'
,
'id'
,
'style'
,
'width'
],
tbody
:
[
'class'
,
'style'
],
td
:
[
'align'
,
'class'
,
'colspan'
,
'rowspan'
,
'style'
,
'valign'
],
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment