diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json
index 5351bb15c..a96fb7ca6 100644
--- a/app/appearance/langs/en_US.json
+++ b/app/appearance/langs/en_US.json
@@ -491,7 +491,7 @@
"sync": "Sync",
"syncNow": "Sync now",
"cloudBook": "Cloud Notebook",
- "payment": "Payment",
+ "paymentSum": "Cumulatively paid",
"refresh": "Refresh",
"accountManage": "Account Manage",
"logout": "Logout",
diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json
index 2de0a1e0d..58bc50bcc 100644
--- a/app/appearance/langs/es_ES.json
+++ b/app/appearance/langs/es_ES.json
@@ -491,7 +491,7 @@
"sync": "Sincronización",
"syncNow": "Sincronizar ahora",
"cloudBook": "Cuaderno de notas en la nube",
- "payment": "Pago",
+ "paymentSum": "Pagado acumulativamente",
"refresh": "Actualizar",
"accountManage": "Gestión de la cuenta",
"logout": "Cierre de sesión",
diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json
index 4341373d5..38c40bf85 100644
--- a/app/appearance/langs/fr_FR.json
+++ b/app/appearance/langs/fr_FR.json
@@ -491,7 +491,7 @@
"sync": "Synchro",
"syncNow": "Synchro maintenant",
"cloudBook": "Carnet de notes du Cloud",
- "payment": "Paiement",
+ "paymentSum": "Cumulativement payé",
"refresh": "Rafraîchir",
"accountManage": "Gestion des comptes",
"logout": "Se déconnecter",
diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json
index 77dd74c44..dba8420f9 100644
--- a/app/appearance/langs/zh_CHT.json
+++ b/app/appearance/langs/zh_CHT.json
@@ -491,7 +491,7 @@
"sync": "同步",
"syncNow": "立即同步",
"cloudBook": "雲端筆記本",
- "payment": "支付",
+ "payment": "累計已支付",
"refresh": "重新整理",
"accountManage": "帳號管理",
"logout": "登出",
diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json
index 5072ac245..39c486736 100644
--- a/app/appearance/langs/zh_CN.json
+++ b/app/appearance/langs/zh_CN.json
@@ -491,7 +491,7 @@
"sync": "同步",
"syncNow": "立即同步",
"cloudBook": "云端笔记本",
- "payment": "支付",
+ "paymentSum": "累计已支付",
"refresh": "刷新",
"accountManage": "账号管理",
"logout": "登出",
diff --git a/app/src/config/account.ts b/app/src/config/account.ts
index 76e245c3b..adb9eec90 100644
--- a/app/src/config/account.ts
+++ b/app/src/config/account.ts
@@ -112,7 +112,7 @@ ${window.siyuan.languages.account8}`;
-
${window.siyuan.languages.payment}
+
${window.siyuan.languages.paymentSum}
${window.siyuan.user.userPaymentSum} RMB
diff --git a/kernel/model/export.go b/kernel/model/export.go
index 3c659d57e..75da2873b 100644
--- a/kernel/model/export.go
+++ b/kernel/model/export.go
@@ -196,7 +196,7 @@ func exportData(exportFolder string) (err error) {
func Preview(id string) string {
tree, _ := loadTreeByBlockID(id)
- tree = exportTree(tree, false)
+ tree = exportTree(tree, false, false)
luteEngine := NewLute()
luteEngine.SetFootnotes(true)
md := treenode.FormatNode(tree.Root, luteEngine)
@@ -250,7 +250,7 @@ func ExportDocx(id, savePath string, removeAssets bool) (err error) {
func ExportMarkdownHTML(id, savePath string, docx bool) (name, dom string) {
tree, _ := loadTreeByBlockID(id)
- tree = exportTree(tree, true)
+ tree = exportTree(tree, true, true)
name = path.Base(tree.HPath)
name = util.FilterFileName(name) // 导出 PDF、HTML 和 Word 时未移除不支持的文件名符号 https://github.com/siyuan-note/siyuan/issues/5614
@@ -362,7 +362,7 @@ func ExportHTML(id, savePath string, pdf bool) (name, dom string) {
}
}
- tree = exportTree(tree, true)
+ tree = exportTree(tree, true, true)
//if pdf { // TODO: 导出 PDF 时块引转换脚注使用书签跳转 https://github.com/siyuan-note/siyuan/issues/5761
// var footnotesDefs []*ast.Node
// ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
@@ -590,7 +590,7 @@ func AddPDFOutline(id, p string) (err error) {
func CopyStdMarkdown(id string) string {
tree, _ := loadTreeByBlockID(id)
- tree = exportTree(tree, false)
+ tree = exportTree(tree, false, false)
luteEngine := NewLute()
luteEngine.SetFootnotes(true)
luteEngine.SetKramdownIAL(false)
@@ -914,7 +914,7 @@ func ExportMarkdownContent(id string) (hPath, exportedMd string) {
func exportMarkdownContent(id string) (hPath, exportedMd string) {
tree, _ := loadTreeByBlockID(id)
hPath = tree.HPath
- tree = exportTree(tree, false)
+ tree = exportTree(tree, false, true)
luteEngine := NewLute()
luteEngine.SetFootnotes(true)
luteEngine.SetKramdownIAL(false)
@@ -980,6 +980,65 @@ func renderExportMdInlineMathContent(r *render.FormatRenderer, node *ast.Node, e
return ast.WalkContinue
}
+func processKaTexMacros(n *ast.Node) {
+ if ast.NodeInlineMathContent != n.Type && ast.NodeMathBlockContent != n.Type {
+ return
+ }
+
+ mathContent := n.Tokens
+ macros := map[string]string{}
+ if err := gulu.JSON.UnmarshalJSON([]byte(Conf.Editor.KaTexMacros), ¯os); nil != err {
+ logging.LogWarnf("parse katex macros failed: %s", err)
+ return
+ }
+
+ var keys []string
+ for k, _ := range macros {
+ keys = append(keys, k)
+ }
+
+ useMacro := false
+ for k, _ := range macros {
+ if bytes.Contains(mathContent, []byte(k)) {
+ useMacro = true
+ break
+ }
+ }
+ if !useMacro {
+ return
+ }
+
+ usedMacros := extractUsedMacros(mathContent, macros)
+ newcommandBuf := bytes.Buffer{}
+ for _, usedMacro := range usedMacros {
+ expanded := resolveKaTexMacro(usedMacro, ¯os, &keys)
+ newcommandBuf.WriteString("\\newcommand" + usedMacro + "{" + expanded + "}\n")
+ }
+ newcommandBuf.WriteString("\n")
+ mathContent = append(newcommandBuf.Bytes(), mathContent...)
+ n.Tokens = mathContent
+}
+
+func extractUsedMacros(mathContent []byte, macros map[string]string) (ret []string) {
+ for macro, _ := range macros {
+ if bytes.Contains(mathContent, []byte(macro)) {
+ ret = append(ret, macro)
+ }
+ }
+ return
+}
+
+func resolveKaTexMacro(macroName string, macros *map[string]string, keys *[]string) string {
+ v := (*macros)[macroName]
+ for _, k := range *keys {
+ if strings.Contains(v, k) {
+ v = strings.ReplaceAll(v, k, resolveKaTexMacro(k, macros, keys))
+ (*macros)[macroName] = v
+ }
+ }
+ return v
+}
+
func renderExportMdParagraph(r *render.FormatRenderer, node *ast.Node, entering bool) ast.WalkStatus {
if entering {
if r.Options.ChineseParagraphBeginningSpace && ast.NodeDocument == node.Parent.Type {
@@ -1034,7 +1093,7 @@ func withoutKramdownBlockIAL(r *render.FormatRenderer, node *ast.Node) bool {
return !r.Options.KramdownBlockIAL || 0 == len(node.KramdownIAL)
}
-func exportTree(tree *parse.Tree, wysiwyg bool) (ret *parse.Tree) {
+func exportTree(tree *parse.Tree, wysiwyg, expandKaTexMacros bool) (ret *parse.Tree) {
luteEngine := NewLute()
ret = tree
id := tree.Root.ID
@@ -1286,6 +1345,10 @@ func exportTree(tree *parse.Tree, wysiwyg bool) (ret *parse.Tree) {
}
}
+ if expandKaTexMacros && (ast.NodeInlineMathContent == n.Type || ast.NodeMathBlockContent == n.Type) {
+ processKaTexMacros(n)
+ }
+
if ast.NodeWidget == n.Type {
// 挂件块导出 https://github.com/siyuan-note/siyuan/issues/3834
exportMdVal := n.IALAttr("data-export-md")
diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go
index 54e182a8d..8bc11b866 100644
--- a/kernel/model/transaction.go
+++ b/kernel/model/transaction.go
@@ -904,6 +904,17 @@ func (tx *Transaction) doUpdate(operation *Operation) (ret *TxErr) {
treenode.MoveFoldHeading(updatedNode, oldNode)
}
+ // 挂件移动或设置大小后属性丢失 https://github.com/siyuan-note/siyuan/issues/4885
+ // 这里需要把旧节点的属性复制到新节点上,避免属性丢失
+ oldIAL := parse.IAL2Map(oldNode.KramdownIAL)
+ newIAL := parse.IAL2Map(updatedNode.KramdownIAL)
+ for oldIALKey, oldIALVal := range oldIAL {
+ if strings.HasPrefix(oldIALKey, "custom-") {
+ newIAL[oldIALKey] = oldIALVal
+ }
+ }
+ updatedNode.KramdownIAL = parse.Map2IAL(newIAL)
+
cache.PutBlockIAL(updatedNode.ID, parse.IAL2Map(updatedNode.KramdownIAL))
// 替换为新节点