From 279a7e71b7e417bfde9791bcc79e790128f90af1 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Mon, 16 Jun 2025 23:32:48 +0800 Subject: [PATCH] :art: https://github.com/siyuan-note/siyuan/issues/10414 --- app/src/protyle/render/av/action.ts | 9 +++-- app/src/protyle/render/av/gallery/render.ts | 17 +-------- app/src/protyle/render/av/layout.ts | 35 ++++++++++--------- app/src/protyle/render/av/openMenuPanel.ts | 31 ++++++++++------- app/src/protyle/render/av/render.ts | 38 ++++++--------------- app/src/protyle/render/av/row.ts | 3 +- app/src/protyle/render/av/view.ts | 10 ++++-- app/src/protyle/wysiwyg/index.ts | 21 +++++++----- app/src/protyle/wysiwyg/transaction.ts | 2 +- app/src/types/index.d.ts | 2 +- 10 files changed, 78 insertions(+), 90 deletions(-) diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index c4023fa67..87235c1f0 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -118,9 +118,12 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle if (viewItemElement.classList.contains("item--focus")) { openViewMenu({protyle, blockElement, element: viewItemElement}); } else { - blockElement.removeAttribute("data-render"); - blockElement.setAttribute("data-av-type", viewItemElement.dataset.avType); - avRender(blockElement, protyle, undefined, viewItemElement.dataset.id); + transaction(protyle, [{ + action: "setAttrViewBlockView", + blockID: blockElement.getAttribute("data-node-id"), + id: viewItemElement.dataset.id, + avID: blockElement.getAttribute("data-av-id"), + }]); } event.preventDefault(); event.stopPropagation(); diff --git a/app/src/protyle/render/av/gallery/render.ts b/app/src/protyle/render/av/gallery/render.ts index fb0e4b694..3ed56ceab 100644 --- a/app/src/protyle/render/av/gallery/render.ts +++ b/app/src/protyle/render/av/gallery/render.ts @@ -14,7 +14,6 @@ export const renderGallery = (options: { blockElement: HTMLElement, protyle: IProtyle, cb?: (data: IAV) => void, - viewID?: string, renderAll: boolean }) => { const alignSelf = options.blockElement.style.alignSelf; @@ -42,20 +41,6 @@ export const renderGallery = (options: { }); const created = options.protyle.options.history?.created; const snapshot = options.protyle.options.history?.snapshot; - let newViewID = options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW) || ""; - if (typeof options.viewID === "string") { - const viewTabElement = options.blockElement.querySelector(`.av__views > .layout-tab-bar > .item[data-id="${options.viewID}"]`) as HTMLElement; - if (viewTabElement) { - options.blockElement.dataset.pageSize = viewTabElement.dataset.page; - } - newViewID = options.viewID; - fetchPost("/api/av/setDatabaseBlockView", { - id: options.blockElement.dataset.nodeId, - avID: options.blockElement.dataset.avId, - viewID: options.viewID - }); - options.blockElement.setAttribute(Constants.CUSTOM_SY_AV_VIEW, newViewID); - } let searchInputElement = options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement; const isSearching = searchInputElement && document.activeElement.isSameNode(searchInputElement); const query = searchInputElement?.value || ""; @@ -64,7 +49,7 @@ export const renderGallery = (options: { created, snapshot, pageSize: parseInt(options.blockElement.dataset.pageSize) || undefined, - viewID: newViewID, + viewID: options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW) || "", query: query.trim() }, (response) => { const view: IAVGallery = response.data.view; diff --git a/app/src/protyle/render/av/layout.ts b/app/src/protyle/render/av/layout.ts index 90516800c..bcc17e911 100644 --- a/app/src/protyle/render/av/layout.ts +++ b/app/src/protyle/render/av/layout.ts @@ -1,5 +1,6 @@ import {transaction} from "../../wysiwyg/transaction"; import {Constants} from "../../../constants"; +import {fetchPost} from "../../../util/fetch"; export const getLayoutHTML = (data: IAV) => { let html = ""; @@ -189,7 +190,7 @@ export const bindLayoutEvent = (options: { blockID, data: !checked }]); - options.blockElement.querySelectorAll('.av__gallery-fields').forEach(item => { + options.blockElement.querySelectorAll(".av__gallery-fields").forEach(item => { if (checked) { item.classList.add("av__gallery-fields--wrap"); } else { @@ -205,23 +206,25 @@ export const updateLayout = (options: { protyle: IProtyle, target: HTMLElement }) => { - if (options.target.classList.contains("av__layout-item--select")) { + if (options.target.classList.contains("av__layout-item--select") || options.target.dataset.load === "true") { return; } - const avID = options.nodeElement.getAttribute("data-av-id"); - const blockID = options.nodeElement.getAttribute("data-node-id"); - const layout = options.target.getAttribute("data-view-type"); - transaction(options.protyle, [{ - action: "changeAttrViewLayout", - avID, - blockID, - layout - }], [{ - action: "changeAttrViewLayout", - avID, - blockID, - layout: options.data.viewType - }]); + options.target.dataset.load = "true"; options.target.parentElement.querySelector(".av__layout-item--select").classList.remove("av__layout-item--select"); options.target.classList.add("av__layout-item--select"); + fetchPost("/api/av/changeAttrViewLayout", { + blockID: options.nodeElement.getAttribute("data-node-id"), + avID: options.nodeElement.getAttribute("data-av-id"), + layoutType: options.target.getAttribute("data-view-type") + }, (response) => { + const menuElement = document.querySelector(".av__panel").lastElementChild as HTMLElement; + menuElement.innerHTML = getLayoutHTML(response.data); + bindLayoutEvent({ + protyle: options.protyle, + data: response.data, + menuElement, + blockElement: options.nodeElement + }); + options.target.removeAttribute("data-load"); + }); }; diff --git a/app/src/protyle/render/av/openMenuPanel.ts b/app/src/protyle/render/av/openMenuPanel.ts index d9901a8da..602f5f692 100644 --- a/app/src/protyle/render/av/openMenuPanel.ts +++ b/app/src/protyle/render/av/openMenuPanel.ts @@ -1340,9 +1340,12 @@ export const openMenuPanel = (options: { if (!target.parentElement.classList.contains("b3-menu__item--current")) { avPanelElement.querySelector(".b3-menu__item--current")?.classList.remove("b3-menu__item--current"); target.parentElement.classList.add("b3-menu__item--current"); - options.blockElement.removeAttribute("data-render"); - options.blockElement.setAttribute("data-av-type", target.dataset.avType); - avRender(options.blockElement, options.protyle, undefined, target.parentElement.dataset.id); + transaction(options.protyle, [{ + action: "setAttrViewBlockView", + blockID, + id: target.parentElement.dataset.id, + avID + }]); } event.preventDefault(); event.stopPropagation(); @@ -1357,16 +1360,18 @@ export const openMenuPanel = (options: { } else { avPanelElement.querySelector(".b3-menu__item--current")?.classList.remove("b3-menu__item--current"); target.parentElement.classList.add("b3-menu__item--current"); - options.blockElement.removeAttribute("data-render"); - avRender(options.blockElement, options.protyle, () => { - openViewMenu({ - protyle: options.protyle, - blockElement: options.blockElement as HTMLElement, - element: target.parentElement - }); - avPanelElement.querySelector(".b3-chip--primary").classList.remove("b3-chip--primary"); - target.parentElement.querySelector(".b3-chip").classList.add("b3-chip--primary"); - }, target.parentElement.dataset.id); + transaction(options.protyle, [{ + action: "setAttrViewBlockView", + blockID, + id: target.parentElement.dataset.id, + avID, + }]); + window.siyuan.menus.menu.remove(); + openViewMenu({ + protyle: options.protyle, + blockElement: options.blockElement as HTMLElement, + element: target.parentElement + }); } event.preventDefault(); event.stopPropagation(); diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts index 14e5862b0..5701701f0 100644 --- a/app/src/protyle/render/av/render.ts +++ b/app/src/protyle/render/av/render.ts @@ -16,10 +16,8 @@ import {isInAndroid, isInHarmony, isInIOS} from "../../util/compatibility"; import {isMobile} from "../../../util/functions"; import {renderGallery} from "./gallery/render"; import {getViewIcon} from "./view"; -import {bindLayoutEvent, getLayoutHTML} from "./layout"; -import {setPosition} from "../../../util/setPosition"; -export const avRender = (element: Element, protyle: IProtyle, cb?: (data: IAV) => void, viewID?: string, renderAll = true) => { +export const avRender = (element: Element, protyle: IProtyle, cb?: (data: IAV) => void, renderAll = true) => { let avElements: Element[] = []; if (element.getAttribute("data-type") === "NodeAttributeView") { // 编辑器内代码块编辑渲染 @@ -40,7 +38,7 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: (data: IAV) = } if (e.getAttribute("data-av-type") === "gallery") { - renderGallery({blockElement: e, protyle, cb, viewID, renderAll}); + renderGallery({blockElement: e, protyle, cb, renderAll}); return; } @@ -85,16 +83,6 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: (data: IAV) = }); const created = protyle.options.history?.created; const snapshot = protyle.options.history?.snapshot; - let newViewID = e.getAttribute(Constants.CUSTOM_SY_AV_VIEW) || ""; - if (typeof viewID === "string") { - const viewTabElement = e.querySelector(`.av__views > .layout-tab-bar > .item[data-id="${viewID}"]`) as HTMLElement; - if (viewTabElement) { - e.dataset.pageSize = viewTabElement.dataset.page; - } - newViewID = viewID; - fetchPost("/api/av/setDatabaseBlockView", {id: e.dataset.nodeId, viewID, avID: e.dataset.avId,}); - e.setAttribute(Constants.CUSTOM_SY_AV_VIEW, newViewID); - } let searchInputElement = e.querySelector('[data-type="av-search"]') as HTMLInputElement; const isSearching = searchInputElement && document.activeElement.isSameNode(searchInputElement); const query = searchInputElement?.value || ""; @@ -103,7 +91,7 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: (data: IAV) = created, snapshot, pageSize: parseInt(e.dataset.pageSize) || undefined, - viewID: newViewID, + viewID: e.getAttribute(Constants.CUSTOM_SY_AV_VIEW) || "", query: query.trim() }, (response) => { const data = response.data.view as IAVTable; @@ -443,7 +431,7 @@ export const updateSearch = (e: HTMLElement, protyle: IProtyle) => { clearTimeout(searchTimeout); searchTimeout = window.setTimeout(() => { e.removeAttribute("data-render"); - avRender(e, protyle, undefined, undefined, false); + avRender(e, protyle, undefined, false); }, Constants.TIMEOUT_INPUT); }; @@ -489,18 +477,14 @@ export const refreshAV = (protyle: IProtyle, operation: IOperation) => { } if (operation.action === "removeAttrViewView") { item.setAttribute("data-av-type", operation.retData); - } - if (operation.action === "changeAttrViewLayout") { - item.setAttribute("data-av-type", operation.layout); - } - avRender(item, protyle, (data) => { - if (operation.action === "changeAttrViewLayout") { - const menuElement = document.querySelector(".av__panel").lastElementChild as HTMLElement; - menuElement.innerHTML = getLayoutHTML(data); - const tabRect = item.querySelector(".av__views").getBoundingClientRect(); - setPosition(menuElement, tabRect.right - menuElement.clientWidth, tabRect.bottom, tabRect.height); - bindLayoutEvent({protyle: protyle, data, menuElement, blockElement: item}); + } else if (operation.action === "setAttrViewBlockView") { + const viewTabElement = item.querySelector(`.av__views > .layout-tab-bar > .item[data-id="${operation.id}"]`) as HTMLElement; + if (viewTabElement) { + item.dataset.pageSize = viewTabElement.dataset.page; + item.setAttribute("data-av-type", viewTabElement.dataset.avType); } + } + avRender(item, protyle, () => { const attrElement = document.querySelector(`.b3-dialog--open[data-key="${Constants.DIALOG_ATTR}"] div[data-av-id="${avID}"]`) as HTMLElement; if (attrElement) { // 更新属性面板 diff --git a/app/src/protyle/render/av/row.ts b/app/src/protyle/render/av/row.ts index 1778dff03..22e311a80 100644 --- a/app/src/protyle/render/av/row.ts +++ b/app/src/protyle/render/av/row.ts @@ -89,7 +89,8 @@ export const updateHeader = (rowElement: HTMLElement) => { export const setPage = (blockElement: Element) => { const pageSize = parseInt(blockElement.getAttribute("data-page-size")); if (pageSize) { - const currentCount = blockElement.querySelectorAll(".av__row:not(.av__row--header)").length; + const avType = blockElement.getAttribute("data-av-type") as TAVView; + const currentCount = blockElement.querySelectorAll(avType === "table" ? ".av__row:not(.av__row--header)" : ".av__gallery-item").length; if (pageSize < currentCount) { blockElement.setAttribute("data-page-size", currentCount.toString()); } diff --git a/app/src/protyle/render/av/view.ts b/app/src/protyle/render/av/view.ts index 1082f094d..e8709d78c 100644 --- a/app/src/protyle/render/av/view.ts +++ b/app/src/protyle/render/av/view.ts @@ -245,8 +245,12 @@ export const bindSwitcherEvent = (options: { protyle: IProtyle, menuElement: Ele if (event.key === "Enter") { const currentElement = options.menuElement.querySelector(".b3-menu__item--current") as HTMLElement; if (currentElement) { - options.blockElement.removeAttribute("data-render"); - avRender(options.blockElement, options.protyle, undefined, currentElement.dataset.id); + transaction(options.protyle, [{ + action: "setAttrViewBlockView", + blockID: options.blockElement.getAttribute("data-node-id"), + id: currentElement.dataset.id, + avID: options.blockElement.getAttribute("data-av-id"), + }]); options.menuElement.remove(); focusBlock(options.blockElement); } @@ -386,4 +390,4 @@ export const getViewName = (type: string) => { export const getFieldsByData = (data: IAV) => { return data.viewType === "table" ? (data.view as IAVTable).columns : (data.view as IAVGallery).fields; -} +}; diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index 4318cd0ad..b5c06a4db 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -1848,15 +1848,18 @@ export class WYSIWYG { if (avTabHeaderElement.classList.contains("item--focus")) { openViewMenu({protyle, blockElement: nodeElement, element: avTabHeaderElement}); } else { - nodeElement.setAttribute("data-av-type", avTabHeaderElement.dataset.avType); - nodeElement.removeAttribute("data-render"); - avRender(nodeElement, protyle, () => { - openViewMenu({ - protyle, - blockElement: nodeElement, - element: nodeElement.querySelector(".item.item--focus") - }); - }, avTabHeaderElement.dataset.id); + transaction(protyle, [{ + action: "setAttrViewBlockView", + blockID: nodeElement.getAttribute("data-node-id"), + id: avTabHeaderElement.dataset.id, + avID: nodeElement.getAttribute("data-av-id"), + }]); + window.siyuan.menus.menu.remove(); + openViewMenu({ + protyle, + blockElement: nodeElement, + element: avTabHeaderElement + }); } event.stopPropagation(); event.preventDefault(); diff --git a/app/src/protyle/wysiwyg/transaction.ts b/app/src/protyle/wysiwyg/transaction.ts index 897e1ac1d..62603f13e 100644 --- a/app/src/protyle/wysiwyg/transaction.ts +++ b/app/src/protyle/wysiwyg/transaction.ts @@ -851,7 +851,7 @@ export const onTransaction = (protyle: IProtyle, operation: IOperation, isUndo: "removeAttrViewView", "setAttrViewViewName", "setAttrViewViewIcon", "duplicateAttrViewView", "sortAttrViewView", "updateAttrViewColRelation", "setAttrViewPageSize", "updateAttrViewColRollup", "sortAttrViewKey", "setAttrViewColDesc", "duplicateAttrViewKey", "setAttrViewViewDesc", "setAttrViewCoverFrom", "setAttrViewCoverFromAssetKeyID", - "changeAttrViewLayout"].includes(operation.action)) { + "setAttrViewBlockView"].includes(operation.action)) { if (!isUndo) { // 撤销 transaction 会进行推送,需使用推送来进行刷新最新数据 https://github.com/siyuan-note/siyuan/issues/13607 refreshAV(protyle, operation); diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index 6fc98a601..56227b362 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -57,11 +57,11 @@ type TOperation = | "setAttrViewFitImage" | "setAttrViewShowIcon" | "setAttrViewWrapField" - | "changeAttrViewLayout" | "setAttrViewColDate" | "unbindAttrViewBlock" | "setAttrViewViewDesc" | "setAttrViewColDesc" + | "setAttrViewBlockView" type TBazaarType = "templates" | "icons" | "widgets" | "themes" | "plugins" type TCardType = "doc" | "notebook" | "all" type TEventBus = "ws-main" | "sync-start" | "sync-end" | "sync-fail" |