From 05d1085633d78611f8667d13b17d0f212e3d9bc7 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 11 Jun 2025 11:01:51 +0800 Subject: [PATCH 1/4] :art: Database gallery view https://github.com/siyuan-note/siyuan/issues/10414 --- kernel/sql/av.go | 49 ++++++++++++++++++++++++++++++++++++++++ kernel/sql/av_gallery.go | 46 ++----------------------------------- kernel/sql/av_table.go | 47 ++------------------------------------ 3 files changed, 53 insertions(+), 89 deletions(-) diff --git a/kernel/sql/av.go b/kernel/sql/av.go index 214458e7b..8ea161904 100644 --- a/kernel/sql/av.go +++ b/kernel/sql/av.go @@ -25,6 +25,7 @@ import ( "github.com/siyuan-note/logging" "github.com/siyuan-note/siyuan/kernel/av" "github.com/siyuan-note/siyuan/kernel/filesys" + "github.com/siyuan-note/siyuan/kernel/treenode" "github.com/siyuan-note/siyuan/kernel/util" ) @@ -173,6 +174,54 @@ func RenderTemplateField(ial map[string]string, keyValues []*av.KeyValues, tplCo return } +func generateAttrViewItems(attrView *av.AttributeView) (ret map[string][]*av.KeyValues) { + ret = map[string][]*av.KeyValues{} + for _, keyValues := range attrView.KeyValues { + for _, val := range keyValues.Values { + values := ret[val.BlockID] + if nil == values { + values = []*av.KeyValues{{Key: keyValues.Key, Values: []*av.Value{val}}} + } else { + values = append(values, &av.KeyValues{Key: keyValues.Key, Values: []*av.Value{val}}) + } + ret[val.BlockID] = values + } + } + return +} + +func filterNotFoundAttrViewItems(keyValuesMap *map[string][]*av.KeyValues) { + var notFound []string + var toCheckBlockIDs []string + for blockID, keyValues := range *keyValuesMap { + blockValue := getBlockValue(keyValues) + if nil == blockValue { + notFound = append(notFound, blockID) + continue + } + + if blockValue.IsDetached { + continue + } + + if nil != blockValue.Block && "" == blockValue.Block.ID { + notFound = append(notFound, blockID) + continue + } + + toCheckBlockIDs = append(toCheckBlockIDs, blockID) + } + checkRet := treenode.ExistBlockTrees(toCheckBlockIDs) + for blockID, exist := range checkRet { + if !exist { + notFound = append(notFound, blockID) + } + } + for _, blockID := range notFound { + delete(*keyValuesMap, blockID) + } +} + func fillAttributeViewNilValue(value *av.Value, typ av.KeyType) { value.Type = typ switch typ { diff --git a/kernel/sql/av_gallery.go b/kernel/sql/av_gallery.go index ddc057d83..e8167355b 100644 --- a/kernel/sql/av_gallery.go +++ b/kernel/sql/av_gallery.go @@ -64,50 +64,8 @@ func RenderAttributeViewGallery(attrView *av.AttributeView, view *av.View, query }) } - // 生成卡片 - cardsValues := map[string][]*av.KeyValues{} - for _, keyValues := range attrView.KeyValues { - for _, val := range keyValues.Values { - values := cardsValues[val.BlockID] - if nil == values { - values = []*av.KeyValues{{Key: keyValues.Key, Values: []*av.Value{val}}} - } else { - values = append(values, &av.KeyValues{Key: keyValues.Key, Values: []*av.Value{val}}) - } - cardsValues[val.BlockID] = values - } - } - - // 过滤掉不存在的卡片 - var notFound []string - var toCheckBlockIDs []string - for blockID, keyValues := range cardsValues { - blockValue := getBlockValue(keyValues) - if nil == blockValue { - notFound = append(notFound, blockID) - continue - } - - if blockValue.IsDetached { - continue - } - - if nil != blockValue.Block && "" == blockValue.Block.ID { - notFound = append(notFound, blockID) - continue - } - - toCheckBlockIDs = append(toCheckBlockIDs, blockID) - } - checkRet := treenode.ExistBlockTrees(toCheckBlockIDs) - for blockID, exist := range checkRet { - if !exist { - notFound = append(notFound, blockID) - } - } - for _, blockID := range notFound { - delete(cardsValues, blockID) - } + cardsValues := generateAttrViewItems(attrView) // 生成卡片 + filterNotFoundAttrViewItems(&cardsValues) // 过滤掉不存在的卡片 // 生成卡片字段值 for cardID, cardValues := range cardsValues { diff --git a/kernel/sql/av_table.go b/kernel/sql/av_table.go index e1423fb00..56f9741d0 100644 --- a/kernel/sql/av_table.go +++ b/kernel/sql/av_table.go @@ -22,7 +22,6 @@ import ( "github.com/88250/lute/ast" "github.com/siyuan-note/siyuan/kernel/av" - "github.com/siyuan-note/siyuan/kernel/treenode" "github.com/siyuan-note/siyuan/kernel/util" ) @@ -72,50 +71,8 @@ func RenderAttributeViewTable(attrView *av.AttributeView, view *av.View, query s }) } - // 生成行 - rowsValues := map[string][]*av.KeyValues{} - for _, keyValues := range attrView.KeyValues { - for _, val := range keyValues.Values { - values := rowsValues[val.BlockID] - if nil == values { - values = []*av.KeyValues{{Key: keyValues.Key, Values: []*av.Value{val}}} - } else { - values = append(values, &av.KeyValues{Key: keyValues.Key, Values: []*av.Value{val}}) - } - rowsValues[val.BlockID] = values - } - } - - // 过滤掉不存在的行 - var notFound []string - var toCheckBlockIDs []string - for blockID, keyValues := range rowsValues { - blockValue := getBlockValue(keyValues) - if nil == blockValue { - notFound = append(notFound, blockID) - continue - } - - if blockValue.IsDetached { - continue - } - - if nil != blockValue.Block && "" == blockValue.Block.ID { - notFound = append(notFound, blockID) - continue - } - - toCheckBlockIDs = append(toCheckBlockIDs, blockID) - } - checkRet := treenode.ExistBlockTrees(toCheckBlockIDs) - for blockID, exist := range checkRet { - if !exist { - notFound = append(notFound, blockID) - } - } - for _, blockID := range notFound { - delete(rowsValues, blockID) - } + rowsValues := generateAttrViewItems(attrView) // 生成行 + filterNotFoundAttrViewItems(&rowsValues) // 过滤掉不存在的行 // 生成行单元格 for rowID, rowValues := range rowsValues { From e1c1c806d6292eeea2f3e648623424ce10839b23 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 11 Jun 2025 11:34:43 +0800 Subject: [PATCH 2/4] :art: Database gallery view https://github.com/siyuan-note/siyuan/issues/10414 --- kernel/sql/av.go | 26 ++++++++++++++++++++++++++ kernel/sql/av_gallery.go | 25 +------------------------ kernel/sql/av_table.go | 25 +------------------------ 3 files changed, 28 insertions(+), 48 deletions(-) diff --git a/kernel/sql/av.go b/kernel/sql/av.go index 8ea161904..d0890cef7 100644 --- a/kernel/sql/av.go +++ b/kernel/sql/av.go @@ -222,6 +222,32 @@ func filterNotFoundAttrViewItems(keyValuesMap *map[string][]*av.KeyValues) { } } +func fillAttributeViewBaseValue(baseValue *av.BaseValue, fieldID, itemID string, fieldNumberFormat av.NumberFormat, fieldTemplate string) { + switch baseValue.ValueType { + case av.KeyTypeNumber: // 格式化数字 + if nil != baseValue.Value && nil != baseValue.Value.Number && baseValue.Value.Number.IsNotEmpty { + baseValue.Value.Number.Format = fieldNumberFormat + baseValue.Value.Number.FormatNumber() + } + case av.KeyTypeTemplate: // 渲染模板字段 + baseValue.Value = &av.Value{ID: baseValue.ID, KeyID: fieldID, BlockID: itemID, Type: av.KeyTypeTemplate, Template: &av.ValueTemplate{Content: fieldTemplate}} + case av.KeyTypeCreated: // 填充创建时间字段值,后面再渲染 + baseValue.Value = &av.Value{ID: baseValue.ID, KeyID: fieldID, BlockID: itemID, Type: av.KeyTypeCreated} + case av.KeyTypeUpdated: // 填充更新时间字段值,后面再渲染 + baseValue.Value = &av.Value{ID: baseValue.ID, KeyID: fieldID, BlockID: itemID, Type: av.KeyTypeUpdated} + case av.KeyTypeRelation: // 清空关联字段值,后面再渲染 https://ld246.com/article/1703831044435 + if nil != baseValue.Value && nil != baseValue.Value.Relation { + baseValue.Value.Relation.Contents = nil + } + } + + if nil == baseValue.Value { + baseValue.Value = av.GetAttributeViewDefaultValue(baseValue.ID, fieldID, itemID, baseValue.ValueType) + } else { + fillAttributeViewNilValue(baseValue.Value, baseValue.ValueType) + } +} + func fillAttributeViewNilValue(value *av.Value, typ av.KeyType) { value.Type = typ switch typ { diff --git a/kernel/sql/av_gallery.go b/kernel/sql/av_gallery.go index e8167355b..732014106 100644 --- a/kernel/sql/av_gallery.go +++ b/kernel/sql/av_gallery.go @@ -94,30 +94,7 @@ func RenderAttributeViewGallery(attrView *av.AttributeView, view *av.View, query } galleryCard.ID = cardID - switch fieldValue.ValueType { - case av.KeyTypeNumber: // 格式化数字 - if nil != fieldValue.Value && nil != fieldValue.Value.Number && fieldValue.Value.Number.IsNotEmpty { - fieldValue.Value.Number.Format = field.NumberFormat - fieldValue.Value.Number.FormatNumber() - } - case av.KeyTypeTemplate: // 渲染模板字段 - fieldValue.Value = &av.Value{ID: fieldValue.ID, KeyID: field.ID, BlockID: cardID, Type: av.KeyTypeTemplate, Template: &av.ValueTemplate{Content: field.Template}} - case av.KeyTypeCreated: // 填充创建时间字段值,后面再渲染 - fieldValue.Value = &av.Value{ID: fieldValue.ID, KeyID: field.ID, BlockID: cardID, Type: av.KeyTypeCreated} - case av.KeyTypeUpdated: // 填充更新时间字段值,后面再渲染 - fieldValue.Value = &av.Value{ID: fieldValue.ID, KeyID: field.ID, BlockID: cardID, Type: av.KeyTypeUpdated} - case av.KeyTypeRelation: // 清空关联字段值,后面再渲染 https://ld246.com/article/1703831044435 - if nil != fieldValue.Value && nil != fieldValue.Value.Relation { - fieldValue.Value.Relation.Contents = nil - } - } - - if nil == fieldValue.Value { - fieldValue.Value = av.GetAttributeViewDefaultValue(fieldValue.ID, field.ID, cardID, fieldValue.ValueType) - } else { - fillAttributeViewNilValue(fieldValue.Value, fieldValue.ValueType) - } - + fillAttributeViewBaseValue(fieldValue.BaseValue, field.ID, cardID, field.NumberFormat, field.Template) galleryCard.Values = append(galleryCard.Values, fieldValue) } diff --git a/kernel/sql/av_table.go b/kernel/sql/av_table.go index 56f9741d0..4dd5d9117 100644 --- a/kernel/sql/av_table.go +++ b/kernel/sql/av_table.go @@ -101,30 +101,7 @@ func RenderAttributeViewTable(attrView *av.AttributeView, view *av.View, query s } tableRow.ID = rowID - switch tableCell.ValueType { - case av.KeyTypeNumber: // 格式化数字 - if nil != tableCell.Value && nil != tableCell.Value.Number && tableCell.Value.Number.IsNotEmpty { - tableCell.Value.Number.Format = col.NumberFormat - tableCell.Value.Number.FormatNumber() - } - case av.KeyTypeTemplate: // 渲染模板列 - tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeTemplate, Template: &av.ValueTemplate{Content: col.Template}} - case av.KeyTypeCreated: // 填充创建时间列值,后面再渲染 - tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeCreated} - case av.KeyTypeUpdated: // 填充更新时间列值,后面再渲染 - tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeUpdated} - case av.KeyTypeRelation: // 清空关联列值,后面再渲染 https://ld246.com/article/1703831044435 - if nil != tableCell.Value && nil != tableCell.Value.Relation { - tableCell.Value.Relation.Contents = nil - } - } - - if nil == tableCell.Value { - tableCell.Value = av.GetAttributeViewDefaultValue(tableCell.ID, col.ID, rowID, tableCell.ValueType) - } else { - fillAttributeViewNilValue(tableCell.Value, tableCell.ValueType) - } - + fillAttributeViewBaseValue(tableCell.BaseValue, col.ID, rowID, col.NumberFormat, col.Template) tableRow.Cells = append(tableRow.Cells, tableCell) } ret.Rows = append(ret.Rows, &tableRow) From 0440d94f71f87c11bfedf9fdb5d7cddbe3ab4c86 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 11 Jun 2025 11:40:06 +0800 Subject: [PATCH 3/4] :art: Database gallery view https://github.com/siyuan-note/siyuan/issues/10414 --- kernel/sql/av_gallery.go | 91 +++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/kernel/sql/av_gallery.go b/kernel/sql/av_gallery.go index 732014106..4e850b456 100644 --- a/kernel/sql/av_gallery.go +++ b/kernel/sql/av_gallery.go @@ -341,55 +341,62 @@ func fillGalleryCardCover(attrView *av.AttributeView, view *av.View, cardValues case av.CoverFromNone: case av.CoverFromContentImage: blockValue := getBlockValue(cardValues) - if !blockValue.IsDetached { - tree := loadTreeByBlockID(blockValue.BlockID) - if nil == tree { - break - } - node := treenode.GetNodeInTree(tree, blockValue.BlockID) - if nil == node { + if blockValue.IsDetached { + break + } + + tree := loadTreeByBlockID(blockValue.BlockID) + if nil == tree { + break + } + node := treenode.GetNodeInTree(tree, blockValue.BlockID) + if nil == node { + break + } + + if ast.NodeDocument == node.Type { + if titleImg := treenode.GetDocTitleImgPath(node); "" != titleImg { + galleryCard.CoverURL = titleImg break } + if titleImgCss := node.IALAttr("title-img"); strings.HasPrefix(titleImgCss, "background:") { + galleryCard.CoverURL = titleImgCss + break + } + } + + ast.Walk(node, func(n *ast.Node, entering bool) ast.WalkStatus { + if !entering { + return ast.WalkContinue + } + + if ast.NodeImage != n.Type { + return ast.WalkContinue + } + + dest := n.ChildByType(ast.NodeLinkDest) + if nil == dest { + return ast.WalkContinue + } + galleryCard.CoverURL = dest.TokensStr() + return ast.WalkStop + }) + + if "" == galleryCard.CoverURL { if ast.NodeDocument == node.Type { - if titleImg := treenode.GetDocTitleImgPath(node); "" != titleImg { - galleryCard.CoverURL = titleImg + node = node.FirstChild + } + + buf := bytes.Buffer{} + for c := node; nil != c; c = c.Next { + buf.WriteString(renderBlockDOMByNode(c, luteEngine)) + if 1024*4 < buf.Len() { break } } - - ast.Walk(node, func(n *ast.Node, entering bool) ast.WalkStatus { - if !entering { - return ast.WalkContinue - } - - if ast.NodeImage != n.Type { - return ast.WalkContinue - } - - dest := n.ChildByType(ast.NodeLinkDest) - if nil == dest { - return ast.WalkContinue - } - galleryCard.CoverURL = dest.TokensStr() - return ast.WalkStop - }) - - if "" == galleryCard.CoverURL { - if ast.NodeDocument == node.Type { - node = node.FirstChild - } - - buf := bytes.Buffer{} - for c := node; nil != c; c = c.Next { - buf.WriteString(renderBlockDOMByNode(c, luteEngine)) - if 1024*4 < buf.Len() { - break - } - } - galleryCard.CoverContent = buf.String() - return - } + galleryCard.CoverContent = buf.String() + return } case av.CoverFromAssetField: if "" == view.Gallery.CoverFromAssetKeyID { From d9e5f2c312918b7f4bb6bacff32b399049ba8683 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 11 Jun 2025 11:47:46 +0800 Subject: [PATCH 4/4] :art: Database gallery view https://github.com/siyuan-note/siyuan/issues/10414 --- kernel/sql/av_gallery.go | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/sql/av_gallery.go b/kernel/sql/av_gallery.go index 4e850b456..dea8120be 100644 --- a/kernel/sql/av_gallery.go +++ b/kernel/sql/av_gallery.go @@ -416,6 +416,7 @@ func fillGalleryCardCover(attrView *av.AttributeView, view *av.View, cardValues func renderBlockDOMByNode(node *ast.Node, luteEngine *lute.Lute) string { tree := &parse.Tree{Root: &ast.Node{Type: ast.NodeDocument}, Context: &parse.Context{ParseOption: luteEngine.ParseOptions}} blockRenderer := render.NewProtyleRenderer(tree, luteEngine.RenderOptions) + blockRenderer.Options.ProtyleContenteditable = false ast.Walk(node, func(node *ast.Node, entering bool) ast.WalkStatus { rendererFunc := blockRenderer.RendererFuncs[node.Type] return rendererFunc(node, entering)