Skip to content

Commit

Permalink
fix: mermaid will render a plain text on DOM target when secondary re…
Browse files Browse the repository at this point in the history
…nder happens, reference: mermaid-js/mermaid#311 (comment)
  • Loading branch information
suxin1 committed Apr 1, 2023
1 parent 58ea174 commit 2c05994
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 384 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
### Meidt
<h1 align="center">Medit</h1>

A browser based Markdown editor.
<p align="center">This libray is extracted from <a href="https://github.com/marktext/marktext">Marktext</a>. Thanks to their hard work.</p>
30 changes: 30 additions & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module.exports = {
parserPreset: {
parserOpts: {
headerPattern: /^(\w*)(?:\((.*)\))?:[ ]?(.*)$/,
headerCorrespondence: ['type', 'scope', 'subject']
}
},
rules: {
'type-empty': [2, 'never'],
'type-case': [2, 'always', 'lower-case'],
'subject-empty': [2, 'never'],
'type-enum': [
2,
'always',
[
'build',
'ci',
'chore',
'docs',
'feat',
'fix',
'perf',
'refactor',
'revert',
'style',
'test'
]
]
}
}
4 changes: 4 additions & 0 deletions lib/contentState/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,11 @@ class ContentState {
})
this.setNextRenderRange()
this.stateRender.collectLabels(blocks)
console.log("[ContentState::render]: blocks", blocks);

