// SiYuan - Build Your Eternal Digital Garden // Copyright (c) 2020-present, b3log.org // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package model import ( "errors" "fmt" "sort" "strings" "github.com/siyuan-note/siyuan/kernel/sql" "github.com/siyuan-note/siyuan/kernel/treenode" "github.com/siyuan-note/siyuan/kernel/util" ) func RenameBookmark(oldBookmark, newBookmark string) (err error) { if treenode.ContainsMarker(newBookmark) { return errors.New(Conf.Language(112)) } newBookmark = strings.TrimSpace(newBookmark) if "" == newBookmark { return errors.New(Conf.Language(126)) } if oldBookmark == newBookmark { return } util.PushEndlessProgress(Conf.Language(110)) bookmarks := sql.QueryBookmarkBlocksByKeyword(oldBookmark) treeBlocks := map[string][]string{} for _, tag := range bookmarks { if blocks, ok := treeBlocks[tag.RootID]; !ok { treeBlocks[tag.RootID] = []string{tag.ID} } else { treeBlocks[tag.RootID] = append(blocks, tag.ID) } } for treeID, blocks := range treeBlocks { util.PushEndlessProgress("[" + treeID + "]") tree, e := loadTreeByBlockID(treeID) if nil != e { util.ClearPushProgress(100) return e } for _, blockID := range blocks { node := treenode.GetNodeInTree(tree, blockID) if nil == node { continue } if bookmarkAttrVal := node.IALAttr("bookmark"); bookmarkAttrVal == oldBookmark { node.SetIALAttr("bookmark", newBookmark) } } util.PushEndlessProgress(fmt.Sprintf(Conf.Language(111), tree.Root.IALAttr("title"))) if err = writeJSONQueue(tree); nil != err { util.ClearPushProgress(100) return } util.RandomSleep(50, 150) } util.PushEndlessProgress(Conf.Language(113)) sql.WaitForWritingDatabase() util.ReloadUI() return } type BookmarkLabel string type BookmarkBlocks []*Block type Bookmark struct { Name BookmarkLabel `json:"name"` Blocks []*Block `json:"blocks"` Type string `json:"type"` // "bookmark" Depth int `json:"depth"` Count int `json:"count"` } type Bookmarks []*Bookmark func (s Bookmarks) Len() int { return len(s) } func (s Bookmarks) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s Bookmarks) Less(i, j int) bool { return s[i].Name < s[j].Name } func BookmarkLabels() (ret []string) { ret = sql.QueryBookmarkLabels() return } func BuildBookmark() (ret *Bookmarks) { WaitForWritingFiles() sql.WaitForWritingDatabase() ret = &Bookmarks{} sqlBlocks := sql.QueryBookmarkBlocks() labelBlocks := map[BookmarkLabel]BookmarkBlocks{} blocks := fromSQLBlocks(&sqlBlocks, "", 0) for _, block := range blocks { label := BookmarkLabel(block.IAL["bookmark"]) if bs, ok := labelBlocks[label]; ok { bs = append(bs, block) labelBlocks[label] = bs } else { labelBlocks[label] = []*Block{block} } } for label, bs := range labelBlocks { for _, b := range bs { b.Depth = 1 } *ret = append(*ret, &Bookmark{Name: label, Blocks: bs, Type: "bookmark", Count: len(bs)}) } sort.Sort(ret) return }