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 += ``; + }); + galleryHTML += ``; + 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 += ``; + + 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 += ``; - if (options.renderAll) { - options.blockElement.firstElementChild.outerHTML = `
- ${genTabHeaderHTML(response.data, isSearching || !!query, options.protyle.disabled || !!hasClosestByAttribute(options.blockElement, "data-type", "NodeBlockQueryEmbed"))} -
- ${galleryHTML} -
- ${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}
`;