this.stateRender.render(blocks, activeBlocks, matches)
if (isRenderCursor) {
console.log("[ContentState::render] setCursor")
this.setCursor()
} else {
this.muya.blur()
Expand Down Expand Up @@ -269,6 +272,7 @@ class ContentState {
this.stateRender.collectLabels(blocks)
this.stateRender.partialRender(blocksToRender, activeBlocks, matches, startKey, endKey)
if (isRenderCursor) {
console.log("[ContentState:partialRender] setCursor")
this.setCursor()
} else {
this.muya.blur()
Expand Down
2 changes: 1 addition & 1 deletion lib/eventHandler/clickEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class ClickEvent {
end
}
}

console.log("[contextClickBingding]:Context clicked, set curser to: ", contentState.cursor, " and dispatch 'contextmenu' event.")
const sectionChanges = contentState.selectionChange(contentState.cursor)
eventCenter.dispatch('contextmenu', event, sectionChanges)
}
Expand Down
57 changes: 32 additions & 25 deletions lib/parser/render/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import loadRenderer from '../../renderers'
import { CLASS_OR_ID, PREVIEW_DOMPURIFY_CONFIG } from '../../config'
import { conflict, mixins, camelToSnake, sanitize } from '../../utils'
import { patch, toVNode, toHTML, h } from './snabbdom'
import { beginRules } from '../rules'
import {CLASS_OR_ID, PREVIEW_DOMPURIFY_CONFIG} from '../../config'
import {conflict, mixins, camelToSnake, sanitize} from '../../utils'
import {patch, toVNode, toHTML, h} from './snabbdom'
import {beginRules} from '../rules'
import renderInlines from './renderInlines'
import renderBlock from './renderBlock'

class StateRender {
constructor (muya) {
constructor(muya) {
this.muya = muya
this.eventCenter = muya.eventCenter
this.codeCache = new Map()
Expand All @@ -23,16 +23,16 @@ class StateRender {
this.container = null
}

setContainer (container) {
setContainer(container) {
this.container = container
}

// collect link reference definition
collectLabels (blocks) {
collectLabels(blocks) {
this.labels.clear()

const travel = block => {
const { text, children } = block
const {text, children} = block
if (children && children.length) {
children.forEach(c => travel(c))
} else if (text) {
Expand All @@ -52,10 +52,10 @@ class StateRender {
blocks.forEach(b => travel(b))
}

checkConflicted (block, token, cursor) {
const { start, end } = cursor
checkConflicted(block, token, cursor) {
const {start, end} = cursor
const key = block.key
const { start: tokenStart, end: tokenEnd } = token.range
const {start: tokenStart, end: tokenEnd} = token.range

if (key !== start.key && key !== end.key) {
return false
Expand All @@ -69,16 +69,16 @@ class StateRender {
}
}

getClassName (outerClass, block, token, cursor) {
getClassName(outerClass, block, token, cursor) {
return outerClass || (this.checkConflicted(block, token, cursor) ? CLASS_OR_ID.AG_GRAY : CLASS_OR_ID.AG_HIDE)
}

getHighlightClassName (active) {
getHighlightClassName(active) {
return active ? CLASS_OR_ID.AG_HIGHLIGHT : CLASS_OR_ID.AG_SELECTION
}

getSelector (block, activeBlocks) {
const { cursor, selectedBlock } = this.muya.contentState
getSelector(block, activeBlocks) {
const {cursor, selectedBlock} = this.muya.contentState
const type = block.type === 'hr' ? 'p' : block.type
const isActive = activeBlocks.some(b => b.key === block.key) || block.key === cursor.start.key

Expand All @@ -95,22 +95,29 @@ class StateRender {
return selector
}

async renderMermaid () {
async renderMermaid() {
if (this.mermaidCache.size) {
console.log("[StateRender:renderMermaid]: start");

const mermaid = await loadRenderer('mermaid')
mermaid.initialize({
securityLevel: 'strict',
theme: this.muya.options.mermaidTheme
})
for (const [key, value] of this.mermaidCache.entries()) {
const { code } = value
const {code} = value
const target = document.querySelector(key)
if (!target) {
continue
}
try {
mermaid.parse(code)
target.innerHTML = sanitize(code, PREVIEW_DOMPURIFY_CONFIG, true)
// mermaid will not render if DOM target has data-processed attribute set to true,
// so we need to remove it here.
if (target.getAttribute('data-processed') === 'true') {
target.removeAttribute("data-processed");
}
mermaid.init(undefined, target)
} catch (err) {
target.innerHTML = '< Invalid Mermaid Codes >'
Expand All @@ -122,7 +129,7 @@ class StateRender {
}
}

async renderDiagram () {
async renderDiagram() {
const cache = this.diagramCache
if (cache.size) {
const RENDER_MAP = {
Expand All @@ -137,11 +144,11 @@ class StateRender {
if (!target) {
continue
}
const { code, functionType } = value
const {code, functionType} = value
const render = RENDER_MAP[functionType]
const options = {}
if (functionType === 'sequence') {
Object.assign(options, { theme: this.muya.options.sequenceTheme })
Object.assign(options, {theme: this.muya.options.sequenceTheme})
} else if (functionType === 'vega-lite') {
Object.assign(options, {
actions: false,
Expand Down Expand Up @@ -171,7 +178,7 @@ class StateRender {
}
}

render (blocks, activeBlocks, matches) {
render(blocks, activeBlocks, matches) {
const selector = `div#${CLASS_OR_ID.AG_EDITOR_ID}`
const children = blocks.map(block => {
return this.renderBlock(null, block, activeBlocks, matches, true)
Expand All @@ -187,7 +194,7 @@ class StateRender {
}

// Only render the blocks which you updated
partialRender (blocks, activeBlocks, matches, startKey, endKey) {
partialRender(blocks, activeBlocks, matches, startKey, endKey) {
const cursorOutMostBlock = activeBlocks[activeBlocks.length - 1]
// If cursor is not in render blocks, need to render cursor block independently
const needRenderCursorBlock = blocks.indexOf(cursorOutMostBlock) === -1
Expand Down Expand Up @@ -216,7 +223,7 @@ class StateRender {

// Render cursor block independently
if (needRenderCursorBlock) {
const { key } = cursorOutMostBlock
const {key} = cursorOutMostBlock
const cursorDom = document.querySelector(`#${key}`)
if (cursorDom) {
const oldCursorVnode = toVNode(cursorDom)
Expand All @@ -237,7 +244,7 @@ class StateRender {
* @param {array} activeBlocks
* @param {array} matches
*/
singleRender (block, activeBlocks, matches) {
singleRender(block, activeBlocks, matches) {
const selector = `#${block.key}`
const newVdom = this.renderBlock(null, block, activeBlocks, matches, true)
const rootDom = document.querySelector(selector)
Expand All @@ -248,7 +255,7 @@ class StateRender {
this.codeCache.clear()
}

invalidateImageCache () {
invalidateImageCache() {
this.loadImageMap.forEach((imageInfo, key) => {
imageInfo.touchMsec = Date.now()
this.loadImageMap.set(key, imageInfo)
Expand Down
7 changes: 5 additions & 2 deletions lib/parser/render/snabbdom.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ export const patch = init([
eventListenersModule
])

export const h = sh
export const toVNode = sToVNode

export const h = sh // for create virtual dom

export const toVNode = sToVNode // converting a DOM element to a virtual node

export const toHTML = require('snabbdom-to-html') // helper function for convert vnode to HTML string

export const htmlToVNode = html => { // helper function for convert html to vnode
const wrapper = document.createElement('div')
wrapper.innerHTML = html
Expand Down
2 changes: 1 addition & 1 deletion lib/renderers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const loadRenderer = async (name) => {
rendererCache.set(name, m.default)
break
case 'mermaid':
m = await import('mermaid/dist/mermaid.core.js')
m = await import('mermaid/dist/mermaid.core.mjs')
rendererCache.set(name, m.default)
break
case 'vega-lite':
Expand Down
26 changes: 26 additions & 0 deletions lib/selection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Some Knowledge to know before you start

### Node Type
- 1: Element node
- 2: Attribute node
- 3: Text node
- 4: CDATA section node
- 5: Entity Reference node
- 6: Entity node
- 7: Processing Instruction node
- 8: Comment node
- 9: Document node
- 10: Document Type node
- 11: Document Fragment node
- 12: Notation node

### Range.setStart() and Range.setEnd()
If the `node` argument passed to `setStart()` is a text node, the `startOffset` value is the index of the first
character in the text node that should be included in the range. For example, if `node` is a text node containing
the string "Hello, world", and `startOffset` is 3, then the range would start with the fourth character in the
text node, which is the letter "l"

If the `node` argument is an element node, the `startOffset` value is the index of the child node within the
element that should be the start of the range. For example, if `node` is an unordered list (`<ul>`) element with
three list items (`<li>`), and `startOffset` is 2, then the range would start with the third `<li>` child element
within the `<ul>`. translate this to chinese
Loading

0 comments on commit 2c05994

Please sign in to comment.