${window.siyuan.languages.syncInterval}
${window.siyuan.languages.syncIntervalTip}
@@ -477,9 +477,12 @@ export const repos = {
fetchPost("/api/sync/setSyncMode", {mode: parseInt(syncModeElement.value, 10)}, () => {
if (syncModeElement.value === "1" && window.siyuan.config.sync.provider === 0 && window.siyuan.config.system.container !== "docker") {
syncPerceptionElement.parentElement.classList.remove("fn__none");
- syncIntervalElement.parentElement.classList.remove("fn__none");
} else {
syncPerceptionElement.parentElement.classList.add("fn__none");
+ }
+ if (syncModeElement.value === "1") {
+ syncIntervalElement.parentElement.classList.remove("fn__none");
+ } else {
syncIntervalElement.parentElement.classList.add("fn__none");
}
window.siyuan.config.sync.mode = parseInt(syncModeElement.value, 10);
@@ -502,9 +505,12 @@ export const repos = {
syncConfigElement.classList.add("fn__none");
if (window.siyuan.config.sync.mode !== 1 || window.siyuan.config.system.container === "docker" || window.siyuan.config.sync.provider !== 0) {
syncPerceptionElement.parentElement.classList.add("fn__none");
- syncIntervalElement.parentElement.classList.add("fn__none");
} else {
syncPerceptionElement.parentElement.classList.remove("fn__none");
+ }
+ if (window.siyuan.config.sync.mode !== 1) {
+ syncIntervalElement.parentElement.classList.add("fn__none");
+ } else {
syncIntervalElement.parentElement.classList.remove("fn__none");
}
});
diff --git a/app/src/util/assets.ts b/app/src/util/assets.ts
index e0963d59a..16de83659 100644
--- a/app/src/util/assets.ts
+++ b/app/src/util/assets.ts
@@ -243,7 +243,7 @@ export const setInlineStyle = (set = true) => {
unicode-range: U+263a, U+2194-2199, U+2934-2935, U+2639, U+26a0, U+25b6, U+25c0, U+23cf, U+2640, U+2642, U+203c, U+2049,
U+2611, U+303d, U+00a9, U+00ae, U+2122, U+1f170-1f171, U+24c2, U+1f17e, U+1f17f, U+1f22f, U+1f250, U+1f21a,
U+1f232-1f23a, U+1f251, U+3297, U+3299, U+25aa, U+25ab, U+2660, U+2666, U+2665, U+2663, U+1f636, U+1f62e, U+1f642,
- U+1f635, U+2620, U+2763, U+2764, U+1f441, U+270c, U+261d, U+270d, U+200d, U+e50a, U+3030;
+ U+1f635, U+2620, U+2763, U+2764, U+1f441, U+270c, U+261d, U+270d, U+200d, U+e50a, U+3030, U+21aa, U+21a9;
}`;
}
style += `.b3-typography, .protyle-wysiwyg, .protyle-title {font-size:${window.siyuan.config.editor.fontSize}px !important}
diff --git a/kernel/api/export.go b/kernel/api/export.go
index 0b78a8794..c9cdc9041 100644
--- a/kernel/api/export.go
+++ b/kernel/api/export.go
@@ -67,7 +67,7 @@ func exportEPUB(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "epub", ".epub")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "epub", ".epub")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -84,7 +84,7 @@ func exportRTF(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "rtf", ".rtf")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "rtf", ".rtf")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -101,7 +101,7 @@ func exportODT(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "odt", ".odt")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "odt", ".odt")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -118,7 +118,7 @@ func exportMediaWiki(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "mediawiki", ".wiki")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "mediawiki", ".wiki")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -135,7 +135,7 @@ func exportOrgMode(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "org", ".org")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "org", ".org")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -152,7 +152,7 @@ func exportOPML(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "opml", ".opml")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "opml", ".opml")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -169,7 +169,7 @@ func exportTextile(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "textile", ".textile")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "textile", ".textile")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -186,7 +186,7 @@ func exportAsciiDoc(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "asciidoc", ".adoc")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "asciidoc", ".adoc")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -203,7 +203,7 @@ func exportReStructuredText(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "rst", ".rst")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "rst", ".rst")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -340,7 +340,7 @@ func exportMds(c *gin.Context) {
ids = append(ids, id.(string))
}
- name, zipPath := model.BatchExportPandocConvertZip(ids, "", ".md")
+ name, zipPath := model.ExportPandocConvertZip(ids, "", ".md")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@@ -357,7 +357,7 @@ func exportMd(c *gin.Context) {
}
id := arg["id"].(string)
- name, zipPath := model.ExportPandocConvertZip(id, "", ".md")
+ name, zipPath := model.ExportPandocConvertZip([]string{id}, "", ".md")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
diff --git a/kernel/model/export.go b/kernel/model/export.go
index 110996a59..a85aef0b8 100644
--- a/kernel/model/export.go
+++ b/kernel/model/export.go
@@ -269,10 +269,10 @@ func Export2Liandi(id string) (err error) {
title := path.Base(tree.HPath)
tags := tree.Root.IALAttr("tags")
content := exportMarkdownContent0(tree, util.GetCloudForumAssetsServer()+time.Now().Format("2006/01")+"/siyuan/"+Conf.GetUser().UserId+"/", true,
- 4, 1, 0,
+ ".md", 4, 1, 0,
"#", "#",
"", "",
- false, nil)
+ false, nil, true)
result := gulu.Ret.NewResult()
request := httpclient.NewCloudRequest30s()
request = request.
@@ -578,7 +578,7 @@ func Preview(id string) (retStdHTML string) {
blockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
- Conf.Export.AddTitle, true)
+ Conf.Export.AddTitle, true, true)
luteEngine := NewLute()
luteEngine.SetFootnotes(true)
addBlockIALNodes(tree, false)
@@ -681,7 +681,7 @@ func ExportMarkdownHTML(id, savePath string, docx, merge bool) (name, dom string
blockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
- Conf.Export.AddTitle, true)
+ Conf.Export.AddTitle, true, true)
name = path.Base(tree.HPath)
name = util.FilterFileName(name) // 导出 PDF、HTML 和 Word 时未移除不支持的文件名符号 https://github.com/siyuan-note/siyuan/issues/5614
savePath = strings.TrimSpace(savePath)
@@ -840,7 +840,7 @@ func ExportHTML(id, savePath string, pdf, image, keepFold, merge bool) (name, do
blockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
- Conf.Export.AddTitle, true)
+ Conf.Export.AddTitle, true, true)
name = path.Base(tree.HPath)
name = util.FilterFileName(name) // 导出 PDF、HTML 和 Word 时未移除不支持的文件名符号 https://github.com/siyuan-note/siyuan/issues/5614
@@ -1421,7 +1421,6 @@ func ExportStdMarkdown(id string) string {
var defID string
if treenode.IsBlockLink(n) {
defID = strings.TrimPrefix(n.TextMarkAHref, "siyuan://blocks/")
-
} else if treenode.IsBlockRef(n) {
defID, _, _ = treenode.GetBlockRef(n)
}
@@ -1438,13 +1437,13 @@ func ExportStdMarkdown(id string) string {
defBlockIDs = gulu.Str.RemoveDuplicatedElem(defBlockIDs)
return exportMarkdownContent0(tree, cloudAssetsBase, false,
- Conf.Export.BlockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
+ ".md", Conf.Export.BlockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
- Conf.Export.AddTitle, defBlockIDs)
+ Conf.Export.AddTitle, defBlockIDs, true)
}
-func BatchExportPandocConvertZip(ids []string, pandocTo, ext string) (name, zipPath string) {
+func ExportPandocConvertZip(ids []string, pandocTo, ext string) (name, zipPath string) {
block := treenode.GetBlockTree(ids[0])
box := Conf.Box(block.BoxID)
baseFolderName := path.Base(block.HPath)
@@ -1463,31 +1462,8 @@ func BatchExportPandocConvertZip(ids []string, pandocTo, ext string) (name, zipP
}
docPaths = util.FilterSelfChildDocs(docPaths)
- zipPath = exportPandocConvertZip(baseFolderName, docPaths, "gfm+footnotes+hard_line_breaks", pandocTo, ext)
- name = util.GetTreeID(block.Path)
- return
-}
-
-func ExportPandocConvertZip(id, pandocTo, ext string) (name, zipPath string) {
- block := treenode.GetBlockTree(id)
- if nil == block {
- logging.LogErrorf("not found block [%s]", id)
- return
- }
-
- boxID := block.BoxID
- box := Conf.Box(boxID)
- baseFolderName := path.Base(block.HPath)
- if "." == baseFolderName {
- baseFolderName = path.Base(block.Path)
- }
- docPaths := []string{block.Path}
- docFiles := box.ListFiles(strings.TrimSuffix(block.Path, ".sy"))
- for _, docFile := range docFiles {
- docPaths = append(docPaths, docFile.path)
- }
-
- zipPath = exportPandocConvertZip(baseFolderName, docPaths, "gfm+footnotes+hard_line_breaks", pandocTo, ext)
+ defBlockIDs, trees, docPaths := prepareExportTrees(docPaths)
+ zipPath = exportPandocConvertZip(baseFolderName, docPaths, defBlockIDs, "gfm+footnotes+hard_line_breaks", pandocTo, ext, trees)
name = util.GetTreeID(block.Path)
return
}
@@ -1515,7 +1491,9 @@ func ExportNotebookMarkdown(boxID, folderPath string) (zipPath string) {
for _, docFile := range docFiles {
docPaths = append(docPaths, docFile.path)
}
- zipPath = exportPandocConvertZip(baseFolderName, docPaths, "", "", ".md")
+
+ defBlockIDs, trees, docPaths := prepareExportTrees(docPaths)
+ zipPath = exportPandocConvertZip(baseFolderName, docPaths, defBlockIDs, "", "", ".md", trees)
return
}
@@ -1642,7 +1620,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
util.PushEndlessProgress(Conf.language(65) + " " + fmt.Sprintf(Conf.language(70), fmt.Sprintf("%d/%d %s", count, len(docPaths), tree.Root.IALAttr("title"))))
refs := map[string]*parse.Tree{}
- exportRefTrees(tree, &refs, &treeCache)
+ exportRefTrees(tree, &[]string{}, &refs, &treeCache)
for refTreeID, refTree := range refs {
if nil == trees[refTreeID] {
refTrees[refTreeID] = refTree
@@ -1949,10 +1927,10 @@ func walkRelationAvs(avID string, exportAvIDs *hashset.Set) {
}
func ExportMarkdownContent(id string) (hPath, exportedMd string) {
- return exportMarkdownContent(id, Conf.Export.BlockRefMode, nil)
+ return exportMarkdownContent(id, ".md", Conf.Export.BlockRefMode, nil, true)
}
-func exportMarkdownContent(id string, exportRefMode int, defBlockIDs []string) (hPath, exportedMd string) {
+func exportMarkdownContent(id, ext string, exportRefMode int, defBlockIDs []string, singleFile bool) (hPath, exportedMd string) {
tree, err := LoadTreeByBlockID(id)
if err != nil {
logging.LogErrorf("load tree by block id [%s] failed: %s", id, err)
@@ -1960,26 +1938,24 @@ func exportMarkdownContent(id string, exportRefMode int, defBlockIDs []string) (
}
hPath = tree.HPath
exportedMd = exportMarkdownContent0(tree, "", false,
- exportRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
+ ext, exportRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
- Conf.Export.AddTitle, defBlockIDs)
+ Conf.Export.AddTitle, defBlockIDs, singleFile)
docIAL := parse.IAL2Map(tree.Root.KramdownIAL)
exportedMd = yfm(docIAL) + exportedMd
return
}
func exportMarkdownContent0(tree *parse.Tree, cloudAssetsBase string, assetsDestSpace2Underscore bool,
- blockRefMode, blockEmbedMode, fileAnnotationRefMode int,
- tagOpenMarker, tagCloseMarker string,
- blockRefTextLeft, blockRefTextRight string,
- addTitle bool,
- defBlockIDs []string) (ret string) {
+ ext string, blockRefMode, blockEmbedMode, fileAnnotationRefMode int,
+ tagOpenMarker, tagCloseMarker string, blockRefTextLeft, blockRefTextRight string,
+ addTitle bool, defBlockIDs []string, singleFile bool) (ret string) {
tree = exportTree(tree, false, false, false,
blockRefMode, blockEmbedMode, fileAnnotationRefMode,
tagOpenMarker, tagCloseMarker,
blockRefTextLeft, blockRefTextRight,
- addTitle, 0 < len(defBlockIDs))
+ addTitle, 0 < len(defBlockIDs), singleFile)
luteEngine := NewLute()
luteEngine.SetFootnotes(true)
luteEngine.SetKramdownIAL(false)
@@ -2057,7 +2033,7 @@ func exportMarkdownContent0(tree *parse.Tree, cloudAssetsBase string, assetsDest
var href string
bt := treenode.GetBlockTree(defID)
if nil != bt {
- href += bt.HPath + ".md"
+ href += bt.HPath + ext
if "d" != bt.Type {
href += "#" + defID
}
@@ -2090,7 +2066,7 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold, avHiddenCol bool,
blockRefMode, blockEmbedMode, fileAnnotationRefMode int,
tagOpenMarker, tagCloseMarker string,
blockRefTextLeft, blockRefTextRight string,
- addTitle, addDocAnchorSpan bool) (ret *parse.Tree) {
+ addTitle, addDocAnchorSpan, singleFile bool) (ret *parse.Tree) {
luteEngine := NewLute()
ret = tree
id := tree.Root.ID
@@ -2107,7 +2083,7 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold, avHiddenCol bool,
// 收集引用转脚注+锚点哈希
var refFootnotes []*refAsFootnotes
- if 4 == blockRefMode {
+ if 4 == blockRefMode && singleFile {
depth = 0
collectFootnotesDefs(ret, ret.ID, &refFootnotes, &treeCache, &depth)
}
@@ -2266,8 +2242,10 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold, avHiddenCol bool,
}
} else {
if 4 == blockRefMode { // 脚注+锚点哈希
- anchorSpan := treenode.NewSpanAnchor(id)
- ret.Root.PrependChild(anchorSpan)
+ if addDocAnchorSpan {
+ anchorSpan := treenode.NewSpanAnchor(id)
+ ret.Root.PrependChild(anchorSpan)
+ }
}
}
@@ -2965,84 +2943,6 @@ type refAsFootnotes struct {
refAnchorText string
}
-func exportRefTrees(tree *parse.Tree, retTrees, treeCache *map[string]*parse.Tree) {
- if nil != (*retTrees)[tree.ID] {
- return
- }
- (*retTrees)[tree.ID] = tree
-
- ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
- if !entering {
- return ast.WalkContinue
- }
-
- if treenode.IsBlockRef(n) {
- defID, _, _ := treenode.GetBlockRef(n)
- if "" == defID {
- return ast.WalkContinue
- }
- defBlock := treenode.GetBlockTree(defID)
- if nil == defBlock {
- return ast.WalkSkipChildren
- }
-
- var defTree *parse.Tree
- var err error
- if (*treeCache)[defBlock.RootID] != nil {
- defTree = (*treeCache)[defBlock.RootID]
- } else {
- defTree, err = LoadTreeByBlockID(defBlock.RootID)
- if err != nil {
- return ast.WalkSkipChildren
- }
- (*treeCache)[defBlock.RootID] = defTree
- }
-
- exportRefTrees(defTree, retTrees, treeCache)
- } else if ast.NodeAttributeView == n.Type {
- // 导出数据库所在文档时一并导出绑定块所在文档
- // Export the binding block docs when exporting the doc where the database is located https://github.com/siyuan-note/siyuan/issues/11486
-
- avID := n.AttributeViewID
- if "" == avID {
- return ast.WalkContinue
- }
-
- attrView, _ := av.ParseAttributeView(avID)
- if nil == attrView {
- return ast.WalkContinue
- }
-
- blockKeyValues := attrView.GetBlockKeyValues()
- if nil == blockKeyValues {
- return ast.WalkContinue
- }
-
- for _, val := range blockKeyValues.Values {
- defBlock := treenode.GetBlockTree(val.BlockID)
- if nil == defBlock {
- continue
- }
-
- var defTree *parse.Tree
- var err error
- if (*treeCache)[defBlock.RootID] != nil {
- defTree = (*treeCache)[defBlock.RootID]
- } else {
- defTree, err = LoadTreeByBlockID(defBlock.RootID)
- if err != nil {
- continue
- }
- (*treeCache)[defBlock.RootID] = defTree
- }
-
- exportRefTrees(defTree, retTrees, treeCache)
- }
- }
- return ast.WalkContinue
- })
-}
-
func processFileAnnotationRef(refID string, n *ast.Node, fileAnnotationRefMode int) ast.WalkStatus {
p := refID[:strings.LastIndex(refID, "/")]
absPath, err := GetAssetAbsPath(p)
@@ -3090,8 +2990,8 @@ func processFileAnnotationRef(refID string, n *ast.Node, fileAnnotationRefMode i
return ast.WalkSkipChildren
}
-func exportPandocConvertZip(baseFolderName string, docPaths []string,
- pandocFrom, pandocTo, ext string) (zipPath string) {
+func exportPandocConvertZip(baseFolderName string, docPaths, defBlockIDs []string,
+ pandocFrom, pandocTo, ext string, treeCache *map[string]*parse.Tree) (zipPath string) {
defer util.ClearPushProgress(100)
dir, name := path.Split(baseFolderName)
@@ -3111,49 +3011,6 @@ func exportPandocConvertZip(baseFolderName string, docPaths []string,
}
exportRefMode := Conf.Export.BlockRefMode
- var defBlockIDs []string
- if 4 == exportRefMode { // 脚注+锚点哈希
- // 导出锚点哈希,这里先记录下所有定义块的 ID
- walked := map[string]bool{}
- for _, p := range docPaths {
- if walked[p] {
- continue
- }
-
- id := util.GetTreeID(p)
- tree, err := LoadTreeByBlockID(id)
- if err != nil {
- continue
- }
- ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
- if !entering {
- return ast.WalkContinue
- }
-
- var defID string
- if treenode.IsBlockLink(n) {
- defID = strings.TrimPrefix(n.TextMarkAHref, "siyuan://blocks/")
-
- } else if treenode.IsBlockRef(n) {
- defID, _, _ = treenode.GetBlockRef(n)
- }
-
- if "" != defID {
- if defBt := treenode.GetBlockTree(defID); nil != defBt {
- docPaths = append(docPaths, defBt.Path)
- docPaths = gulu.Str.RemoveDuplicatedElem(docPaths)
- defBlockIDs = append(defBlockIDs, defID)
- defBlockIDs = gulu.Str.RemoveDuplicatedElem(defBlockIDs)
- walked[defBt.Path] = true
- }
- }
- return ast.WalkContinue
- })
- }
- defBlockIDs = gulu.Str.RemoveDuplicatedElem(defBlockIDs)
- docPaths = gulu.Str.RemoveDuplicatedElem(docPaths)
- }
-
wrotePathHash := map[string]string{}
assetsPathMap, err := allAssetAbsPaths()
if nil != err {
@@ -3164,7 +3021,7 @@ func exportPandocConvertZip(baseFolderName string, docPaths []string,
luteEngine := util.NewLute()
for i, p := range docPaths {
id := util.GetTreeID(p)
- hPath, md := exportMarkdownContent(id, exportRefMode, defBlockIDs)
+ hPath, md := exportMarkdownContent(id, ext, exportRefMode, defBlockIDs, false)
dir, name = path.Split(hPath)
dir = util.FilterFilePath(dir) // 导出文档时未移除不支持的文件名符号 https://github.com/siyuan-note/siyuan/issues/4590
name = util.FilterFileName(name)
@@ -3269,41 +3126,139 @@ func getExportBlockRefLinkText(blockRef *ast.Node, blockRefTextLeft, blockRefTex
return
}
-func getDestViewVal(attrView *av.AttributeView, keyID, blockID string) *av.TableColumn {
- rollupKey, _ := attrView.GetKey(keyID)
- if nil == rollupKey || nil == rollupKey.Rollup {
- return nil
+func prepareExportTrees(docPaths []string) (defBlockIDs []string, trees *map[string]*parse.Tree, relatedDocPaths []string) {
+ trees = &map[string]*parse.Tree{}
+ treeCache := &map[string]*parse.Tree{}
+ defBlockIDs = []string{}
+ for _, p := range docPaths {
+ id := util.GetTreeID(p)
+ tree, err := LoadTreeByBlockID(id)
+ if err != nil {
+ continue
+ }
+ exportRefTrees(tree, &defBlockIDs, trees, treeCache)
}
- relKey, _ := attrView.GetKey(rollupKey.Rollup.RelationKeyID)
- if nil == relKey || nil == relKey.Relation {
- return nil
+ for _, tree := range *trees {
+ relatedDocPaths = append(relatedDocPaths, tree.Path)
}
-
- relVal := attrView.GetValue(relKey.ID, blockID)
- if nil == relVal || nil == relVal.Relation {
- return nil
- }
-
- destAv, _ := av.ParseAttributeView(relKey.Relation.AvID)
- if nil == destAv {
- return nil
- }
-
- destKey, _ := destAv.GetKey(rollupKey.Rollup.KeyID)
- if nil == destKey {
- return nil
- }
-
- destView, _ := destAv.GetCurrentView(destAv.ViewID)
- if nil == destView {
- return nil
- }
-
- destTable := sql.RenderAttributeViewTable(destAv, destView, "")
- if nil == destTable {
- return nil
- }
-
- return destTable.GetColumn(rollupKey.Rollup.KeyID)
+ relatedDocPaths = gulu.Str.RemoveDuplicatedElem(relatedDocPaths)
+ return
+}
+
+func exportRefTrees(tree *parse.Tree, defBlockIDs *[]string, retTrees, treeCache *map[string]*parse.Tree) {
+ if nil != (*retTrees)[tree.ID] {
+ return
+ }
+ (*retTrees)[tree.ID] = tree
+
+ ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
+ if !entering {
+ return ast.WalkContinue
+ }
+
+ if treenode.IsBlockRef(n) {
+ defID, _, _ := treenode.GetBlockRef(n)
+ if "" == defID {
+ return ast.WalkContinue
+ }
+ defBlock := treenode.GetBlockTree(defID)
+ if nil == defBlock {
+ return ast.WalkSkipChildren
+ }
+
+ var defTree *parse.Tree
+ var err error
+ if (*treeCache)[defBlock.RootID] != nil {
+ defTree = (*treeCache)[defBlock.RootID]
+ } else {
+ defTree, err = LoadTreeByBlockID(defBlock.RootID)
+ if err != nil {
+ return ast.WalkSkipChildren
+ }
+ (*treeCache)[defBlock.RootID] = defTree
+ }
+ *defBlockIDs = append(*defBlockIDs, defID)
+
+ exportRefTrees(defTree, defBlockIDs, retTrees, treeCache)
+ } else if treenode.IsBlockLink(n) {
+ defID := strings.TrimPrefix(n.TextMarkAHref, "siyuan://blocks/")
+ if "" == defID {
+ return ast.WalkContinue
+ }
+ defBlock := treenode.GetBlockTree(defID)
+ if nil == defBlock {
+ return ast.WalkSkipChildren
+ }
+
+ var defTree *parse.Tree
+ var err error
+ if (*treeCache)[defBlock.RootID] != nil {
+ defTree = (*treeCache)[defBlock.RootID]
+ } else {
+ defTree, err = LoadTreeByBlockID(defBlock.RootID)
+ if err != nil {
+ return ast.WalkSkipChildren
+ }
+ (*treeCache)[defBlock.RootID] = defTree
+ }
+ *defBlockIDs = append(*defBlockIDs, defID)
+
+ exportRefTrees(defTree, defBlockIDs, retTrees, treeCache)
+ } else if ast.NodeAttributeView == n.Type {
+ // 导出数据库所在文档时一并导出绑定块所在文档
+ // Export the binding block docs when exporting the doc where the database is located https://github.com/siyuan-note/siyuan/issues/11486
+
+ avID := n.AttributeViewID
+ if "" == avID {
+ return ast.WalkContinue
+ }
+
+ attrView, _ := av.ParseAttributeView(avID)
+ if nil == attrView {
+ return ast.WalkContinue
+ }
+
+ blockKeyValues := attrView.GetBlockKeyValues()
+ if nil == blockKeyValues {
+ return ast.WalkContinue
+ }
+
+ for _, val := range blockKeyValues.Values {
+ defBlock := treenode.GetBlockTree(val.BlockID)
+ if nil == defBlock {
+ continue
+ }
+
+ var defTree *parse.Tree
+ var err error
+ if (*treeCache)[defBlock.RootID] != nil {
+ defTree = (*treeCache)[defBlock.RootID]
+ } else {
+ defTree, err = LoadTreeByBlockID(defBlock.RootID)
+ if err != nil {
+ continue
+ }
+ (*treeCache)[defBlock.RootID] = defTree
+ }
+ *defBlockIDs = append(*defBlockIDs, val.BlockID)
+
+ exportRefTrees(defTree, defBlockIDs, retTrees, treeCache)
+ }
+ }
+ return ast.WalkContinue
+ })
+
+ *defBlockIDs = gulu.Str.RemoveDuplicatedElem(*defBlockIDs)
+}
+
+func loadTreeWithCache(id string, treeCache *map[string]*parse.Tree) (tree *parse.Tree, err error) {
+ if tree = (*treeCache)[id]; nil != tree {
+ return
+ }
+ tree, err = LoadTreeByBlockID(id)
+ if nil == err && nil != tree {
+ (*treeCache)[id] = tree
+ }
+ return
}