diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index 0550c31f9..97bc74e0e 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -110,7 +110,7 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle const cellElement = hasClosestByClassName(event.target, "av__cell"); if (cellElement && !cellElement.parentElement.classList.contains("av__row--header")) { - popTextCell(protyle, cellElement); + popTextCell(protyle, [cellElement]); event.preventDefault(); event.stopPropagation(); return true; @@ -197,7 +197,7 @@ export const avContextmenu = (protyle: IProtyle, event: MouseEvent & { detail: a icon: getColIconByType(cellElement.getAttribute("data-dtype") as TAVCol), label: cellElement.textContent.trim(), click() { - popTextCell(protyle, rowElement.querySelector(`.av__cell[data-col-id="${cellElement.dataset.colId}"]`)); + popTextCell(protyle, Array.from(blockElement.querySelectorAll(`.av__row--select:not(.av__row--header) .av__cell[data-col-id="${cellElement.dataset.colId}"]`))); } }); }); diff --git a/app/src/protyle/render/av/cell.ts b/app/src/protyle/render/av/cell.ts index 90d602e6f..a3324ac5e 100644 --- a/app/src/protyle/render/av/cell.ts +++ b/app/src/protyle/render/av/cell.ts @@ -281,18 +281,19 @@ export const openCalcMenu = (protyle: IProtyle, calcElement: HTMLElement) => { menu.open({x: calcRect.left, y: calcRect.bottom, h: calcRect.height}); }; -export const popTextCell = (protyle: IProtyle, cellElement: HTMLElement) => { - const type = cellElement.parentElement.parentElement.firstElementChild.querySelector(`[data-col-id="${cellElement.getAttribute("data-col-id")}"]`).getAttribute("data-dtype") as TAVCol; - const cellRect = cellElement.getBoundingClientRect(); +export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[]) => { + const type = cellElements[0].parentElement.parentElement.firstElementChild.querySelector(`[data-col-id="${cellElements[0].getAttribute("data-col-id")}"]`).getAttribute("data-dtype") as TAVCol; + const cellRect = cellElements[0].getBoundingClientRect(); let html = ""; const style = `style="position:absolute;left: ${cellRect.left}px;top: ${cellRect.top}px;width:${Math.max(cellRect.width, 200)}px;height: ${cellRect.height}px"`; - const blockElement = hasClosestBlock(cellElement); + const blockElement = hasClosestBlock(cellElements[0]); if (type === "block" || type === "text") { - html = ``; + html = ``; } else if (type === "number") { - html = ``; + html = ``; } else if (["select", "mSelect"].includes(type) && blockElement) { - openMenuPanel(protyle, blockElement, "select", {cellElement}); + // TODO + openMenuPanel(protyle, blockElement, "select", {cellElement: cellElements[0]}); return; } window.siyuan.menus.menu.remove(); @@ -305,14 +306,14 @@ export const popTextCell = (protyle: IProtyle, cellElement: HTMLElement) => { inputElement.select(); inputElement.focus(); inputElement.addEventListener("blur", () => { - updateCellValue(protyle, cellElement, type); + updateCellValue(protyle, type, cellElements); }); inputElement.addEventListener("keydown", (event) => { if (event.isComposing) { return; } if (event.key === "Escape" || event.key === "Enter") { - updateCellValue(protyle, cellElement, type); + updateCellValue(protyle, type, cellElements); event.preventDefault(); event.stopPropagation(); } @@ -325,51 +326,58 @@ export const popTextCell = (protyle: IProtyle, cellElement: HTMLElement) => { }); }; -const updateCellValue = (protyle: IProtyle, cellElement: HTMLElement, type: TAVCol) => { - const rowElement = hasClosestByClassName(cellElement, "av__row"); - if (!rowElement) { - return; - } - const blockElement = hasClosestBlock(rowElement); +const updateCellValue = (protyle: IProtyle, type: TAVCol, cellElements: HTMLElement[]) => { + const blockElement = hasClosestBlock(cellElements[0]); if (!blockElement) { return; } - const rowID = rowElement.getAttribute("data-id"); - const avMaskElement = document.querySelector(".av__mask"); - const cellId = cellElement.getAttribute("data-id"); - const colId = cellElement.getAttribute("data-col-id"); + + const avMaskElement = document.querySelector(".av__mask") + const doOperations: IOperation[] = [] + const undoOperations: IOperation[] = [] const avID = blockElement.getAttribute("data-av-id"); - const inputValue: { content: string | number, isNotEmpty?: boolean } = { - content: (avMaskElement.querySelector(".b3-text-field") as HTMLInputElement).value - }; - const oldValue: { content: string | number, isNotEmpty?: boolean } = { - content: cellElement.textContent.trim() - }; - if (type === "number") { - oldValue.content = parseFloat(oldValue.content as string); - oldValue.isNotEmpty = !!oldValue.content; - inputValue.content = parseFloat(inputValue.content as string); - inputValue.isNotEmpty = !!inputValue.content; - } - transaction(protyle, [{ - action: "updateAttrViewCell", - id: cellId, - avID, - keyID: colId, - rowID, - data: { - [type]: inputValue + cellElements.forEach((item) => { + const rowElement = hasClosestByClassName(item, "av__row"); + if (!rowElement) { + return; } - }], [{ - action: "updateAttrViewCell", - id: cellId, - avID, - keyID: colId, - rowID, - data: { - [type]: oldValue + const rowID = rowElement.getAttribute("data-id"); + const cellId = item.getAttribute("data-id"); + const colId = item.getAttribute("data-col-id"); + const inputValue: { content: string | number, isNotEmpty?: boolean } = { + content: (avMaskElement.querySelector(".b3-text-field") as HTMLInputElement).value + }; + const oldValue: { content: string | number, isNotEmpty?: boolean } = { + content: item.textContent.trim() + }; + if (type === "number") { + oldValue.content = parseFloat(oldValue.content as string); + oldValue.isNotEmpty = !!oldValue.content; + inputValue.content = parseFloat(inputValue.content as string); + inputValue.isNotEmpty = !!inputValue.content; } - }]); + doOperations.push({ + action: "updateAttrViewCell", + id: cellId, + avID, + keyID: colId, + rowID, + data: { + [type]: inputValue + } + }) + undoOperations.push({ + action: "updateAttrViewCell", + id: cellId, + avID, + keyID: colId, + rowID, + data: { + [type]: oldValue + } + }) + }) + transaction(protyle, doOperations, undoOperations); setTimeout(() => { avMaskElement.remove(); }); diff --git a/app/src/protyle/render/av/col.ts b/app/src/protyle/render/av/col.ts index 462f48c9b..7ad5fd707 100644 --- a/app/src/protyle/render/av/col.ts +++ b/app/src/protyle/render/av/col.ts @@ -4,6 +4,16 @@ import {transaction} from "../../wysiwyg/transaction"; import {fetchPost} from "../../../util/fetch"; import {getDefaultOperatorByType, setFilter} from "./filter"; import {genCellValue} from "./cell"; +import {openMenuPanel} from "./openMenuPanel"; + +export const getEditHTML = (options: { + protyle: IProtyle, + blockElement: HTMLElement, + cellElement: HTMLElement, + data: IAV +}) => { + // TODO +} export const getColIconByType = (type: TAVCol) => { switch (type) { @@ -95,7 +105,7 @@ export const showColMenu = (protyle: IProtyle, blockElement: HTMLElement, cellEl icon: "iconEdit", label: window.siyuan.languages.edit, click() { - + openMenuPanel(protyle, blockElement, "edit", {cellElement}); } }); } diff --git a/app/src/protyle/render/av/openMenuPanel.ts b/app/src/protyle/render/av/openMenuPanel.ts index 2f5407e58..118ee2c1a 100644 --- a/app/src/protyle/render/av/openMenuPanel.ts +++ b/app/src/protyle/render/av/openMenuPanel.ts @@ -1,7 +1,7 @@ import {transaction} from "../../wysiwyg/transaction"; import {fetchPost} from "../../../util/fetch"; import {addCol} from "./addCol"; -import {getColIconByType} from "./col"; +import {getColIconByType, getEditHTML} from "./col"; import {setPosition} from "../../../util/setPosition"; import {hasClosestByAttribute} from "../../util/hasClosest"; import {bindSelectEvent, getSelectHTML, addSelectColAndCell, setSelectCol, removeSelectCell} from "./select"; @@ -10,7 +10,7 @@ import {addSort, bindSortsEvent, getSortsHTML} from "./sort"; export const openMenuPanel = (protyle: IProtyle, blockElement: HTMLElement, - type: "select" | "properties" | "config" | "sorts" | "filters" = "config", + type: "select" | "properties" | "config" | "sorts" | "filters" | "edit" = "config", options?: any) => { let avPanelElement = document.querySelector(".av__panel"); if (avPanelElement) { @@ -32,6 +32,8 @@ export const openMenuPanel = (protyle: IProtyle, html = getFiltersHTML(data.view); } else if (type === "select") { html = getSelectHTML(data.view, options); + } else if (type === "edit") { + html = getEditHTML({protyle, data, blockElement, cellElement: options.cellElement}); } document.body.insertAdjacentHTML("beforeend", `