Feat:支持直接在富文本编辑框中编辑数学公式
This commit is contained in:
parent
8152fab185
commit
f996ec9bae
@ -332,5 +332,11 @@ export const defaultOpt = {
|
|||||||
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分
|
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分
|
||||||
createNodePrefixContent: null,
|
createNodePrefixContent: null,
|
||||||
// 添加附加的节点后置内容,后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分
|
// 添加附加的节点后置内容,后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分
|
||||||
createNodePostfixContent: null
|
createNodePostfixContent: null,
|
||||||
|
// 是否开启在富文本编辑框中直接编辑数学公式
|
||||||
|
enableEditFormulaInRichTextEdit: true,
|
||||||
|
// 转换富文本内容,当进入富文本编辑时,可以通过该参数传递一个函数,函数接收文本内容,需要返回你处理后的文本内容
|
||||||
|
transformRichTextOnEnterEdit: null,
|
||||||
|
// 可以传递一个函数,即将结束富文本编辑前会执行该函数,函数接收richText实例,所以你可以在此时机更新quill文档数据
|
||||||
|
beforeHideRichTextEdit: null
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,18 @@ class Formula {
|
|||||||
this.opt = opt
|
this.opt = opt
|
||||||
this.mindMap = opt.mindMap
|
this.mindMap = opt.mindMap
|
||||||
window.katex = katex
|
window.katex = katex
|
||||||
|
this.init()
|
||||||
this.extendQuill()
|
this.extendQuill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
if (this.mindMap.opt.enableEditFormulaInRichTextEdit) {
|
||||||
|
this.mindMap.opt.transformRichTextOnEnterEdit =
|
||||||
|
this.latexRichToText.bind(this)
|
||||||
|
this.mindMap.opt.beforeHideRichTextEdit = this.formatLatex.bind(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 获取katex配置
|
// 获取katex配置
|
||||||
getKatexConfig() {
|
getKatexConfig() {
|
||||||
const config = {
|
const config = {
|
||||||
@ -59,6 +68,74 @@ class Formula {
|
|||||||
richTextPlugin.setTextStyleIfNotRichText(richTextPlugin.node)
|
richTextPlugin.setTextStyleIfNotRichText(richTextPlugin.node)
|
||||||
richTextPlugin.hideEditText([node])
|
richTextPlugin.hideEditText([node])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将公式富文本转换为公式源码
|
||||||
|
latexRichToText(nodeText) {
|
||||||
|
if (nodeText.indexOf('class="ql-formula"') !== -1) {
|
||||||
|
const parser = new DOMParser()
|
||||||
|
const doc = parser.parseFromString(nodeText, 'text/html')
|
||||||
|
const els = doc.getElementsByClassName('ql-formula')
|
||||||
|
for (const el of els)
|
||||||
|
nodeText = nodeText.replace(
|
||||||
|
el.outerHTML,
|
||||||
|
`\$${el
|
||||||
|
.getAttribute('data-value')
|
||||||
|
.replaceAll('&', '&')
|
||||||
|
.replaceAll('<', '<')
|
||||||
|
.replaceAll('>', '>')}\$`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return nodeText
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用格式化的 latex 字符串内容更新 quill 内容:输入 $*****$
|
||||||
|
formatLatex(richText) {
|
||||||
|
const contents = richText.quill.getContents()
|
||||||
|
const ops = contents.ops
|
||||||
|
let mod = false
|
||||||
|
for (let i = ops.length - 1; i >= 0; i--) {
|
||||||
|
const op = ops[i]
|
||||||
|
const insert = op.insert
|
||||||
|
if (insert && typeof insert !== 'object' && insert !== '\n') {
|
||||||
|
if (/\$.+?\$/g.test(insert)) {
|
||||||
|
const m = [...insert.matchAll(/\$.+?\$/g)]
|
||||||
|
const arr = insert.split(/\$.+?\$/g)
|
||||||
|
for (let j = m.length - 1; j >= 0; j--) {
|
||||||
|
const exp = m[j]?.[0].slice(1, -1) ?? null // $...$ 之间的表达式
|
||||||
|
if (exp !== null && exp.trim().length > 0) {
|
||||||
|
const isLegal = this.checkFormulaIsLegal(exp)
|
||||||
|
if (isLegal) {
|
||||||
|
arr.splice(j + 1, 0, { insert: { formula: exp } }) // 添加到对应位置之后
|
||||||
|
mod = true
|
||||||
|
} else {
|
||||||
|
arr.splice(j + 1, 0, '')
|
||||||
|
}
|
||||||
|
} else arr.splice(j + 1, 0, '') // 表达式为空时,占位
|
||||||
|
}
|
||||||
|
while (arr.length > 0) {
|
||||||
|
let v = arr.pop()
|
||||||
|
if (typeof v === 'string') {
|
||||||
|
if (v.length < 1) continue
|
||||||
|
v = { insert: v }
|
||||||
|
}
|
||||||
|
v['attributes'] = ops[i]['attributes']
|
||||||
|
ops.splice(i + 1, 0, v)
|
||||||
|
}
|
||||||
|
ops.splice(i, 1) // 删除原来的字符串
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mod) richText.quill.setContents(contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkFormulaIsLegal(str) {
|
||||||
|
try {
|
||||||
|
katex.renderToString(str)
|
||||||
|
return true
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Formula.instanceName = 'formula'
|
Formula.instanceName = 'formula'
|
||||||
|
|||||||
@ -171,7 +171,8 @@ class RichText {
|
|||||||
customInnerElsAppendTo,
|
customInnerElsAppendTo,
|
||||||
nodeTextEditZIndex,
|
nodeTextEditZIndex,
|
||||||
textAutoWrapWidth,
|
textAutoWrapWidth,
|
||||||
selectTextOnEnterEditText
|
selectTextOnEnterEditText,
|
||||||
|
transformRichTextOnEnterEdit
|
||||||
} = this.mindMap.opt
|
} = this.mindMap.opt
|
||||||
this.node = node
|
this.node = node
|
||||||
this.isInserting = isInserting
|
this.isInserting = isInserting
|
||||||
@ -241,7 +242,10 @@ class RichText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 节点文本内容
|
// 节点文本内容
|
||||||
const nodeText = node.getData('text')
|
let nodeText = node.getData('text')
|
||||||
|
if (typeof transformRichTextOnEnterEdit === 'function') {
|
||||||
|
nodeText = transformRichTextOnEnterEdit(nodeText)
|
||||||
|
}
|
||||||
// 是否是空文本
|
// 是否是空文本
|
||||||
const isEmptyText = isUndef(nodeText)
|
const isEmptyText = isUndef(nodeText)
|
||||||
// 是否是非空的非富文本
|
// 是否是非空的非富文本
|
||||||
@ -325,6 +329,10 @@ class RichText {
|
|||||||
if (!this.showTextEdit) {
|
if (!this.showTextEdit) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const { beforeHideRichTextEdit } = this.mindMap.opt
|
||||||
|
if (typeof beforeHideRichTextEdit === 'function') {
|
||||||
|
beforeHideRichTextEdit(this)
|
||||||
|
}
|
||||||
let html = this.getEditText()
|
let html = this.getEditText()
|
||||||
let list =
|
let list =
|
||||||
nodes && nodes.length > 0 ? nodes : this.mindMap.renderer.activeNodeList
|
nodes && nodes.length > 0 ? nodes : this.mindMap.renderer.activeNodeList
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user