From 06a2f3fb5c7b4136d76cbaf353cec13e0604399a Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 11:49:35 +0800 Subject: [PATCH 01/19] :zap: Reduce disk reads when editing documents https://github.com/siyuan-note/siyuan/issues/10961 --- kernel/sql/database.go | 66 ++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/kernel/sql/database.go b/kernel/sql/database.go index 4cb5523ce9..dcd0b9bf2f 100644 --- a/kernel/sql/database.go +++ b/kernel/sql/database.go @@ -130,6 +130,11 @@ func initDBTables() { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create table [blocks] failed: %s", err) } + _, err = db.Exec("CREATE INDEX idx_blocks_id ON blocks(id)") + if nil != err { + logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create index [idx_blocks_id] failed: %s", err) + } + _, err = db.Exec("CREATE INDEX idx_blocks_root_id ON blocks(root_id)") if nil != err { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create index [idx_blocks_root_id] failed: %s", err) @@ -139,7 +144,7 @@ func initDBTables() { if nil != err { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "drop table [blocks_fts] failed: %s", err) } - _, err = db.Exec("CREATE VIRTUAL TABLE blocks_fts USING fts5(id UNINDEXED, parent_id UNINDEXED, root_id UNINDEXED, hash UNINDEXED, box UNINDEXED, path UNINDEXED, hpath, name, alias, memo, tag, content, fcontent, markdown UNINDEXED, length UNINDEXED, type UNINDEXED, subtype UNINDEXED, ial, sort UNINDEXED, created UNINDEXED, updated UNINDEXED, tokenize=\"siyuan\")") + _, err = db.Exec("CREATE VIRTUAL TABLE blocks_fts USING fts5(id, parent_id UNINDEXED, root_id UNINDEXED, hash UNINDEXED, box UNINDEXED, path UNINDEXED, hpath, name, alias, memo, tag, content, fcontent, markdown UNINDEXED, length UNINDEXED, type UNINDEXED, subtype UNINDEXED, ial, sort UNINDEXED, created UNINDEXED, updated UNINDEXED, tokenize=\"siyuan\")") if nil != err { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create table [blocks_fts] failed: %s", err) } @@ -148,7 +153,7 @@ func initDBTables() { if nil != err { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "drop table [blocks_fts_case_insensitive] failed: %s", err) } - _, err = db.Exec("CREATE VIRTUAL TABLE blocks_fts_case_insensitive USING fts5(id UNINDEXED, parent_id UNINDEXED, root_id UNINDEXED, hash UNINDEXED, box UNINDEXED, path UNINDEXED, hpath, name, alias, memo, tag, content, fcontent, markdown UNINDEXED, length UNINDEXED, type UNINDEXED, subtype UNINDEXED, ial, sort UNINDEXED, created UNINDEXED, updated UNINDEXED, tokenize=\"siyuan case_insensitive\")") + _, err = db.Exec("CREATE VIRTUAL TABLE blocks_fts_case_insensitive USING fts5(id, parent_id UNINDEXED, root_id UNINDEXED, hash UNINDEXED, box UNINDEXED, path UNINDEXED, hpath, name, alias, memo, tag, content, fcontent, markdown UNINDEXED, length UNINDEXED, type UNINDEXED, subtype UNINDEXED, ial, sort UNINDEXED, created UNINDEXED, updated UNINDEXED, tokenize=\"siyuan case_insensitive\")") if nil != err { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create table [blocks_fts_case_insensitive] failed: %s", err) } @@ -954,30 +959,59 @@ func deleteByBoxTx(tx *sql.Tx, box string) (err error) { } func deleteBlocksByIDs(tx *sql.Tx, ids []string) (err error) { - in := bytes.Buffer{} - in.Grow(4096) - in.WriteString("(") + placeholders := strings.Repeat("?,", len(ids)) + placeholders = placeholders[:len(placeholders)-1] + stmt := "DELETE FROM blocks WHERE id IN (" + placeholders + ")" + args := make([]interface{}, len(ids)) for i, id := range ids { - in.WriteString("'") - in.WriteString(id) - in.WriteString("'") - if i < len(ids)-1 { - in.WriteString(",") - } + args[i] = id + } + if err = execStmtTx(tx, stmt, args...); nil != err { + return + } + var ftsIDs []string + for _, id := range ids { removeBlockCache(id) + ftsIDs = append(ftsIDs, "\""+id+"\"") } - in.WriteString(")") - stmt := "DELETE FROM blocks WHERE id IN " + in.String() - if err = execStmtTx(tx, stmt); nil != err { + stmt = "SELECT ROWID FROM blocks_fts WHERE blocks_fts MATCH 'id:(" + strings.Join(ftsIDs, " OR ") + ")'" + rows, err := tx.Query(stmt) + if nil != err { + logging.LogErrorf("query blocks_fts failed: %s", err) return } - stmt = "DELETE FROM blocks_fts WHERE id IN " + in.String() + var rowIDs []string + for rows.Next() { + var rowID int + if err = rows.Scan(&rowID); nil != err { + return + } + rowIDs = append(rowIDs, fmt.Sprintf("%d", rowID)) + } + rows.Close() + stmt = "DELETE FROM blocks_fts WHERE rowid IN (" + strings.Join(rowIDs, ",") + ")" if err = execStmtTx(tx, stmt); nil != err { return } + if !caseSensitive { - stmt = "DELETE FROM blocks_fts_case_insensitive WHERE id IN " + in.String() + stmt = "SELECT ROWID FROM blocks_fts_case_insensitive WHERE blocks_fts_case_insensitive MATCH 'id:(" + strings.Join(ftsIDs, " OR ") + ")'" + rows, err = tx.Query(stmt) + if nil != err { + logging.LogErrorf("query blocks_fts_case_insensitive failed: %s", err) + return + } + rowIDs = nil + for rows.Next() { + var rowID int + if err = rows.Scan(&rowID); nil != err { + return + } + rowIDs = append(rowIDs, fmt.Sprintf("%d", rowID)) + } + rows.Close() + stmt = "DELETE FROM blocks_fts_case_insensitive WHERE rowid IN (" + strings.Join(rowIDs, ",") + ")" if err = execStmtTx(tx, stmt); nil != err { return } From 616821a090e77daa43a01bdf93717c95a90a6193 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 15:38:40 +0800 Subject: [PATCH 02/19] :zap: Reduce disk reads when editing documents https://github.com/siyuan-note/siyuan/issues/10961 --- kernel/sql/database.go | 48 ++++++------------------------------------ 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/kernel/sql/database.go b/kernel/sql/database.go index dcd0b9bf2f..d709b29644 100644 --- a/kernel/sql/database.go +++ b/kernel/sql/database.go @@ -959,59 +959,25 @@ func deleteByBoxTx(tx *sql.Tx, box string) (err error) { } func deleteBlocksByIDs(tx *sql.Tx, ids []string) (err error) { - placeholders := strings.Repeat("?,", len(ids)) - placeholders = placeholders[:len(placeholders)-1] - stmt := "DELETE FROM blocks WHERE id IN (" + placeholders + ")" - args := make([]interface{}, len(ids)) - for i, id := range ids { - args[i] = id - } - if err = execStmtTx(tx, stmt, args...); nil != err { - return - } - var ftsIDs []string for _, id := range ids { removeBlockCache(id) ftsIDs = append(ftsIDs, "\""+id+"\"") } - stmt = "SELECT ROWID FROM blocks_fts WHERE blocks_fts MATCH 'id:(" + strings.Join(ftsIDs, " OR ") + ")'" - rows, err := tx.Query(stmt) - if nil != err { - logging.LogErrorf("query blocks_fts failed: %s", err) + + stmt := "DELETE FROM blocks WHERE id IN (" + strings.Join(ftsIDs, ",") + ")" + if err = execStmtTx(tx, stmt); nil != err { return } - var rowIDs []string - for rows.Next() { - var rowID int - if err = rows.Scan(&rowID); nil != err { - return - } - rowIDs = append(rowIDs, fmt.Sprintf("%d", rowID)) - } - rows.Close() - stmt = "DELETE FROM blocks_fts WHERE rowid IN (" + strings.Join(rowIDs, ",") + ")" + + ftsIDsMatch := strings.Join(ftsIDs, " OR ") + stmt = "DELETE FROM blocks_fts WHERE rowid IN (SELECT ROWID FROM blocks_fts WHERE blocks_fts MATCH 'id:(" + ftsIDsMatch + ")')" if err = execStmtTx(tx, stmt); nil != err { return } if !caseSensitive { - stmt = "SELECT ROWID FROM blocks_fts_case_insensitive WHERE blocks_fts_case_insensitive MATCH 'id:(" + strings.Join(ftsIDs, " OR ") + ")'" - rows, err = tx.Query(stmt) - if nil != err { - logging.LogErrorf("query blocks_fts_case_insensitive failed: %s", err) - return - } - rowIDs = nil - for rows.Next() { - var rowID int - if err = rows.Scan(&rowID); nil != err { - return - } - rowIDs = append(rowIDs, fmt.Sprintf("%d", rowID)) - } - rows.Close() - stmt = "DELETE FROM blocks_fts_case_insensitive WHERE rowid IN (" + strings.Join(rowIDs, ",") + ")" + stmt = "DELETE FROM blocks_fts_case_insensitive WHERE rowid IN (SELECT ROWID FROM blocks_fts_case_insensitive WHERE blocks_fts_case_insensitive MATCH 'id:(" + ftsIDsMatch + ")')" if err = execStmtTx(tx, stmt); nil != err { return } From 5e99a372424a5f92e2810ea59cbdb46783b4ed3e Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 15:39:00 +0800 Subject: [PATCH 03/19] :zap: Reduce disk reads when editing documents https://github.com/siyuan-note/siyuan/issues/10961 --- kernel/sql/database.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/sql/database.go b/kernel/sql/database.go index d709b29644..e29d2e6336 100644 --- a/kernel/sql/database.go +++ b/kernel/sql/database.go @@ -971,13 +971,13 @@ func deleteBlocksByIDs(tx *sql.Tx, ids []string) (err error) { } ftsIDsMatch := strings.Join(ftsIDs, " OR ") - stmt = "DELETE FROM blocks_fts WHERE rowid IN (SELECT ROWID FROM blocks_fts WHERE blocks_fts MATCH 'id:(" + ftsIDsMatch + ")')" + stmt = "DELETE FROM blocks_fts WHERE ROWID IN (SELECT ROWID FROM blocks_fts WHERE blocks_fts MATCH 'id:(" + ftsIDsMatch + ")')" if err = execStmtTx(tx, stmt); nil != err { return } if !caseSensitive { - stmt = "DELETE FROM blocks_fts_case_insensitive WHERE rowid IN (SELECT ROWID FROM blocks_fts_case_insensitive WHERE blocks_fts_case_insensitive MATCH 'id:(" + ftsIDsMatch + ")')" + stmt = "DELETE FROM blocks_fts_case_insensitive WHERE ROWID IN (SELECT ROWID FROM blocks_fts_case_insensitive WHERE blocks_fts_case_insensitive MATCH 'id:(" + ftsIDsMatch + ")')" if err = execStmtTx(tx, stmt); nil != err { return } From 3f62aea1e9d4b796fc5744f3f33cbf2fd0dd063d Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 15:57:18 +0800 Subject: [PATCH 04/19] :art: Import md progress --- kernel/model/import.go | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/model/import.go b/kernel/model/import.go index 938cf00e98..5552f3e9d9 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -899,6 +899,7 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) { util.PushEndlessProgress(fmt.Sprintf(Conf.Language(66), fmt.Sprintf("%d/%d ", i, len(importTrees))+tree.HPath)) } } + util.PushClearProgress() importTrees = []*parse.Tree{} searchLinks = map[string]string{} From 803afcf481092730197efe75cbe63f62a08c7b49 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 10 Apr 2024 16:19:31 +0800 Subject: [PATCH 05/19] :art: fix https://github.com/siyuan-note/siyuan/issues/10958 --- app/src/protyle/gutter/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index b0cec7d52f..7470734a03 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -842,6 +842,7 @@ export class Gutter { srcIDs: sourceIds, avID, }]); + focusBlock(selectsElement[0]) }); } }).element); @@ -1302,6 +1303,7 @@ export class Gutter { srcIDs: sourceIds, avID, }]); + focusBlock(nodeElement) }); } }).element); From 3b339656c9d3a11b4032dc8b5b4e1e9e0c992d43 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 10 Apr 2024 16:45:55 +0800 Subject: [PATCH 06/19] :art: fix https://github.com/siyuan-note/siyuan/issues/10962 --- app/electron/main.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/electron/main.js b/app/electron/main.js index 0bae340644..76308e509d 100644 --- a/app/electron/main.js +++ b/app/electron/main.js @@ -1202,7 +1202,9 @@ app.whenReady().then(() => { app.on("open-url", async (event, url) => { // for macOS if (url.startsWith("siyuan://")) { + let isBackground = true; if (workspaces.length === 0) { + isBackground = false; let index = 0; while (index < 10) { index++; @@ -1212,6 +1214,9 @@ app.on("open-url", async (event, url) => { // for macOS } } } + if (!isBackground) { + await sleep(1500); + } workspaces.forEach(item => { if (item.browserWindow && !item.browserWindow.isDestroyed()) { item.browserWindow.webContents.send("siyuan-open-url", url); From aed87dfd15a360ef01eeb28276b86de99ff4f003 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 17:02:11 +0800 Subject: [PATCH 07/19] :bug: Dynamic loading results in incomplete list display https://github.com/siyuan-note/siyuan/issues/10965 --- kernel/treenode/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/treenode/node.go b/kernel/treenode/node.go index 2ffed90f88..91b31af858 100644 --- a/kernel/treenode/node.go +++ b/kernel/treenode/node.go @@ -342,7 +342,7 @@ func FirstLeafBlock(node *ast.Node) (ret *ast.Node) { func CountBlockNodes(node *ast.Node) (ret int) { ast.Walk(node, func(n *ast.Node, entering bool) ast.WalkStatus { - if !entering || !n.IsBlock() || ast.NodeList == n.Type || ast.NodeListItem == n.Type || ast.NodeBlockquote == n.Type || ast.NodeSuperBlock == n.Type { + if !entering || !n.IsBlock() || ast.NodeList == n.Type || ast.NodeBlockquote == n.Type || ast.NodeSuperBlock == n.Type { return ast.WalkContinue } From e9deb4624be6c68e29456be7c69be17511385c81 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 17:27:17 +0800 Subject: [PATCH 08/19] :bug: Database relation field search cannot search for some values https://github.com/siyuan-note/siyuan/issues/10966 --- kernel/model/attribute_view.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 0dbe323b46..d338f7d13b 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -83,9 +83,7 @@ func GetAttributeViewPrimaryKeyValues(avID, keyword string, page, pageSize int) } } - if gulu.Str.Contains(kv.Block.ID, view.Table.RowIDs) { - tmp[kv.Block.ID] = kv - } + tmp[kv.Block.ID] = kv } } } From f6cd80c7193b82651575e2b66c2a773d6db4120e Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 17:28:30 +0800 Subject: [PATCH 09/19] :bug: Database relation field search cannot search for some values https://github.com/siyuan-note/siyuan/issues/10966 --- kernel/model/attribute_view.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index d338f7d13b..72168ee4f5 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -95,7 +95,7 @@ func GetAttributeViewPrimaryKeyValues(avID, keyword string, page, pageSize int) } if 1 > pageSize { - pageSize = 32 + pageSize = 16 } start := (page - 1) * pageSize end := start + pageSize From dd6be581b70c928330aab77a16c15746c5f6095d Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 10 Apr 2024 18:01:28 +0800 Subject: [PATCH 10/19] :art: fix https://github.com/siyuan-note/siyuan/issues/10968 --- app/src/layout/dock/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/layout/dock/index.ts b/app/src/layout/dock/index.ts index 9c7b3f3161..52de07d253 100644 --- a/app/src/layout/dock/index.ts +++ b/app/src/layout/dock/index.ts @@ -30,6 +30,7 @@ export class Dock { public resizeElement: HTMLElement; public pin = true; public data: { [key: string]: Model | boolean }; + private hideResizeTimeout:number constructor(options: { app: App, @@ -360,6 +361,7 @@ export class Dock { this.layout.element.style.height = "0px"; } this.resizeElement.classList.add("fn__none"); + clearTimeout(this.hideResizeTimeout); this.hideDock(); } if ((type === "graph" || type === "globalGraph") && this.layout.element.querySelector(".fullscreen")) { @@ -516,7 +518,7 @@ export class Dock { } if (this.pin) { this.layout.element.style.opacity = ""; - setTimeout(() => { + this.hideResizeTimeout = window.setTimeout(() => { this.resizeElement.classList.remove("fn__none"); }, 200); // 需等待动画完毕后再出现,否则会出现滚动条 https://ld246.com/article/1676596622064 } From 444f87391913ccd25d451d2b9734d53be1989e01 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 18:02:07 +0800 Subject: [PATCH 11/19] :art: Improve data indexing --- kernel/sql/database.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernel/sql/database.go b/kernel/sql/database.go index e29d2e6336..15db0723eb 100644 --- a/kernel/sql/database.go +++ b/kernel/sql/database.go @@ -959,6 +959,10 @@ func deleteByBoxTx(tx *sql.Tx, box string) (err error) { } func deleteBlocksByIDs(tx *sql.Tx, ids []string) (err error) { + if 1 > len(ids) { + return + } + var ftsIDs []string for _, id := range ids { removeBlockCache(id) @@ -1136,6 +1140,10 @@ func deleteByRootID(tx *sql.Tx, rootID string, context map[string]interface{}) ( } func batchDeleteByRootIDs(tx *sql.Tx, rootIDs []string, context map[string]interface{}) (err error) { + if 1 > len(rootIDs) { + return + } + ids := strings.Join(rootIDs, "','") ids = "('" + ids + "')" stmt := "DELETE FROM blocks WHERE root_id IN " + ids From 339c69c503a956ed1aa2db71650109ca6bffc060 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 18:04:56 +0800 Subject: [PATCH 12/19] :bug: Database date field between filter calculation error https://github.com/siyuan-note/siyuan/issues/10967 --- kernel/av/filter.go | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/kernel/av/filter.go b/kernel/av/filter.go index f830f4a8e8..632fd856d8 100644 --- a/kernel/av/filter.go +++ b/kernel/av/filter.go @@ -248,7 +248,7 @@ func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDa direction := relativeDate.Direction relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction) _, relativeTimeEnd2 := calcRelativeTimeRegion(relativeDate2.Count, relativeDate2.Unit, relativeDate2.Direction) - return filterTime(value.Date.Content, value.Date.IsNotEmpty, relativeTimeStart, relativeTimeEnd, relativeTimeEnd2, operator) + return filterRelativeTime(value.Date.Content, value.Date.IsNotEmpty, relativeTimeStart, relativeTimeEnd, relativeTimeEnd2, operator) } else { // 使用具体时间比较 if nil == other.Date { return true @@ -257,7 +257,7 @@ func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDa otherTime := time.UnixMilli(other.Date.Content) otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location()) otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location()) - return filterTime(value.Date.Content, value.Date.IsNotEmpty, otherStart, otherEnd, time.Now(), operator) + return filterTime(value.Date.Content, value.Date.IsNotEmpty, otherStart, otherEnd, operator) } } case KeyTypeCreated: @@ -269,7 +269,7 @@ func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDa unit := relativeDate.Unit direction := relativeDate.Direction relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction) - return filterTime(value.Created.Content, true, relativeTimeStart, relativeTimeEnd, time.Now(), operator) + return filterRelativeTime(value.Created.Content, true, relativeTimeStart, relativeTimeEnd, time.Now(), operator) } else { // 使用具体时间比较 if nil == other.Created { return true @@ -278,7 +278,7 @@ func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDa otherTime := time.UnixMilli(other.Created.Content) otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location()) otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location()) - return filterTime(value.Created.Content, value.Created.IsNotEmpty, otherStart, otherEnd, time.Now(), operator) + return filterTime(value.Created.Content, value.Created.IsNotEmpty, otherStart, otherEnd, operator) } } case KeyTypeUpdated: @@ -290,7 +290,7 @@ func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDa unit := relativeDate.Unit direction := relativeDate.Direction relativeTimeStart, relativeTimeEnd := calcRelativeTimeRegion(count, unit, direction) - return filterTime(value.Updated.Content, true, relativeTimeStart, relativeTimeEnd, time.Now(), operator) + return filterRelativeTime(value.Updated.Content, true, relativeTimeStart, relativeTimeEnd, time.Now(), operator) } else { // 使用具体时间比较 if nil == other.Updated { return true @@ -299,7 +299,7 @@ func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDa otherTime := time.UnixMilli(other.Updated.Content) otherStart := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 0, 0, 0, 0, otherTime.Location()) otherEnd := time.Date(otherTime.Year(), otherTime.Month(), otherTime.Day(), 23, 59, 59, 999999999, otherTime.Location()) - return filterTime(value.Updated.Content, value.Updated.IsNotEmpty, otherStart, otherEnd, time.Now(), operator) + return filterTime(value.Updated.Content, value.Updated.IsNotEmpty, otherStart, otherEnd, operator) } } case KeyTypeSelect, KeyTypeMSelect: @@ -520,7 +520,7 @@ func (value *Value) filter(other *Value, relativeDate, relativeDate2 *RelativeDa return false } -func filterTime(valueMills int64, valueIsNotEmpty bool, otherValueStart, otherValueEnd, otherValueEnd2 time.Time, operator FilterOperator) bool { +func filterRelativeTime(valueMills int64, valueIsNotEmpty bool, otherValueStart, otherValueEnd, otherValueEnd2 time.Time, operator FilterOperator) bool { valueTime := time.UnixMilli(valueMills) switch operator { case FilterOperatorIsEqual: @@ -545,6 +545,31 @@ func filterTime(valueMills int64, valueIsNotEmpty bool, otherValueStart, otherVa return false } +func filterTime(valueMills int64, valueIsNotEmpty bool, otherValueStart, otherValueEnd time.Time, operator FilterOperator) bool { + valueTime := time.UnixMilli(valueMills) + switch operator { + case FilterOperatorIsEqual: + return (valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)) && valueTime.Before(otherValueEnd) + case FilterOperatorIsNotEqual: + return valueTime.Before(otherValueStart) || valueTime.After(otherValueEnd) + case FilterOperatorIsGreater: + return valueTime.After(otherValueEnd) || valueTime.Equal(otherValueEnd) + case FilterOperatorIsGreaterOrEqual: + return valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart) + case FilterOperatorIsLess: + return valueTime.Before(otherValueStart) + case FilterOperatorIsLessOrEqual: + return valueTime.Before(otherValueEnd) || valueTime.Equal(otherValueEnd) + case FilterOperatorIsBetween: + return (valueTime.After(otherValueStart) || valueTime.Equal(otherValueStart)) && (valueTime.Before(otherValueEnd) || valueTime.Equal(otherValueEnd)) + case FilterOperatorIsEmpty: + return !valueIsNotEmpty + case FilterOperatorIsNotEmpty: + return valueIsNotEmpty + } + return false +} + // 根据 Count、Unit 和 Direction 计算相对当前时间的开始时间和结束时间 func calcRelativeTimeRegion(count int, unit RelativeDateUnit, direction RelativeDateDirection) (start, end time.Time) { now := time.Now() From 9cc706c1b24c2303ca4bade24aefa6c0a2db804e Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 10 Apr 2024 18:35:45 +0800 Subject: [PATCH 13/19] :art: fix https://github.com/siyuan-note/siyuan/issues/10969 --- app/src/layout/dock/Outline.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/layout/dock/Outline.ts b/app/src/layout/dock/Outline.ts index 352dad3958..79abc2ccb8 100644 --- a/app/src/layout/dock/Outline.ts +++ b/app/src/layout/dock/Outline.ts @@ -229,7 +229,7 @@ export class Outline extends Model { private bindSort() { this.element.addEventListener("mousedown", (event: MouseEvent) => { const item = hasClosestByClassName(event.target as HTMLElement, "b3-list-item"); - if (!item || item.tagName !== "LI") { + if (!item || item.tagName !== "LI" || this.element.getAttribute("data-loading") === "true") { return; } const documentSelf = document; @@ -244,7 +244,7 @@ export class Outline extends Model { } }); documentSelf.onmousemove = (moveEvent: MouseEvent) => { - if (!editor || editor.disabled || moveEvent.clientY === event.clientY && moveEvent.clientX === event.clientX || this.element.getAttribute("data-loading") === "true") { + if (!editor || editor.disabled || moveEvent.clientY === event.clientY && moveEvent.clientX === event.clientX) { return; } moveEvent.preventDefault(); @@ -327,6 +327,10 @@ export class Outline extends Model { previousID: undoPreviousID, parentID: undoParentID, }]); + // https://github.com/siyuan-note/siyuan/issues/10828#issuecomment-2044099675 + editor.wysiwyg.element.querySelectorAll('[data-type="NodeHeading"] [contenteditable="true"][spellcheck]').forEach(item => { + item.setAttribute("contenteditable", "false"); + }); return true; } this.element.querySelectorAll(".dragover__top, .dragover__bottom, .dragover").forEach(item => { From a5ec51a3d160bdd884603a37d1a6b8ecb8c378d4 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 20:49:08 +0800 Subject: [PATCH 14/19] :zap: Reduce disk reads when editing documents https://github.com/siyuan-note/siyuan/issues/10961 --- kernel/sql/database.go | 41 +++++++++++++++++++++-------------------- kernel/sql/upsert.go | 6 +++--- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/kernel/sql/database.go b/kernel/sql/database.go index 15db0723eb..1e752d8643 100644 --- a/kernel/sql/database.go +++ b/kernel/sql/database.go @@ -166,6 +166,10 @@ func initDBTables() { if nil != err { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create table [spans] failed: %s", err) } + _, err = db.Exec("CREATE INDEX idx_spans_root_id ON spans(root_id)") + if nil != err { + logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create index [idx_spans_root_id] failed: %s", err) + } _, err = db.Exec("DROP TABLE IF EXISTS assets") if nil != err { @@ -175,6 +179,10 @@ func initDBTables() { if nil != err { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create table [assets] failed: %s", err) } + _, err = db.Exec("CREATE INDEX idx_assets_root_id ON assets(root_id)") + if nil != err { + logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create index [idx_assets_root_id] failed: %s", err) + } _, err = db.Exec("DROP TABLE IF EXISTS attributes") if nil != err { @@ -184,6 +192,10 @@ func initDBTables() { if nil != err { logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create table [attributes] failed: %s", err) } + _, err = db.Exec("CREATE INDEX idx_attributes_root_id ON attributes(root_id)") + if nil != err { + logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "create index [idx_attributes_root_id] failed: %s", err) + } _, err = db.Exec("DROP TABLE IF EXISTS refs") if nil != err { @@ -1008,12 +1020,6 @@ func deleteBlocksByBoxTx(tx *sql.Tx, box string) (err error) { return } -func deleteSpansByPathTx(tx *sql.Tx, box, path string) (err error) { - stmt := "DELETE FROM spans WHERE box = ? AND path = ?" - err = execStmtTx(tx, stmt, box, path) - return -} - func deleteSpansByRootID(tx *sql.Tx, rootID string) (err error) { stmt := "DELETE FROM spans WHERE root_id =?" err = execStmtTx(tx, stmt, rootID) @@ -1026,28 +1032,23 @@ func deleteSpansByBoxTx(tx *sql.Tx, box string) (err error) { return } -func deleteAssetsByPathTx(tx *sql.Tx, box, path string) (err error) { - stmt := "DELETE FROM assets WHERE box = ? AND docpath = ?" - err = execStmtTx(tx, stmt, box, path) +func deleteAssetsByRootID(tx *sql.Tx, rootID string) (err error) { + stmt := "DELETE FROM assets WHERE root_id = ?" + err = execStmtTx(tx, stmt, rootID) return } -func deleteAttributeByBlockID(tx *sql.Tx, blockID string) (err error) { - stmt := "DELETE FROM attributes WHERE block_id = ?" - err = execStmtTx(tx, stmt, blockID) +func deleteAssetsByBoxTx(tx *sql.Tx, box string) (err error) { + stmt := "DELETE FROM assets WHERE box = ?" + err = execStmtTx(tx, stmt, box) return } -func deleteAttributesByPathTx(tx *sql.Tx, box, path string) (err error) { - stmt := "DELETE FROM attributes WHERE box = ? AND path = ?" - err = execStmtTx(tx, stmt, box, path) +func deleteAttributesByRootID(tx *sql.Tx, rootID string) (err error) { + stmt := "DELETE FROM attributes WHERE root_id = ?" + err = execStmtTx(tx, stmt, rootID) return -} -func deleteAssetsByBoxTx(tx *sql.Tx, box string) (err error) { - stmt := "DELETE FROM assets WHERE box = ?" - err = execStmtTx(tx, stmt, box) - return } func deleteAttributesByBoxTx(tx *sql.Tx, box string) (err error) { diff --git a/kernel/sql/upsert.go b/kernel/sql/upsert.go index 33c93b309d..06c5c37cfb 100644 --- a/kernel/sql/upsert.go +++ b/kernel/sql/upsert.go @@ -440,13 +440,13 @@ func upsertTree(tx *sql.Tx, tree *parse.Tree, context map[string]interface{}) (e return } - if err = deleteSpansByPathTx(tx, tree.Box, tree.Path); nil != err { + if err = deleteSpansByRootID(tx, tree.ID); nil != err { return } - if err = deleteAssetsByPathTx(tx, tree.Box, tree.Path); nil != err { + if err = deleteAssetsByRootID(tx, tree.ID); nil != err { return } - if err = deleteAttributesByPathTx(tx, tree.Box, tree.Path); nil != err { + if err = deleteAttributesByRootID(tx, tree.ID); nil != err { return } if err = deleteRefsByPathTx(tx, tree.Box, tree.Path); nil != err { From 4033b15ee82c905ac0d07984c45c0a196f482ae7 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 21:32:08 +0800 Subject: [PATCH 15/19] :art: Improve notification https://ld246.com/article/1712750404715 --- kernel/model/cloud_service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/model/cloud_service.go b/kernel/model/cloud_service.go index 612aa87e52..dcbe38dd81 100644 --- a/kernel/model/cloud_service.go +++ b/kernel/model/cloud_service.go @@ -246,7 +246,7 @@ func refreshSubscriptionExpirationRemind() { if 0 < remains && expireDay > remains { util.WaitForUILoaded() - time.Sleep(time.Second * 3) + time.Sleep(time.Second * 7) util.PushErrMsg(fmt.Sprintf(Conf.Language(127), remains), 0) return } From d08ffd8f419091aaf059e2dbd61d7a5f05938d79 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 10 Apr 2024 22:01:21 +0800 Subject: [PATCH 16/19] :art: fix https://github.com/siyuan-note/siyuan/issues/10829 --- app/src/protyle/render/av/select.ts | 12 ++---------- app/src/util/upDownHint.ts | 7 ++++++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/src/protyle/render/av/select.ts b/app/src/protyle/render/av/select.ts index 7742fa8cae..57fb025c83 100644 --- a/app/src/protyle/render/av/select.ts +++ b/app/src/protyle/render/av/select.ts @@ -17,13 +17,12 @@ const filterSelectHTML = (key: string, options: { name: string, color: string }[ selected.push(item.dataset.content); }); } - const checkedName = document.querySelector('.av__panel .b3-menu__item--current[data-type="addColOptionOrCell"]')?.getAttribute("data-name") || ""; if (options) { options.forEach(item => { if (!key || (key.toLowerCase().indexOf(item.name.toLowerCase()) > -1 || item.name.toLowerCase().indexOf(key.toLowerCase()) > -1)) { - html += `${html}`; - } else if (html.indexOf("b3-menu__item--current") === -1) { - if (key) { - html = html.replace(`class="b3-menu__item" data-name="${key}"`, `class="b3-menu__item b3-menu__item--current" data-name="${key}"`); - } else { - html = html.replace('class="b3-menu__item"', 'class="b3-menu__item b3-menu__item--current"'); - } } return html; }; @@ -423,7 +415,7 @@ export const bindSelectEvent = (protyle: IProtyle, data: IAV, menuElement: HTMLE if (event.isComposing) { return; } - let currentElement = upDownHint(listElement, event, "b3-menu__item--current"); + let currentElement = upDownHint(listElement, event, "b3-menu__item--current", listElement.firstElementChild); if (event.key === "Enter") { if (!currentElement) { currentElement = menuElement.querySelector(".b3-menu__item--current"); diff --git a/app/src/util/upDownHint.ts b/app/src/util/upDownHint.ts index 83e6133760..01cdb5b5bb 100644 --- a/app/src/util/upDownHint.ts +++ b/app/src/util/upDownHint.ts @@ -2,8 +2,13 @@ const isNormalItem = (currentHintElement: HTMLElement, className: string) => { return currentHintElement.classList.contains("fn__none") || !currentHintElement.classList.contains(className); }; -export const upDownHint = (listElement: Element, event: KeyboardEvent, classActiveName = "b3-list-item--focus") => { +export const upDownHint = (listElement: Element, event: KeyboardEvent, classActiveName = "b3-list-item--focus", defaultElement?: Element) => { let currentHintElement: HTMLElement = listElement.querySelector("." + classActiveName); + if (!currentHintElement && defaultElement) { + defaultElement.classList.add(classActiveName); + defaultElement.scrollIntoView(true); + return; + } if (!currentHintElement) { return; } From 12ee5d5c4db4d4702744e21d3227a414bb83fab1 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 10 Apr 2024 22:38:48 +0800 Subject: [PATCH 17/19] :art: fix https://github.com/siyuan-note/siyuan/issues/10895 --- app/src/menus/index.ts | 8 +++++++- app/src/protyle/render/av/cell.ts | 9 ++++++++- app/src/protyle/render/av/openMenuPanel.ts | 14 +++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/app/src/menus/index.ts b/app/src/menus/index.ts index dd71910940..5caee18dea 100644 --- a/app/src/menus/index.ts +++ b/app/src/menus/index.ts @@ -7,7 +7,7 @@ import {initNavigationMenu, initFileMenu} from "./navigation"; import {initTabMenu} from "./tab"; /// #endif import {Menu} from "./Menu"; -import {hasTopClosestByTag} from "../protyle/util/hasClosest"; +import {hasClosestByClassName, hasTopClosestByTag} from "../protyle/util/hasClosest"; import {App} from "../index"; @@ -73,6 +73,12 @@ export class Menus { break; } + if (hasClosestByClassName(target, "av__panel") && !hasClosestByClassName(target, "b3-menu")) { + document.querySelector(".av__panel").dispatchEvent(new CustomEvent("click", {detail: "close"})) + event.stopPropagation(); + break; + } + target = target.parentElement; } }, false); diff --git a/app/src/protyle/render/av/cell.ts b/app/src/protyle/render/av/cell.ts index 7f8689f285..fae6b21ae4 100644 --- a/app/src/protyle/render/av/cell.ts +++ b/app/src/protyle/render/av/cell.ts @@ -439,12 +439,19 @@ export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[], type } }); } - avMaskElement.addEventListener("click", (event) => { + + const removeAvMask = (event: Event) => { if ((event.target as HTMLElement).classList.contains("av__mask") && document.activeElement.tagName !== "TEXTAREA" && document.activeElement.tagName !== "INPUT") { updateCellValueByInput(protyle, type, blockElement, cellElements); avMaskElement?.remove(); } + } + avMaskElement.addEventListener("click", (event) => { + removeAvMask(event) + }); + avMaskElement.addEventListener("contextmenu", (event) => { + removeAvMask(event) }); }; diff --git a/app/src/protyle/render/av/openMenuPanel.ts b/app/src/protyle/render/av/openMenuPanel.ts index 11a04b11c8..50034dd9ec 100644 --- a/app/src/protyle/render/av/openMenuPanel.ts +++ b/app/src/protyle/render/av/openMenuPanel.ts @@ -456,10 +456,14 @@ export const openMenuPanel = (options: { window.siyuan.dragElement = undefined; } }); - avPanelElement.addEventListener("click", (event) => { + avPanelElement.addEventListener("click", (event: MouseEvent) => { + let type: string; + if (typeof event.detail === "string") { + type = event.detail; + } let target = event.target as HTMLElement; - while (target && !target.isSameNode(avPanelElement)) { - const type = target.dataset.type; + while (target && !target.isSameNode(avPanelElement) || type) { + type = target.dataset.type || type; if (type === "close") { if (!options.protyle.toolbar.subElement.classList.contains("fn__none")) { // 优先关闭资源文件搜索 @@ -480,6 +484,7 @@ export const openMenuPanel = (options: { menuElement.innerHTML = getViewHTML(data.view); setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height); bindViewEvent({protyle: options.protyle, data, menuElement, blockElement: options.blockElement}); + window.siyuan.menus.menu.remove(); event.preventDefault(); event.stopPropagation(); break; @@ -488,6 +493,7 @@ export const openMenuPanel = (options: { tabRect = options.blockElement.querySelector(".av__views").getBoundingClientRect(); menuElement.innerHTML = getPropertiesHTML(data.view); setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height); + window.siyuan.menus.menu.remove(); event.preventDefault(); event.stopPropagation(); break; @@ -495,6 +501,7 @@ export const openMenuPanel = (options: { menuElement.innerHTML = getSortsHTML(data.view.columns, data.view.sorts); bindSortsEvent(options.protyle, menuElement, data, blockID); setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height); + window.siyuan.menus.menu.remove(); event.preventDefault(); event.stopPropagation(); break; @@ -558,6 +565,7 @@ export const openMenuPanel = (options: { } else if (type === "goFilters") { menuElement.innerHTML = getFiltersHTML(data.view); setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height); + window.siyuan.menus.menu.remove(); event.preventDefault(); event.stopPropagation(); break; From fc3263985bf3cdbbd7ea1c697adfa08cda8b78c7 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 10 Apr 2024 22:58:59 +0800 Subject: [PATCH 18/19] :art: Improve database primary key binding block https://github.com/siyuan-note/siyuan/issues/10945 --- app/appearance/langs/en_US.json | 3 ++- app/appearance/langs/es_ES.json | 3 ++- app/appearance/langs/fr_FR.json | 3 ++- app/appearance/langs/zh_CHT.json | 3 ++- app/appearance/langs/zh_CN.json | 3 ++- kernel/model/attribute_view.go | 12 ++++++++++++ 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json index 80afc6e7d9..fa5a508899 100644 --- a/app/appearance/langs/en_US.json +++ b/app/appearance/langs/en_US.json @@ -1471,6 +1471,7 @@ "238": "Marketplace package [%s] update failed, please try again later", "239": "Related operations are being processed, please try again later", "240": "Drag heading under container blocks in the doc is not supported", - "241": "Drag to its subheading is not supported" + "241": "Drag to its subheading is not supported", + "242": "The binding block already exists in the current database" } } diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json index 9c3c65fa3d..620fa4b3c0 100644 --- a/app/appearance/langs/es_ES.json +++ b/app/appearance/langs/es_ES.json @@ -1471,6 +1471,7 @@ "238": "Error en la actualización del paquete Marketplace [%s], inténtalo de nuevo más tarde", "239": "Las operaciones relacionadas se están procesando, inténtalo de nuevo más tarde", "240": "No se admite arrastrar encabezado debajo de los bloques contenedores en el documento", - "241": "No se admite arrastrar a su subtítulo" + "241": "No se admite arrastrar a su subtítulo", + "242": "El bloque de enlace ya existe en la base de datos actual" } } diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json index aaf039aa34..adbf842204 100644 --- a/app/appearance/langs/fr_FR.json +++ b/app/appearance/langs/fr_FR.json @@ -1471,6 +1471,7 @@ "238": "La mise à jour du package Marketplace [%s] a échoué, veuillez réessayer plus tard", "239": "Les opérations associées sont en cours de traitement, veuillez réessayer plus tard", "240": "Le déplacement du titre sous les blocs conteneurs dans la doc n'est pas pris en charge", - "241": "Le glisser vers son sous-titre n'est pas pris en charge" + "241": "Le glisser vers son sous-titre n'est pas pris en charge", + "242": "Le bloc de liaison existe déjà dans la base de données actuelle" } } diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json index 780c181ec4..d21ac9f4c6 100644 --- a/app/appearance/langs/zh_CHT.json +++ b/app/appearance/langs/zh_CHT.json @@ -1471,6 +1471,7 @@ "238": "市集包 [%s] 更新失敗,請稍後再試", "239": "相關操作正在處理中,請稍後再試", "240": "不支援拖曳文件中容器區塊下的標題", - "241": "不支持拖曳為自己的子標題" + "241": "不支持拖曳為自己的子標題", + "242": "目前資料庫中已經存在該綁定區塊" } } diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json index e41a3897e8..5325449e45 100644 --- a/app/appearance/langs/zh_CN.json +++ b/app/appearance/langs/zh_CN.json @@ -1471,6 +1471,7 @@ "238": "集市包 [%s] 更新失败,请稍后再试", "239": "相关操作正在处理中,请稍后再试", "240": "不支持拖拽文档中容器块下的标题", - "241": "不支持拖拽为自己的子标题" + "241": "不支持拖拽为自己的子标题", + "242": "当前数据库中已经存在该绑定块" } } diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 72168ee4f5..a0823574d9 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -2129,6 +2129,7 @@ func addAttributeViewBlock(avID, blockID, previousBlockID, addingBlockID string, blockValue.IsDetached = isDetached blockValue.Block.Content = content blockValue.UpdatedAt = now + util.PushMsg(Conf.language(242), 3000) err = av.SaveAttributeView(attrView) } return @@ -2869,6 +2870,17 @@ func replaceAttributeViewBlock(operation *Operation, tx *Transaction) (err error node, _, _ = getNodeByBlockID(tx, operation.NextID) } + // 检查是否已经存在绑定块 + // Improve database primary key binding block https://github.com/siyuan-note/siyuan/issues/10945 + for _, keyValues := range attrView.KeyValues { + for _, value := range keyValues.Values { + if value.BlockID == operation.NextID { + util.PushMsg(Conf.language(242), 3000) + return + } + } + } + for _, keyValues := range attrView.KeyValues { for _, value := range keyValues.Values { if value.BlockID == operation.PreviousID { From 98843fcd09c9a6ab439860eaa95f2f46c0ff808a Mon Sep 17 00:00:00 2001 From: Vanessa Date: Wed, 10 Apr 2024 23:02:00 +0800 Subject: [PATCH 19/19] :art: fix https://github.com/siyuan-note/siyuan/issues/10971 --- app/src/protyle/wysiwyg/keydown.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/protyle/wysiwyg/keydown.ts b/app/src/protyle/wysiwyg/keydown.ts index 50bd50bead..11247477c5 100644 --- a/app/src/protyle/wysiwyg/keydown.ts +++ b/app/src/protyle/wysiwyg/keydown.ts @@ -697,7 +697,9 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { } event.stopPropagation(); event.preventDefault(); - } else if (nodeEditableElement?.textContent.substr(position.end + 1).indexOf("\n") === -1) { + } else if (nodeEditableElement?.textContent.substr(position.end + 1).indexOf("\n") === -1 && + // table 下方为折叠块 + nodeEditableElement.tagName !== "TABLE") { // 下一个块是折叠块 const nextFoldElement = getNextBlock(nodeElement) as HTMLElement; if (nextFoldElement && nextFoldElement.getAttribute("fold") === "1") {