diff --git a/app/src/assets/scss/business/_av.scss b/app/src/assets/scss/business/_av.scss
index e57ceccb7..9a2cf6c66 100644
--- a/app/src/assets/scss/business/_av.scss
+++ b/app/src/assets/scss/business/_av.scss
@@ -127,10 +127,6 @@
overflow: auto hidden;
}
- &__body {
- float: left;
- }
-
&__row {
display: flex;
border-bottom: 1px solid var(--b3-theme-surface-lighter);
@@ -256,6 +252,7 @@
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 16px;
width: 100%;
+ margin-top: 8px;
&--top {
margin-top: 16px;
@@ -919,6 +916,7 @@
display: flex;
font-size: 87.5%;
align-items: center;
+ padding-top: 16px;
.counter:hover {
background-color: var(--b3-list-icon-hover);
diff --git a/app/src/protyle/render/av/gallery/render.ts b/app/src/protyle/render/av/gallery/render.ts
index 9255e8766..3b272fe15 100644
--- a/app/src/protyle/render/av/gallery/render.ts
+++ b/app/src/protyle/render/av/gallery/render.ts
@@ -1,6 +1,6 @@
import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName} from "../../../util/hasClosest";
import {Constants} from "../../../../constants";
-import {fetchPost} from "../../../../util/fetch";
+import {fetchSyncPost} from "../../../../util/fetch";
import {escapeAttr} from "../../../../util/escape";
import {unicode2Emoji} from "../../../../emoji";
import {cellValueIsEmpty, renderCell} from "../cell";
@@ -12,24 +12,216 @@ import {processRender} from "../../../util/processCode";
import {getColIconByType, getColNameByType} from "../col";
import {getCompressURL} from "../../../../util/image";
-export const renderGallery = (options: {
+interface ITableOptions {
+ protyle: IProtyle,
+ blockElement: HTMLElement,
+ cb: (data: IAV) => void,
+ data: IAV,
+ renderAll: boolean,
+ resetData: {
+ alignSelf: string,
+ selectItemIds: string[],
+ isSearching: boolean,
+ editIds: string[],
+ query: string,
+ oldOffset: number,
+ }
+}
+
+const getGalleryHTML = (data: IAVGallery, selectItemIds: string[], editIds: string[]) => {
+ let galleryHTML = "";
+ // body
+ data.cards.forEach((item: IAVGalleryItem, rowIndex: number) => {
+ galleryHTML += `
`;
+ if (data.coverFrom !== 0) {
+ const coverClass = "av__gallery-cover av__gallery-cover--" + data.cardAspectRatio;
+ if (item.coverURL) {
+ if (item.coverURL.startsWith("background")) {
+ galleryHTML += `
`;
+ } else {
+ galleryHTML += `
`;
+ }
+ } else if (item.coverContent) {
+ galleryHTML += `
`;
+ } else {
+ galleryHTML += `
`;
+ }
+ }
+ galleryHTML += `
`;
+ item.values.forEach((cell, fieldsIndex) => {
+ if (data.fields[fieldsIndex].hidden) {
+ return;
+ }
+ let checkClass = "";
+ if (cell.valueType === "checkbox") {
+ checkClass = cell.value?.checkbox?.checked ? " av__cell-check" : " av__cell-uncheck";
+ }
+ const isEmpty = cellValueIsEmpty(cell.value);
+ // NOTE: innerHTML 中不能换行否则 https://github.com/siyuan-note/siyuan/issues/15132
+ let ariaLabel = escapeAttr(data.fields[fieldsIndex].name) || getColNameByType(data.fields[fieldsIndex].type);
+ if (data.fields[fieldsIndex].desc) {
+ ariaLabel += escapeAttr(`
${data.fields[fieldsIndex].desc}
`);
+ }
+ galleryHTML += `
${renderCell(cell.value, rowIndex, data.showIcon, "gallery")}
${data.fields[fieldsIndex].icon ? unicode2Emoji(data.fields[fieldsIndex].icon, undefined, true) : ``}${window.siyuan.languages.edit} ${Lute.EscapeHTMLStr(data.fields[fieldsIndex].name)}
`;
+ });
+ galleryHTML += `
+
+
+
+
+
`;
+ });
+ galleryHTML += `${window.siyuan.languages.newRow}
`;
+ return `
+ ${galleryHTML}
+
+
+
+
`;
+};
+
+const renderGroupGallery = (options: ITableOptions) => {
+ const searchInputElement = options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement;
+ const isSearching = searchInputElement && document.activeElement === searchInputElement;
+ const query = searchInputElement?.value || "";
+
+ let avBodyHTML = "";
+ options.data.view.groups.forEach((group: IAVGallery) => {
+ if (group.groupHidden === 0) {
+ group.fields = (options.data.view as IAVGallery).fields;
+ avBodyHTML += `
+
+
+
${group.name}
${group.cards.length}
+
+${getGalleryHTML(group, options.resetData.selectItemIds, options.resetData.editIds)}
`;
+ }
+ });
+ if (options.renderAll) {
+ options.blockElement.firstElementChild.outerHTML = `
+ ${genTabHeaderHTML(options.data, isSearching || !!query, options.protyle.disabled || !!hasClosestByAttribute(options.blockElement, "data-type", "NodeBlockQueryEmbed"))}
+
+ ${avBodyHTML}
+
+
${Constants.ZWSP}
+
`;
+ } else {
+ options.blockElement.querySelector(".av__header").nextElementSibling.innerHTML = avBodyHTML;
+ }
+ afterRenderGallery(options);
+};
+
+const afterRenderGallery = (options: ITableOptions) => {
+ const view = options.data.view as IAVGallery;
+ if (view.coverFrom === 1 || view.coverFrom === 3) {
+ processRender(options.blockElement);
+ }
+ if (typeof options.resetData.oldOffset === "number") {
+ options.protyle.contentElement.scrollTop = options.resetData.oldOffset;
+ }
+ options.blockElement.setAttribute("data-render", "true");
+ if (options.resetData.alignSelf) {
+ options.blockElement.style.alignSelf = options.resetData.alignSelf;
+ }
+ if (getSelection().rangeCount > 0) {
+ // 修改表头后光标重新定位
+ const range = getSelection().getRangeAt(0);
+ if (!hasClosestByClassName(range.startContainer, "av__title")) {
+ const blockElement = hasClosestBlock(range.startContainer);
+ if (blockElement && options.blockElement === blockElement && !options.resetData.isSearching) {
+ focusBlock(options.blockElement);
+ }
+ }
+ }
+ options.blockElement.querySelector(".layout-tab-bar").scrollLeft = (options.blockElement.querySelector(".layout-tab-bar .item--focus") as HTMLElement).offsetLeft - 30;
+ if (options.cb) {
+ options.cb(options.data);
+ }
+ if (options.data.view.hideAttrViewName) {
+ options.blockElement.querySelector(".av__gallery").classList.add("av__gallery--top");
+ }
+ if (!options.renderAll) {
+ return;
+ }
+ const viewsElement = options.blockElement.querySelector(".av__views") as HTMLElement;
+ const searchInputElement = options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement;
+ searchInputElement.value = options.resetData.query || "";
+ if (options.resetData.isSearching) {
+ searchInputElement.focus();
+ }
+ searchInputElement.addEventListener("compositionstart", (event: KeyboardEvent) => {
+ event.stopPropagation();
+ });
+ searchInputElement.addEventListener("keydown", (event: KeyboardEvent) => {
+ if (event.isComposing) {
+ return;
+ }
+ electronUndo(event);
+ });
+ searchInputElement.addEventListener("input", (event: KeyboardEvent) => {
+ event.stopPropagation();
+ if (event.isComposing) {
+ return;
+ }
+ if (searchInputElement.value || document.activeElement === searchInputElement) {
+ viewsElement.classList.add("av__views--show");
+ } else {
+ viewsElement.classList.remove("av__views--show");
+ }
+ updateSearch(options.blockElement, options.protyle);
+ });
+ searchInputElement.addEventListener("compositionend", () => {
+ updateSearch(options.blockElement, options.protyle);
+ });
+ searchInputElement.addEventListener("blur", (event: KeyboardEvent) => {
+ if (event.isComposing) {
+ return;
+ }
+ if (!searchInputElement.value) {
+ viewsElement.classList.remove("av__views--show");
+ searchInputElement.style.width = "0";
+ searchInputElement.style.paddingLeft = "0";
+ searchInputElement.style.paddingRight = "0";
+ }
+ });
+ addClearButton({
+ inputElement: searchInputElement,
+ right: 0,
+ width: "1em",
+ height: searchInputElement.clientHeight,
+ clearCB() {
+ viewsElement.classList.remove("av__views--show");
+ searchInputElement.style.width = "0";
+ searchInputElement.style.paddingLeft = "0";
+ searchInputElement.style.paddingRight = "0";
+ focusBlock(options.blockElement);
+ updateSearch(options.blockElement, options.protyle);
+ }
+ });
+};
+
+export const renderGallery = async (options: {
blockElement: HTMLElement,
protyle: IProtyle,
cb?: (data: IAV) => void,
- renderAll: boolean
+ renderAll: boolean,
+ data?: IAV,
}) => {
- const alignSelf = options.blockElement.style.alignSelf;
- let oldOffset: number;
- if (options.blockElement.firstElementChild.innerHTML === "") {
- options.blockElement.style.alignSelf = "";
- options.blockElement.firstElementChild.outerHTML = `
-
-
-
-
`;
- } else {
- oldOffset = options.protyle.contentElement.scrollTop;
- }
+ const searchInputElement = options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement;
const editIds: string[] = [];
options.blockElement.querySelectorAll(".av__gallery-fields--edit").forEach(item => {
editIds.push(item.parentElement.getAttribute("data-id"));
@@ -41,187 +233,77 @@ export const renderGallery = (options: {
selectItemIds.push(rowId);
}
});
+ const resetData = {
+ isSearching: searchInputElement && document.activeElement === searchInputElement,
+ query: searchInputElement?.value || "",
+ alignSelf: options.blockElement.style.alignSelf,
+ oldOffset: options.protyle.contentElement.scrollTop,
+ editIds,
+ selectItemIds,
+ };
+ if (options.blockElement.firstElementChild.innerHTML === "") {
+ options.blockElement.style.alignSelf = "";
+ options.blockElement.firstElementChild.outerHTML = `
+
+
+
+
`;
+ }
const created = options.protyle.options.history?.created;
const snapshot = options.protyle.options.history?.snapshot;
- let searchInputElement = options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement;
- const isSearching = searchInputElement && document.activeElement === searchInputElement;
- const query = searchInputElement?.value || "";
- fetchPost(created ? "/api/av/renderHistoryAttributeView" : (snapshot ? "/api/av/renderSnapshotAttributeView" : "/api/av/renderAttributeView"), {
- id: options.blockElement.getAttribute("data-av-id"),
- created,
- snapshot,
- pageSize: parseInt(options.blockElement.dataset.pageSize) || undefined,
- viewID: options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW) || "",
- query: query.trim()
- }, (response) => {
- const view: IAVGallery = response.data.view;
- if (response.data.viewType === "table") {
- options.blockElement.setAttribute("data-av-type", "table");
- avRender(options.blockElement, options.protyle, options.cb, options.renderAll);
- return;
- }
- if (!options.blockElement.dataset.pageSize) {
- options.blockElement.dataset.pageSize = view.pageSize.toString();
- }
- let galleryHTML = "";
- // body
- view.cards.forEach((item: IAVGalleryItem, rowIndex: number) => {
- galleryHTML += ``;
- if (view.coverFrom !== 0) {
- const coverClass = "av__gallery-cover av__gallery-cover--" + view.cardAspectRatio;
- if (item.coverURL) {
- if (item.coverURL.startsWith("background")) {
- galleryHTML += `
`;
- } else {
- galleryHTML += `
`;
- }
- } else if (item.coverContent) {
- galleryHTML += `
`;
- } else {
- galleryHTML += `
`;
- }
- }
- galleryHTML += `
`;
- item.values.forEach((cell, fieldsIndex) => {
- if (view.fields[fieldsIndex].hidden) {
- return;
- }
- let checkClass = "";
- if (cell.valueType === "checkbox") {
- checkClass = cell.value?.checkbox?.checked ? " av__cell-check" : " av__cell-uncheck";
- }
- const isEmpty = cellValueIsEmpty(cell.value);
- // NOTE: innerHTML 中不能换行否则 https://github.com/siyuan-note/siyuan/issues/15132
- let ariaLabel = escapeAttr(view.fields[fieldsIndex].name) || getColNameByType(view.fields[fieldsIndex].type);
- if (view.fields[fieldsIndex].desc) {
- ariaLabel += escapeAttr(`
${view.fields[fieldsIndex].desc}
`);
- }
- galleryHTML += `
${renderCell(cell.value, rowIndex, view.showIcon, "gallery")}
${view.fields[fieldsIndex].icon ? unicode2Emoji(view.fields[fieldsIndex].icon, undefined, true) : ``}${window.siyuan.languages.edit} ${Lute.EscapeHTMLStr(view.fields[fieldsIndex].name)}
`;
- });
- galleryHTML += `
-
-
-
-
-
`;
+
+ let data: IAV = options.data;
+ if (!data) {
+ const response = await fetchSyncPost(created ? "/api/av/renderHistoryAttributeView" : (snapshot ? "/api/av/renderSnapshotAttributeView" : "/api/av/renderAttributeView"), {
+ id: options.blockElement.getAttribute("data-av-id"),
+ created,
+ snapshot,
+ pageSize: parseInt(options.blockElement.dataset.pageSize) || undefined,
+ viewID: options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW) || "",
+ query: resetData.query.trim()
});
- galleryHTML += `${window.siyuan.languages.newRow}
`;
- if (options.renderAll) {
- options.blockElement.firstElementChild.outerHTML = `
- ${genTabHeaderHTML(response.data, isSearching || !!query, options.protyle.disabled || !!hasClosestByAttribute(options.blockElement, "data-type", "NodeBlockQueryEmbed"))}
-
- ${galleryHTML}
-
-
-
+ data = response.data;
+ }
+ if (data.viewType === "table") {
+ options.blockElement.setAttribute("data-av-type", "table");
+ avRender(options.blockElement, options.protyle, options.cb, options.renderAll);
+ return;
+ }
+ const view: IAVGallery = data.view as IAVGallery;
+ if (view.groups?.length > 0) {
+ renderGroupGallery({
+ blockElement: options.blockElement,
+ protyle: options.protyle,
+ cb: options.cb,
+ renderAll: options.renderAll,
+ data,
+ resetData
+ });
+ return;
+ }
+ if (!options.blockElement.dataset.pageSize) {
+ options.blockElement.dataset.pageSize = view.pageSize.toString();
+ }
+ const bodyHTML = getGalleryHTML(view, selectItemIds, editIds);
+ if (options.renderAll) {
+ options.blockElement.firstElementChild.outerHTML = `
+ ${genTabHeaderHTML(data, resetData.isSearching || !!resetData.query, options.protyle.disabled || !!hasClosestByAttribute(options.blockElement, "data-type", "NodeBlockQueryEmbed"))}
+
${Constants.ZWSP}
`;
- } else {
- const galleryElement = options.blockElement.firstElementChild.querySelector(".av__gallery");
- galleryElement.innerHTML = galleryHTML;
- if (view.hideAttrViewName) {
- galleryElement.classList.add("av__gallery--top");
- } else {
- galleryElement.classList.remove("av__gallery--top");
- }
- }
- if (view.coverFrom === 1 || view.coverFrom === 3) {
- processRender(options.blockElement);
- }
- if (typeof oldOffset === "number") {
- options.protyle.contentElement.scrollTop = oldOffset;
- }
- options.blockElement.setAttribute("data-render", "true");
- if (alignSelf) {
- options.blockElement.style.alignSelf = alignSelf;
- }
- if (getSelection().rangeCount > 0) {
- // 修改表头后光标重新定位
- const range = getSelection().getRangeAt(0);
- if (!hasClosestByClassName(range.startContainer, "av__title")) {
- const blockElement = hasClosestBlock(range.startContainer);
- if (blockElement && options.blockElement === blockElement && !isSearching) {
- focusBlock(options.blockElement);
- }
- }
- }
- options.blockElement.querySelector(".layout-tab-bar").scrollLeft = (options.blockElement.querySelector(".layout-tab-bar .item--focus") as HTMLElement).offsetLeft - 30;
- if (options.cb) {
- options.cb(response.data);
- }
- if (!options.renderAll) {
- return;
- }
- const viewsElement = options.blockElement.querySelector(".av__views") as HTMLElement;
- searchInputElement = options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement;
- searchInputElement.value = query || "";
- if (isSearching) {
- searchInputElement.focus();
- }
- searchInputElement.addEventListener("compositionstart", (event: KeyboardEvent) => {
- event.stopPropagation();
- });
- searchInputElement.addEventListener("keydown", (event: KeyboardEvent) => {
- if (event.isComposing) {
- return;
- }
- electronUndo(event);
- });
- searchInputElement.addEventListener("input", (event: KeyboardEvent) => {
- event.stopPropagation();
- if (event.isComposing) {
- return;
- }
- if (searchInputElement.value || document.activeElement === searchInputElement) {
- viewsElement.classList.add("av__views--show");
- } else {
- viewsElement.classList.remove("av__views--show");
- }
- updateSearch(options.blockElement, options.protyle);
- });
- searchInputElement.addEventListener("compositionend", () => {
- updateSearch(options.blockElement, options.protyle);
- });
- searchInputElement.addEventListener("blur", (event: KeyboardEvent) => {
- if (event.isComposing) {
- return;
- }
- if (!searchInputElement.value) {
- viewsElement.classList.remove("av__views--show");
- searchInputElement.style.width = "0";
- searchInputElement.style.paddingLeft = "0";
- searchInputElement.style.paddingRight = "0";
- }
- });
- addClearButton({
- inputElement: searchInputElement,
- right: 0,
- width: "1em",
- height: searchInputElement.clientHeight,
- clearCB() {
- viewsElement.classList.remove("av__views--show");
- searchInputElement.style.width = "0";
- searchInputElement.style.paddingLeft = "0";
- searchInputElement.style.paddingRight = "0";
- focusBlock(options.blockElement);
- updateSearch(options.blockElement, options.protyle);
- }
- });
+ } else {
+ options.blockElement.querySelector(".av__body").innerHTML = bodyHTML;
+ }
+ afterRenderGallery({
+ resetData,
+ renderAll: options.renderAll,
+ data,
+ cb: options.cb,
+ protyle: options.protyle,
+ blockElement: options.blockElement,
});
};
diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts
index b2c70ef76..d95ae1569 100644
--- a/app/src/protyle/render/av/render.ts
+++ b/app/src/protyle/render/av/render.ts
@@ -239,7 +239,7 @@ const renderGroupTable = (options: ITableOptions) => {
${group.name}
${group.rows.length}
-${getTableHTMLs(group, options.blockElement).contentHTML}
`;
+${getTableHTMLs(group, options.blockElement).contentHTML}
`;
}
});
if (options.renderAll) {
@@ -475,7 +475,7 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: (data: IAV) =
const data = response.data.view as IAVTable;
if (response.data.viewType === "gallery") {
e.setAttribute("data-av-type", "table");
- renderGallery({blockElement: e, protyle, cb, renderAll});
+ renderGallery({blockElement: e, protyle, cb, renderAll, data: response.data});
return;
}
if (data.groups?.length > 0) {
@@ -486,7 +486,7 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: (data: IAV) =
e.dataset.pageSize = data.pageSize.toString();
}
const tableHTMLs = getTableHTMLs(data, e);
- const avBodyHTML = `
+ const avBodyHTML = `
${tableHTMLs.contentHTML}
${tableHTMLs.footerHTML}
`;