import {fetchPost} from "../../../util/fetch"; import {getColIconByType} from "./col"; import {Constants} from "../../../constants"; import {addDragFill, renderCell} from "./cell"; import {unicode2Emoji} from "../../../emoji"; import {focusBlock} from "../../util/selection"; import {hasClosestBlock, hasClosestByClassName, isInEmbedBlock} from "../../util/hasClosest"; import {stickyRow, updateHeader} from "./row"; import {getCalcValue} from "./calc"; import {renderAVAttribute} from "./blockAttr"; import {showMessage} from "../../../dialog/message"; import {addClearButton} from "../../../util/addClearButton"; export const avRender = (element: Element, protyle: IProtyle, cb?: () => void, viewID?: string) => { let avElements: Element[] = []; if (element.getAttribute("data-type") === "NodeAttributeView") { // 编辑器内代码块编辑渲染 avElements = [element]; } else { avElements = Array.from(element.querySelectorAll('[data-type="NodeAttributeView"]')); } if (avElements.length === 0) { return; } if (avElements.length > 0) { avElements.forEach((e: HTMLElement) => { if (e.getAttribute("data-render") === "true") { return; } const alignSelf = e.style.alignSelf; if (e.firstElementChild.innerHTML === "") { e.style.alignSelf = ""; let html = ""; [1, 2, 3].forEach(() => { html += `
`; }); e.firstElementChild.innerHTML = html; } const left = e.querySelector(".av__scroll")?.scrollLeft || 0; const headerTransform = (e.querySelector(".av__row--header") as HTMLElement)?.style.transform; const footerTransform = (e.querySelector(".av__row--footer") as HTMLElement)?.style.transform; const selectRowIds: string[] = []; e.querySelectorAll(".av__row--select").forEach(rowItem => { const rowId = rowItem.getAttribute("data-id"); if (rowId) { selectRowIds.push(rowId); } }); let selectCellId = ""; const selectCellElement = e.querySelector(".av__cell--select") as HTMLElement; if (selectCellElement) { selectCellId = (hasClosestByClassName(selectCellElement, "av__row") as HTMLElement).dataset.id + Constants.ZWSP + selectCellElement.getAttribute("data-col-id"); } let dragFillId = ""; const dragFillElement = e.querySelector(".av__drag-fill") as HTMLElement; if (dragFillElement) { dragFillId = (hasClosestByClassName(dragFillElement, "av__row") as HTMLElement).dataset.id + Constants.ZWSP + dragFillElement.parentElement.getAttribute("data-col-id"); } const activeIds: string[] = []; e.querySelectorAll(".av__cell--active").forEach((item: HTMLElement) => { activeIds.push((hasClosestByClassName(item, "av__row") as HTMLElement).dataset.id + Constants.ZWSP + item.getAttribute("data-col-id")); }); 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}); 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 || ""; fetchPost(created ? "/api/av/renderHistoryAttributeView" : (snapshot ? "/api/av/renderSnapshotAttributeView" : "/api/av/renderAttributeView"), { id: e.getAttribute("data-av-id"), created, snapshot, pageSize: parseInt(e.dataset.pageSize) || undefined, viewID: newViewID, query: query.trim() }, (response) => { const data = response.data.view as IAVTable; if (!e.dataset.pageSize) { e.dataset.pageSize = data.pageSize.toString(); } // header let tableHTML = '
'; let calcHTML = ""; let pinIndex = -1; let pinMaxIndex = -1; let indexWidth = 0; const eWidth = e.clientWidth; let hasFilter = false; data.columns.forEach((item, index) => { if (!hasFilter) { data.filters.find(filterItem => { if (filterItem.value.type === item.type && item.id === filterItem.column) { hasFilter = true; return true; } }); } if (!item.hidden) { if (item.pin) { pinIndex = index; } if (indexWidth < eWidth - 200) { indexWidth += parseInt(item.width) || 200; pinMaxIndex = index; } } }); pinIndex = Math.min(pinIndex, pinMaxIndex); if (pinIndex > -1) { tableHTML = '
'; calcHTML = '
'; } let hasCalc = false; data.columns.forEach((column: IAVColumn, index: number) => { if (column.hidden) { return; } tableHTML += `
${column.icon ? unicode2Emoji(column.icon, "av__cellheadericon", true) : ``} ${column.name} ${column.pin ? '' : ""}
`; if (pinIndex === index) { tableHTML += "
"; } if (column.type === "lineNumber") { // lineNumber type 不参与计算操作 calcHTML += `
 
`; } else { calcHTML += `
${getCalcValue(column) || '' + window.siyuan.languages.calc}
`; } if (column.calc && column.calc.operator !== "") { hasCalc = true; } if (pinIndex === index) { calcHTML += "
"; } }); tableHTML += `
`; // body data.rows.forEach((row: IAVRow, rowIndex: number) => { tableHTML += `
`; if (pinIndex > -1) { tableHTML += '
'; } else { tableHTML += '
'; } row.cells.forEach((cell, index) => { if (data.columns[index].hidden) { return; } // https://github.com/siyuan-note/siyuan/issues/10262 let checkClass = ""; if (cell.valueType === "checkbox") { checkClass = cell.value?.checkbox?.checked ? " av__cell-check" : " av__cell-uncheck"; } tableHTML += `
${renderCell(cell.value, rowIndex)}
`; if (pinIndex === index) { tableHTML += "
"; } }); tableHTML += "
"; }); let tabHTML = ""; let viewData: IAVView; response.data.views.forEach((item: IAVView) => { tabHTML += `
${item.icon ? unicode2Emoji(item.icon, "item__graphic", true) : ''} ${item.name}
`; if (item.id === response.data.viewID) { viewData = item; } }); e.firstElementChild.outerHTML = `
${tabHTML}
${response.data.views.length}
${response.data.isMirror ? `
` : ""}
${response.data.name || ""}
${tableHTML}
${calcHTML}
${Constants.ZWSP}
`; e.setAttribute("data-render", "true"); // 历史兼容 e.style.margin = ""; if (left) { e.querySelector(".av__scroll").scrollLeft = left; } if (alignSelf) { e.style.alignSelf = alignSelf; } const editRect = protyle.contentElement.getBoundingClientRect(); if (headerTransform) { (e.querySelector(".av__row--header") as HTMLElement).style.transform = headerTransform; } else { stickyRow(e, editRect, "top"); } if (footerTransform) { (e.querySelector(".av__row--footer") as HTMLElement).style.transform = footerTransform; } else { stickyRow(e, editRect, "bottom"); } if (selectCellId) { const newCellElement = e.querySelector(`.av__row[data-id="${selectCellId.split(Constants.ZWSP)[0]}"] .av__cell[data-col-id="${selectCellId.split(Constants.ZWSP)[1]}"]`); if (newCellElement) { newCellElement.classList.add("av__cell--select"); } const avMaskElement = document.querySelector(".av__mask"); if (avMaskElement) { (avMaskElement.querySelector("textarea, input") as HTMLTextAreaElement)?.focus(); } else if (!document.querySelector(".av__panel") && !isSearching) { focusBlock(e); } } selectRowIds.forEach((selectRowId, index) => { const rowElement = e.querySelector(`.av__row[data-id="${selectRowId}"]`) as HTMLElement; if (rowElement) { rowElement.classList.add("av__row--select"); rowElement.querySelector(".av__firstcol use").setAttribute("xlink:href", "#iconCheck"); } if (index === selectRowIds.length - 1 && rowElement) { updateHeader(rowElement); } }); if (dragFillId) { addDragFill(e.querySelector(`.av__row[data-id="${dragFillId.split(Constants.ZWSP)[0]}"] .av__cell[data-col-id="${dragFillId.split(Constants.ZWSP)[1]}"]`)); } activeIds.forEach(activeId => { e.querySelector(`.av__row[data-id="${activeId.split(Constants.ZWSP)[0]}"] .av__cell[data-col-id="${activeId.split(Constants.ZWSP)[1]}"]`)?.classList.add("av__cell--active"); }); if (getSelection().rangeCount > 0) { // 修改表头后光标重新定位 const range = getSelection().getRangeAt(0); if (!hasClosestByClassName(range.startContainer, "av__title")) { const blockElement = hasClosestBlock(range.startContainer); if (blockElement && e.isSameNode(blockElement) && !isSearching) { focusBlock(e); } } } e.querySelector(".layout-tab-bar").scrollLeft = (e.querySelector(".layout-tab-bar .item--focus") as HTMLElement).offsetLeft; if (cb) { cb(); } const viewsElement = e.querySelector(".av__views") as HTMLElement; searchInputElement = e.querySelector('[data-type="av-search"]') as HTMLInputElement; searchInputElement.value = query || ""; if (isSearching) { searchInputElement.focus(); } searchInputElement.addEventListener("input", (event: KeyboardEvent) => { if (event.isComposing) { return; } if (searchInputElement.value || document.activeElement.isSameNode(searchInputElement)) { viewsElement.classList.add("av__views--show"); } else { viewsElement.classList.remove("av__views--show"); } updateSearch(e, protyle); }); searchInputElement.addEventListener("compositionend", () => { updateSearch(e, 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(e); updateSearch(e, protyle); } }); }); }); } }; let searchTimeout: number; const updateSearch = (e: HTMLElement, protyle: IProtyle) => { clearTimeout(searchTimeout); searchTimeout = window.setTimeout(() => { e.removeAttribute("data-render"); avRender(e, protyle); }, Constants.TIMEOUT_INPUT); }; const refreshTimeouts: { [key: string]: number; } = {}; export const refreshAV = (protyle: IProtyle, operation: IOperation) => { if (operation.action === "setAttrViewName") { Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-av-id="${operation.id}"]`)).forEach((item: HTMLElement) => { const titleElement = item.querySelector(".av__title") as HTMLElement; if (!titleElement) { return; } titleElement.textContent = operation.data; titleElement.dataset.title = operation.data; }); } // 只能 setTimeout,以前方案快速输入后最后一次修改会被忽略;必须为每一个 protyle 单独设置,否则有多个 protyle 时,其余无法被执行 clearTimeout(refreshTimeouts[protyle.id]); refreshTimeouts[protyle.id] = window.setTimeout(() => { if (operation.action === "setAttrViewColWidth") { Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-av-id="${operation.avID}"]`)).forEach((item: HTMLElement) => { const cellElement = item.querySelector(`.av__cell[data-col-id="${operation.id}"]`) as HTMLElement; if (!cellElement || cellElement.style.width === operation.data || item.getAttribute("custom-sy-av-view") !== operation.keyID) { return; } item.querySelectorAll(".av__row").forEach(rowItem => { (rowItem.querySelector(`[data-col-id="${operation.id}"]`) as HTMLElement).style.width = operation.data; }); }); } else { // 修改表格名 avID 传入到 id 上了 https://github.com/siyuan-note/siyuan/issues/12724 const avID = operation.action === "setAttrViewName" ? operation.id : operation.avID; Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-av-id="${avID}"]`)).forEach((item: HTMLElement) => { item.removeAttribute("data-render"); const updateRow = item.querySelector('.av__row[data-need-update="true"]'); if (operation.action === "sortAttrViewCol" || operation.action === "sortAttrViewRow") { item.querySelectorAll(".av__cell--active").forEach((item: HTMLElement) => { item.classList.remove("av__cell--active"); item.querySelector(".av__drag-fill")?.remove(); }); addDragFill(item.querySelector(".av__cell--select")); } avRender(item, protyle, () => { const attrElement = document.querySelector(`.b3-dialog--open[data-key="${Constants.DIALOG_ATTR}"] div[data-av-id="${avID}"]`) as HTMLElement; if (attrElement) { // 更新属性面板 renderAVAttribute(attrElement.parentElement, attrElement.dataset.nodeId, protyle); } else { if (operation.action === "insertAttrViewBlock" && updateRow && !item.querySelector(`.av__row[data-id="${updateRow.getAttribute("data-id")}"]`)) { showMessage(window.siyuan.languages.insertRowTip); document.querySelector(".av__mask")?.remove(); } } item.removeAttribute("data-loading"); }); }); } }, ["insertAttrViewBlock"].includes(operation.action) ? 2 : 100); };