block.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. // SiYuan - Refactor your thinking
  2. // Copyright (c) 2020-present, b3log.org
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package model
  17. import (
  18. "errors"
  19. "fmt"
  20. "strconv"
  21. "strings"
  22. "time"
  23. "github.com/88250/lute/ast"
  24. "github.com/88250/lute/parse"
  25. "github.com/open-spaced-repetition/go-fsrs"
  26. "github.com/siyuan-note/siyuan/kernel/filesys"
  27. "github.com/siyuan-note/siyuan/kernel/sql"
  28. "github.com/siyuan-note/siyuan/kernel/treenode"
  29. "github.com/siyuan-note/siyuan/kernel/util"
  30. )
  31. // Block 描述了内容块。
  32. type Block struct {
  33. Box string `json:"box"`
  34. Path string `json:"path"`
  35. HPath string `json:"hPath"`
  36. ID string `json:"id"`
  37. RootID string `json:"rootID"`
  38. ParentID string `json:"parentID"`
  39. Name string `json:"name"`
  40. Alias string `json:"alias"`
  41. Memo string `json:"memo"`
  42. Tag string `json:"tag"`
  43. Content string `json:"content"`
  44. FContent string `json:"fcontent"`
  45. Markdown string `json:"markdown"`
  46. Folded bool `json:"folded"`
  47. Type string `json:"type"`
  48. SubType string `json:"subType"`
  49. RefText string `json:"refText"`
  50. Defs []*Block `json:"-"` // 当前块引用了这些块,避免序列化 JSON 时产生循环引用
  51. Refs []*Block `json:"refs"` // 当前块被这些块引用
  52. DefID string `json:"defID"`
  53. DefPath string `json:"defPath"`
  54. IAL map[string]string `json:"ial"`
  55. Children []*Block `json:"children"`
  56. Depth int `json:"depth"`
  57. Count int `json:"count"`
  58. Sort int `json:"sort"`
  59. Created string `json:"created"`
  60. Updated string `json:"updated"`
  61. RiffCardID string `json:"riffCardID"`
  62. RiffCard *RiffCard `json:"riffCard"`
  63. }
  64. type RiffCard struct {
  65. Due time.Time `json:"due"`
  66. Reps uint64 `json:"reps"`
  67. Lapses uint64 `json:"lapses"`
  68. State fsrs.State `json:"state"`
  69. LastReview time.Time `json:"lastReview"`
  70. }
  71. func getRiffCard(card *fsrs.Card) *RiffCard {
  72. due := card.Due
  73. if due.IsZero() {
  74. due = time.Now()
  75. }
  76. return &RiffCard{
  77. Due: due,
  78. Reps: card.Reps,
  79. Lapses: card.Lapses,
  80. State: card.State,
  81. LastReview: card.LastReview,
  82. }
  83. }
  84. func (block *Block) IsContainerBlock() bool {
  85. switch block.Type {
  86. case "NodeDocument", "NodeBlockquote", "NodeList", "NodeListItem", "NodeSuperBlock":
  87. return true
  88. }
  89. return false
  90. }
  91. type Path struct {
  92. ID string `json:"id"` // 块 ID
  93. Box string `json:"box"` // 块 Box
  94. Name string `json:"name"` // 当前路径
  95. HPath string `json:"hPath"` // 人类可读路径
  96. Type string `json:"type"` // "path"
  97. NodeType string `json:"nodeType"` // 节点类型
  98. SubType string `json:"subType"` // 节点子类型
  99. Blocks []*Block `json:"blocks,omitempty"` // 子块节点
  100. Children []*Path `json:"children,omitempty"` // 子路径节点
  101. Depth int `json:"depth"` // 层级深度
  102. Count int `json:"count"` // 子块计数
  103. Updated string `json:"updated"` // 更新时间
  104. Created string `json:"created"` // 创建时间
  105. }
  106. type BlockTreeInfo struct {
  107. ID string `json:"id"`
  108. Type string `json:"type"`
  109. ParentID string `json:"parentID"`
  110. ParentType string `json:"parentType"`
  111. PreviousID string `json:"previousID"`
  112. PreviousType string `json:"previousType"`
  113. NextID string `json:"nextID"`
  114. NextType string `json:"nextType"`
  115. }
  116. func GetBlockTreeInfos(ids []string) (ret map[string]*BlockTreeInfo) {
  117. ret = map[string]*BlockTreeInfo{}
  118. luteEngine := util.NewLute()
  119. treeCache := map[string]*parse.Tree{}
  120. for _, id := range ids {
  121. bt := treenode.GetBlockTree(id)
  122. if nil == bt {
  123. ret[id] = &BlockTreeInfo{ID: id}
  124. continue
  125. }
  126. tree := treeCache[bt.RootID]
  127. if nil == tree {
  128. tree, _ = filesys.LoadTree(bt.BoxID, bt.Path, luteEngine)
  129. if nil == tree {
  130. ret[id] = &BlockTreeInfo{ID: id}
  131. continue
  132. }
  133. treeCache[bt.RootID] = tree
  134. }
  135. node := treenode.GetNodeInTree(tree, id)
  136. if nil == node {
  137. ret[id] = &BlockTreeInfo{ID: id}
  138. continue
  139. }
  140. bti := &BlockTreeInfo{ID: id, Type: node.Type.String()}
  141. ret[id] = bti
  142. parent := treenode.ParentBlock(node)
  143. if nil != parent {
  144. bti.ParentID = parent.ID
  145. bti.ParentType = parent.Type.String()
  146. }
  147. previous := treenode.PreviousBlock(node)
  148. if nil != previous {
  149. bti.PreviousID = previous.ID
  150. bti.PreviousType = previous.Type.String()
  151. }
  152. next := treenode.NextBlock(node)
  153. if nil != next {
  154. bti.NextID = next.ID
  155. bti.NextType = next.Type.String()
  156. }
  157. }
  158. return
  159. }
  160. func GetBlockSiblingID(id string) (parent, previous, next string) {
  161. tree, err := LoadTreeByBlockID(id)
  162. if nil != err {
  163. return
  164. }
  165. node := treenode.GetNodeInTree(tree, id)
  166. if nil == node {
  167. return
  168. }
  169. if !node.IsBlock() {
  170. return
  171. }
  172. parentListCount := 0
  173. var parentListItem, current *ast.Node
  174. for p := node.Parent; nil != p; p = p.Parent {
  175. if ast.NodeListItem == p.Type {
  176. parentListCount++
  177. if 1 < parentListCount {
  178. parentListItem = p
  179. break
  180. }
  181. current = p.Parent
  182. }
  183. }
  184. if nil != parentListItem {
  185. parent = parentListItem.ID
  186. if parentListItem.Previous != nil {
  187. previous = parentListItem.Previous.ID
  188. if flb := treenode.FirstChildBlock(parentListItem.Previous); nil != flb {
  189. previous = flb.ID
  190. }
  191. }
  192. if parentListItem.Next != nil {
  193. next = parentListItem.Next.ID
  194. if flb := treenode.FirstChildBlock(parentListItem.Next); nil != flb {
  195. next = flb.ID
  196. }
  197. }
  198. return
  199. }
  200. if nil == current {
  201. current = node
  202. }
  203. if nil != current.Parent && current.Parent.IsBlock() {
  204. parent = current.Parent.ID
  205. if flb := treenode.FirstChildBlock(current.Parent); nil != flb {
  206. parent = flb.ID
  207. }
  208. if ast.NodeDocument == current.Parent.Type {
  209. parent = current.Parent.ID
  210. if nil != current.Previous && current.Previous.IsBlock() {
  211. previous = current.Previous.ID
  212. if flb := treenode.FirstChildBlock(current.Previous); nil != flb {
  213. previous = flb.ID
  214. }
  215. }
  216. if nil != current.Next && current.Next.IsBlock() {
  217. next = current.Next.ID
  218. if flb := treenode.FirstChildBlock(current.Next); nil != flb {
  219. next = flb.ID
  220. }
  221. }
  222. } else {
  223. if nil != current.Parent.Previous && current.Parent.Previous.IsBlock() {
  224. previous = current.Parent.Previous.ID
  225. if flb := treenode.FirstChildBlock(current.Parent.Previous); nil != flb {
  226. previous = flb.ID
  227. }
  228. }
  229. if nil != current.Parent.Next && current.Parent.Next.IsBlock() {
  230. next = current.Parent.Next.ID
  231. if flb := treenode.FirstChildBlock(current.Parent.Next); nil != flb {
  232. next = flb.ID
  233. }
  234. }
  235. }
  236. }
  237. return
  238. }
  239. func IsBlockFolded(id string) (isFolded, isRoot bool) {
  240. tree, _ := LoadTreeByBlockID(id)
  241. if nil == tree {
  242. return
  243. }
  244. if tree.Root.ID == id {
  245. isRoot = true
  246. }
  247. for i := 0; i < 32; i++ {
  248. b, _ := getBlock(id, nil)
  249. if nil == b {
  250. return
  251. }
  252. if "1" == b.IAL["fold"] {
  253. isFolded = true
  254. return
  255. }
  256. id = b.ParentID
  257. }
  258. return
  259. }
  260. func RecentUpdatedBlocks() (ret []*Block) {
  261. ret = []*Block{}
  262. sqlBlocks := sql.QueryRecentUpdatedBlocks()
  263. if 1 > len(sqlBlocks) {
  264. return
  265. }
  266. ret = fromSQLBlocks(&sqlBlocks, "", 0)
  267. return
  268. }
  269. func TransferBlockRef(fromID, toID string, refIDs []string) (err error) {
  270. toTree, _ := LoadTreeByBlockID(toID)
  271. if nil == toTree {
  272. err = ErrBlockNotFound
  273. return
  274. }
  275. toNode := treenode.GetNodeInTree(toTree, toID)
  276. if nil == toNode {
  277. err = ErrBlockNotFound
  278. return
  279. }
  280. toRefText := getNodeRefText(toNode)
  281. util.PushMsg(Conf.Language(116), 7000)
  282. if 1 > len(refIDs) { // 如果不指定 refIDs,则转移所有引用了 fromID 的块
  283. refIDs, _ = sql.QueryRefIDsByDefID(fromID, false)
  284. }
  285. for _, refID := range refIDs {
  286. tree, _ := LoadTreeByBlockID(refID)
  287. if nil == tree {
  288. continue
  289. }
  290. node := treenode.GetNodeInTree(tree, refID)
  291. textMarks := node.ChildrenByType(ast.NodeTextMark)
  292. for _, textMark := range textMarks {
  293. if textMark.IsTextMarkType("block-ref") && textMark.TextMarkBlockRefID == fromID {
  294. textMark.TextMarkBlockRefID = toID
  295. if "d" == textMark.TextMarkBlockRefSubtype {
  296. textMark.TextMarkTextContent = toRefText
  297. }
  298. }
  299. }
  300. if err = indexWriteTreeUpsertQueue(tree); nil != err {
  301. return
  302. }
  303. }
  304. sql.WaitForWritingDatabase()
  305. return
  306. }
  307. func SwapBlockRef(refID, defID string, includeChildren bool) (err error) {
  308. refTree, err := LoadTreeByBlockID(refID)
  309. if nil != err {
  310. return
  311. }
  312. refNode := treenode.GetNodeInTree(refTree, refID)
  313. if nil == refNode {
  314. return
  315. }
  316. if ast.NodeListItem == refNode.Parent.Type {
  317. refNode = refNode.Parent
  318. }
  319. defTree, err := LoadTreeByBlockID(defID)
  320. if nil != err {
  321. return
  322. }
  323. sameTree := defTree.ID == refTree.ID
  324. var defNode *ast.Node
  325. if !sameTree {
  326. defNode = treenode.GetNodeInTree(defTree, defID)
  327. } else {
  328. defNode = treenode.GetNodeInTree(refTree, defID)
  329. }
  330. if nil == defNode {
  331. return
  332. }
  333. var defNodeChildren []*ast.Node
  334. if ast.NodeListItem == defNode.Parent.Type {
  335. defNode = defNode.Parent
  336. } else if ast.NodeHeading == defNode.Type && includeChildren {
  337. defNodeChildren = treenode.HeadingChildren(defNode)
  338. }
  339. if ast.NodeListItem == defNode.Type {
  340. for c := defNode.FirstChild; nil != c; c = c.Next {
  341. if ast.NodeList == c.Type {
  342. defNodeChildren = append(defNodeChildren, c)
  343. }
  344. }
  345. }
  346. refreshUpdated(defNode)
  347. refreshUpdated(refNode)
  348. refPivot := treenode.NewParagraph()
  349. refNode.InsertBefore(refPivot)
  350. if ast.NodeListItem == defNode.Type {
  351. if ast.NodeListItem == refNode.Type {
  352. if !includeChildren {
  353. for _, c := range defNodeChildren {
  354. refNode.AppendChild(c)
  355. }
  356. }
  357. defNode.InsertAfter(refNode)
  358. refPivot.InsertAfter(defNode)
  359. } else {
  360. newID := ast.NewNodeID()
  361. li := &ast.Node{ID: newID, Type: ast.NodeListItem, ListData: &ast.ListData{Typ: defNode.Parent.ListData.Typ}}
  362. li.SetIALAttr("id", newID)
  363. li.SetIALAttr("updated", newID[:14])
  364. li.AppendChild(refNode)
  365. defNode.InsertAfter(li)
  366. if !includeChildren {
  367. for _, c := range defNodeChildren {
  368. li.AppendChild(c)
  369. }
  370. }
  371. newID = ast.NewNodeID()
  372. list := &ast.Node{ID: newID, Type: ast.NodeList, ListData: &ast.ListData{Typ: defNode.Parent.ListData.Typ}}
  373. list.SetIALAttr("id", newID)
  374. list.SetIALAttr("updated", newID[:14])
  375. list.AppendChild(defNode)
  376. refPivot.InsertAfter(list)
  377. }
  378. } else {
  379. if ast.NodeListItem == refNode.Type {
  380. newID := ast.NewNodeID()
  381. list := &ast.Node{ID: newID, Type: ast.NodeList, ListData: &ast.ListData{Typ: refNode.Parent.ListData.Typ}}
  382. list.SetIALAttr("id", newID)
  383. list.SetIALAttr("updated", newID[:14])
  384. list.AppendChild(refNode)
  385. defNode.InsertAfter(list)
  386. newID = ast.NewNodeID()
  387. li := &ast.Node{ID: newID, Type: ast.NodeListItem, ListData: &ast.ListData{Typ: refNode.Parent.ListData.Typ}}
  388. li.SetIALAttr("id", newID)
  389. li.SetIALAttr("updated", newID[:14])
  390. li.AppendChild(defNode)
  391. for i := len(defNodeChildren) - 1; -1 < i; i-- {
  392. defNode.InsertAfter(defNodeChildren[i])
  393. }
  394. refPivot.InsertAfter(li)
  395. } else {
  396. defNode.InsertAfter(refNode)
  397. refPivot.InsertAfter(defNode)
  398. for i := len(defNodeChildren) - 1; -1 < i; i-- {
  399. defNode.InsertAfter(defNodeChildren[i])
  400. }
  401. }
  402. }
  403. refPivot.Unlink()
  404. if err = indexWriteTreeUpsertQueue(refTree); nil != err {
  405. return
  406. }
  407. if !sameTree {
  408. if err = indexWriteTreeUpsertQueue(defTree); nil != err {
  409. return
  410. }
  411. }
  412. WaitForWritingFiles()
  413. util.ReloadUI()
  414. return
  415. }
  416. func GetHeadingDeleteTransaction(id string) (transaction *Transaction, err error) {
  417. tree, err := LoadTreeByBlockID(id)
  418. if nil != err {
  419. return
  420. }
  421. node := treenode.GetNodeInTree(tree, id)
  422. if nil == node {
  423. err = errors.New(fmt.Sprintf(Conf.Language(15), id))
  424. return
  425. }
  426. if ast.NodeHeading != node.Type {
  427. return
  428. }
  429. var nodes []*ast.Node
  430. nodes = append(nodes, node)
  431. nodes = append(nodes, treenode.HeadingChildren(node)...)
  432. transaction = &Transaction{}
  433. luteEngine := util.NewLute()
  434. for _, n := range nodes {
  435. op := &Operation{}
  436. op.ID = n.ID
  437. op.Action = "delete"
  438. transaction.DoOperations = append(transaction.DoOperations, op)
  439. op = &Operation{}
  440. op.ID = n.ID
  441. if nil != n.Parent {
  442. op.ParentID = n.Parent.ID
  443. }
  444. if nil != n.Previous {
  445. op.PreviousID = n.Previous.ID
  446. }
  447. op.Action = "insert"
  448. op.Data = luteEngine.RenderNodeBlockDOM(n)
  449. transaction.UndoOperations = append(transaction.UndoOperations, op)
  450. }
  451. return
  452. }
  453. func GetHeadingChildrenIDs(id string) (ret []string) {
  454. tree, err := LoadTreeByBlockID(id)
  455. if nil != err {
  456. return
  457. }
  458. heading := treenode.GetNodeInTree(tree, id)
  459. if nil == heading || ast.NodeHeading != heading.Type {
  460. return
  461. }
  462. children := treenode.HeadingChildren(heading)
  463. nodes := append([]*ast.Node{}, children...)
  464. for _, n := range nodes {
  465. ret = append(ret, n.ID)
  466. }
  467. return
  468. }
  469. func GetHeadingChildrenDOM(id string) (ret string) {
  470. tree, err := LoadTreeByBlockID(id)
  471. if nil != err {
  472. return
  473. }
  474. heading := treenode.GetNodeInTree(tree, id)
  475. if nil == heading || ast.NodeHeading != heading.Type {
  476. return
  477. }
  478. nodes := append([]*ast.Node{}, heading)
  479. children := treenode.HeadingChildren(heading)
  480. nodes = append(nodes, children...)
  481. luteEngine := util.NewLute()
  482. ret = renderBlockDOMByNodes(nodes, luteEngine)
  483. return
  484. }
  485. func GetHeadingLevelTransaction(id string, level int) (transaction *Transaction, err error) {
  486. tree, err := LoadTreeByBlockID(id)
  487. if nil != err {
  488. return
  489. }
  490. node := treenode.GetNodeInTree(tree, id)
  491. if nil == node {
  492. err = errors.New(fmt.Sprintf(Conf.Language(15), id))
  493. return
  494. }
  495. if ast.NodeHeading != node.Type {
  496. return
  497. }
  498. hLevel := node.HeadingLevel
  499. if hLevel == level {
  500. return
  501. }
  502. diff := level - hLevel
  503. var children, childrenHeadings []*ast.Node
  504. children = append(children, node)
  505. children = append(children, treenode.HeadingChildren(node)...)
  506. for _, c := range children {
  507. ccH := c.ChildrenByType(ast.NodeHeading)
  508. childrenHeadings = append(childrenHeadings, ccH...)
  509. }
  510. transaction = &Transaction{}
  511. luteEngine := util.NewLute()
  512. for _, c := range childrenHeadings {
  513. op := &Operation{}
  514. op.ID = c.ID
  515. op.Action = "update"
  516. op.Data = luteEngine.RenderNodeBlockDOM(c)
  517. transaction.UndoOperations = append(transaction.UndoOperations, op)
  518. c.HeadingLevel += diff
  519. if 6 < c.HeadingLevel {
  520. c.HeadingLevel = 6
  521. } else if 1 > c.HeadingLevel {
  522. c.HeadingLevel = 1
  523. }
  524. op = &Operation{}
  525. op.ID = c.ID
  526. op.Action = "update"
  527. op.Data = luteEngine.RenderNodeBlockDOM(c)
  528. transaction.DoOperations = append(transaction.DoOperations, op)
  529. }
  530. return
  531. }
  532. func GetBlockDOM(id string) (ret string) {
  533. if "" == id {
  534. return
  535. }
  536. tree, err := LoadTreeByBlockID(id)
  537. if nil != err {
  538. return
  539. }
  540. node := treenode.GetNodeInTree(tree, id)
  541. luteEngine := NewLute()
  542. ret = luteEngine.RenderNodeBlockDOM(node)
  543. return
  544. }
  545. func GetBlockKramdown(id string) (ret string) {
  546. if "" == id {
  547. return
  548. }
  549. tree, err := LoadTreeByBlockID(id)
  550. if nil != err {
  551. return
  552. }
  553. addBlockIALNodes(tree, false)
  554. node := treenode.GetNodeInTree(tree, id)
  555. root := &ast.Node{Type: ast.NodeDocument}
  556. root.AppendChild(node.Next) // IAL
  557. root.PrependChild(node)
  558. luteEngine := NewLute()
  559. ret = treenode.ExportNodeStdMd(root, luteEngine)
  560. return
  561. }
  562. type ChildBlock struct {
  563. ID string `json:"id"`
  564. Type string `json:"type"`
  565. SubType string `json:"subType,omitempty"`
  566. }
  567. func GetChildBlocks(id string) (ret []*ChildBlock) {
  568. ret = []*ChildBlock{}
  569. if "" == id {
  570. return
  571. }
  572. tree, err := LoadTreeByBlockID(id)
  573. if nil != err {
  574. return
  575. }
  576. node := treenode.GetNodeInTree(tree, id)
  577. if nil == node {
  578. return
  579. }
  580. if ast.NodeHeading == node.Type {
  581. children := treenode.HeadingChildren(node)
  582. for _, c := range children {
  583. ret = append(ret, &ChildBlock{
  584. ID: c.ID,
  585. Type: treenode.TypeAbbr(c.Type.String()),
  586. SubType: treenode.SubTypeAbbr(c),
  587. })
  588. }
  589. return
  590. }
  591. if !node.IsContainerBlock() {
  592. return
  593. }
  594. for c := node.FirstChild; nil != c; c = c.Next {
  595. if !c.IsBlock() {
  596. continue
  597. }
  598. ret = append(ret, &ChildBlock{
  599. ID: c.ID,
  600. Type: treenode.TypeAbbr(c.Type.String()),
  601. SubType: treenode.SubTypeAbbr(c),
  602. })
  603. }
  604. return
  605. }
  606. func GetTailChildBlocks(id string, n int) (ret []*ChildBlock) {
  607. ret = []*ChildBlock{}
  608. if "" == id {
  609. return
  610. }
  611. tree, err := LoadTreeByBlockID(id)
  612. if nil != err {
  613. return
  614. }
  615. node := treenode.GetNodeInTree(tree, id)
  616. if nil == node {
  617. return
  618. }
  619. if ast.NodeHeading == node.Type {
  620. children := treenode.HeadingChildren(node)
  621. for i := len(children) - 1; 0 <= i; i-- {
  622. c := children[i]
  623. ret = append(ret, &ChildBlock{
  624. ID: c.ID,
  625. Type: treenode.TypeAbbr(c.Type.String()),
  626. SubType: treenode.SubTypeAbbr(c),
  627. })
  628. if n == len(ret) {
  629. return
  630. }
  631. }
  632. return
  633. }
  634. if !node.IsContainerBlock() {
  635. return
  636. }
  637. for c := node.LastChild; nil != c; c = c.Previous {
  638. if !c.IsBlock() {
  639. continue
  640. }
  641. ret = append(ret, &ChildBlock{
  642. ID: c.ID,
  643. Type: treenode.TypeAbbr(c.Type.String()),
  644. SubType: treenode.SubTypeAbbr(c),
  645. })
  646. if n == len(ret) {
  647. return
  648. }
  649. }
  650. return
  651. }
  652. func GetBlock(id string, tree *parse.Tree) (ret *Block, err error) {
  653. ret, err = getBlock(id, tree)
  654. return
  655. }
  656. func getBlock(id string, tree *parse.Tree) (ret *Block, err error) {
  657. if "" == id {
  658. return
  659. }
  660. if nil == tree {
  661. tree, err = LoadTreeByBlockID(id)
  662. if nil != err {
  663. time.Sleep(1 * time.Second)
  664. tree, err = LoadTreeByBlockID(id)
  665. if nil != err {
  666. return
  667. }
  668. }
  669. }
  670. node := treenode.GetNodeInTree(tree, id)
  671. if nil == node {
  672. err = ErrBlockNotFound
  673. return
  674. }
  675. sqlBlock := sql.BuildBlockFromNode(node, tree)
  676. if nil == sqlBlock {
  677. return
  678. }
  679. ret = fromSQLBlock(sqlBlock, "", 0)
  680. return
  681. }
  682. func getEmbeddedBlock(trees map[string]*parse.Tree, sqlBlock *sql.Block, headingMode int, breadcrumb bool) (block *Block, blockPaths []*BlockPath) {
  683. tree, _ := trees[sqlBlock.RootID]
  684. if nil == tree {
  685. tree, _ = LoadTreeByBlockID(sqlBlock.RootID)
  686. }
  687. if nil == tree {
  688. return
  689. }
  690. def := treenode.GetNodeInTree(tree, sqlBlock.ID)
  691. if nil == def {
  692. return
  693. }
  694. var unlinks, nodes []*ast.Node
  695. ast.Walk(def, func(n *ast.Node, entering bool) ast.WalkStatus {
  696. if !entering {
  697. return ast.WalkContinue
  698. }
  699. if ast.NodeHeading == n.Type {
  700. if "1" == n.IALAttr("fold") {
  701. children := treenode.HeadingChildren(n)
  702. for _, c := range children {
  703. unlinks = append(unlinks, c)
  704. }
  705. }
  706. }
  707. return ast.WalkContinue
  708. })
  709. for _, n := range unlinks {
  710. n.Unlink()
  711. }
  712. nodes = append(nodes, def)
  713. if 0 == headingMode && ast.NodeHeading == def.Type && "1" != def.IALAttr("fold") {
  714. children := treenode.HeadingChildren(def)
  715. for _, c := range children {
  716. if "1" == c.IALAttr("heading-fold") {
  717. // 嵌入块包含折叠标题时不应该显示其下方块 https://github.com/siyuan-note/siyuan/issues/4765
  718. continue
  719. }
  720. nodes = append(nodes, c)
  721. }
  722. }
  723. b := treenode.GetBlockTree(def.ID)
  724. if nil == b {
  725. return
  726. }
  727. // 嵌入块查询结果中显示块引用计数 https://github.com/siyuan-note/siyuan/issues/7191
  728. var defIDs []string
  729. for _, n := range nodes {
  730. defIDs = append(defIDs, n.ID)
  731. }
  732. refCount := sql.QueryRefCount(defIDs)
  733. for _, n := range nodes {
  734. if cnt := refCount[n.ID]; 0 < cnt {
  735. n.SetIALAttr("refcount", strconv.Itoa(cnt))
  736. }
  737. }
  738. luteEngine := NewLute()
  739. luteEngine.RenderOptions.ProtyleContenteditable = false // 不可编辑
  740. dom := renderBlockDOMByNodes(nodes, luteEngine)
  741. content := renderBlockContentByNodes(nodes)
  742. block = &Block{Box: def.Box, Path: def.Path, HPath: b.HPath, ID: def.ID, Type: def.Type.String(), Content: dom, Markdown: content /* 这里使用 Markdown 字段来临时存储 content */}
  743. if "" != sqlBlock.IAL {
  744. block.IAL = map[string]string{}
  745. ialStr := strings.TrimPrefix(sqlBlock.IAL, "{:")
  746. ialStr = strings.TrimSuffix(ialStr, "}")
  747. ial := parse.Tokens2IAL([]byte(ialStr))
  748. for _, kv := range ial {
  749. block.IAL[kv[0]] = kv[1]
  750. }
  751. }
  752. if breadcrumb {
  753. blockPaths = buildBlockBreadcrumb(def, nil)
  754. }
  755. if 1 > len(blockPaths) {
  756. blockPaths = []*BlockPath{}
  757. }
  758. return
  759. }