diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index 78a4aa216..ede01846d 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -3,7 +3,7 @@ import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName} from "../ import {transaction} from "../../wysiwyg/transaction"; import {openEditorTab} from "../../../menus/util"; import {copySubMenu} from "../../../menus/commonMenuItem"; -import {getTypeByCellElement, popTextCell} from "./cell"; +import {getCellText, getTypeByCellElement, popTextCell} from "./cell"; import {getColIconByType, showColMenu} from "./col"; import {insertAttrViewBlockAnimation, setPageSize, stickyRow, updateHeader} from "./row"; import {emitOpenMenu} from "../../../plugin/EventBus"; @@ -11,7 +11,6 @@ import {addCol} from "./col"; import {openMenuPanel} from "./openMenuPanel"; import {hintRef} from "../../hint/extend"; import {focusByRange} from "../../util/selection"; -import {writeText} from "../../util/compatibility"; import {showMessage} from "../../../dialog/message"; import {previewImage} from "../../preview/image"; import {isLocalPath, pathPosix} from "../../../util/pathName"; @@ -42,12 +41,7 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle const copyElement = hasClosestByAttribute(event.target, "data-type", "copy"); if (copyElement) { - const textElement = copyElement.previousElementSibling; - if (textElement.querySelector(".av__cellicon")) { - writeText(`${textElement.firstChild.textContent} → ${textElement.lastChild.textContent}`); - } else { - writeText(textElement.textContent); - } + getCellText(hasClosestByClassName(copyElement, "av__cell")); showMessage(window.siyuan.languages.copied); event.preventDefault(); event.stopPropagation(); diff --git a/app/src/protyle/render/av/cell.ts b/app/src/protyle/render/av/cell.ts index 8e7887ab2..0b7e170b0 100644 --- a/app/src/protyle/render/av/cell.ts +++ b/app/src/protyle/render/av/cell.ts @@ -2,12 +2,68 @@ import {transaction} from "../../wysiwyg/transaction"; import {hasClosestBlock, hasClosestByClassName} from "../../util/hasClosest"; import {openMenuPanel} from "./openMenuPanel"; import {updateAttrViewCellAnimation} from "./action"; -import {isNotCtrl} from "../../util/compatibility"; +import {isNotCtrl, writeText} from "../../util/compatibility"; import {objEquals} from "../../../util/functions"; import {fetchPost} from "../../../util/fetch"; import {focusBlock} from "../../util/selection"; import * as dayjs from "dayjs"; +export const getCellText = (cellElement: HTMLElement | false) => { + if (!cellElement) { + return + } + const textElement = cellElement.querySelector(".av__celltext"); + if (textElement) { + if (textElement.querySelector(".av__cellicon")) { + writeText(`${textElement.firstChild.textContent} → ${textElement.lastChild.textContent}`); + } else { + writeText(textElement.textContent); + } + } else { + writeText(cellElement.textContent); + } +} + +const genCellValueByElement = (colType: TAVCol, cellElement: HTMLElement) => { + let cellValue: IAVCellValue; + if (colType === "number") { + const value = cellElement.querySelector(".av__celltext").getAttribute("data-content") + cellValue = { + type: colType, + number: { + content: parseFloat(value) || 0, + isNotEmpty: !!value + } + }; + } else if (["text", "block", "url", "phone", "email", "template"].includes(colType)) { + cellValue = { + type: colType, + [colType]: { + content: cellElement.querySelector(".av__celltext").textContent.trim() + } + }; + } else if (colType === "mSelect" || colType === "select") { + const mSelect: IAVCellSelectValue[] = [] + cellElement.querySelectorAll(".b3-chip").forEach((item: HTMLElement) => { + mSelect.push({ + content: item.textContent.trim(), + color: item.style.color.replace("var(--b3-font-color", "").replace(")", "") + }) + }) + cellValue = { + type: colType, + mSelect + }; + } else if (["date", "created", "updated"].includes(colType)) { + debugger; + cellValue = { + type: colType, + [colType]: JSON.parse(cellElement.querySelector(".av__celltext").getAttribute("data-value")) + }; + } + return cellValue; +} + export const genCellValue = (colType: TAVCol, value: string | any) => { let cellValue: IAVCellValue; if (typeof value === "string") { @@ -24,6 +80,7 @@ export const genCellValue = (colType: TAVCol, value: string | any) => { cellValue = { type: colType, number: { + content: 0, isNotEmpty: false } }; @@ -177,7 +234,7 @@ export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[], type } else if (type === "date") { openMenuPanel({protyle, blockElement, type: "date", cellElements}); } else if (type === "checkbox") { - updateCellValue(protyle, type, cellElements); + updateCellValueByInput(protyle, type, cellElements); } if (!hasClosestByClassName(cellElements[0], "custom-attr")) { cellElements[0].classList.add("av__cell--select"); @@ -210,7 +267,7 @@ export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[], type } if (event.key === "Escape" || event.key === "Tab" || (event.key === "Enter" && !event.shiftKey && isNotCtrl(event))) { - updateCellValue(protyle, type, cellElements); + updateCellValueByInput(protyle, type, cellElements); if (event.key === "Tab") { protyle.wysiwyg.element.dispatchEvent(new KeyboardEvent("keydown", { shiftKey: event.shiftKey, @@ -228,13 +285,13 @@ export const popTextCell = (protyle: IProtyle, cellElements: HTMLElement[], type } avMaskElement.addEventListener("click", (event) => { if ((event.target as HTMLElement).classList.contains("av__mask")) { - updateCellValue(protyle, type, cellElements); + updateCellValueByInput(protyle, type, cellElements); avMaskElement?.remove(); } }); }; -const updateCellValue = (protyle: IProtyle, type: TAVCol, cellElements: HTMLElement[]) => { +const updateCellValueByInput = (protyle: IProtyle, type: TAVCol, cellElements: HTMLElement[]) => { const rowElement = hasClosestByClassName(cellElements[0], "av__row"); if (!rowElement) { return; @@ -377,3 +434,69 @@ const updateCellValue = (protyle: IProtyle, type: TAVCol, cellElements: HTMLElem item.remove(); }); }; + +export const updateCellsValue = (protyle: IProtyle, nodeElement: HTMLElement) => { + const doOperations: IOperation[] = [] + const undoOperations: IOperation[] = [] + + const avID = nodeElement.dataset.avId + const id = nodeElement.dataset.nodeId + let text = '' + const cellElements: Element[] = Array.from(nodeElement.querySelectorAll(".av__cell--select")) || []; + if (cellElements.length === 0) { + nodeElement.querySelectorAll(".av__row--select:not(.av__row--header)").forEach(rowElement => { + rowElement.querySelectorAll(".av__cell").forEach(cellElement => { + cellElements.push(cellElement) + }) + }); + } + cellElements.forEach((item: HTMLElement) => { + const rowElement = hasClosestByClassName(item, "av__row"); + if (!rowElement) { + return; + } + const type = getTypeByCellElement(item); + if (["created", "updated", "template"].includes(type)) { + return; + } + const rowID = rowElement.getAttribute("data-id"); + const cellId = item.getAttribute("data-id"); + const colId = item.getAttribute("data-col-id"); + + text += getCellText(item); + + doOperations.push({ + action: "updateAttrViewCell", + id: cellId, + avID, + keyID: colId, + rowID, + data: genCellValue(type, "") + }); + undoOperations.push({ + action: "updateAttrViewCell", + id: cellId, + avID, + keyID: colId, + rowID, + data: genCellValueByElement(type, item) + }); + if (!hasClosestByClassName(cellElements[0], "custom-attr")) { + updateAttrViewCellAnimation(item); + } + }) + if (doOperations.length > 0) { + doOperations.push({ + action: "doUpdateUpdated", + id, + data: dayjs().format("YYYYMMDDHHmmss"), + }) + undoOperations.push({ + action: "doUpdateUpdated", + id, + data: nodeElement.getAttribute("updated"), + }) + transaction(protyle, doOperations, undoOperations); + } + return text; +} diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts index 2cbc4f4d3..846ec2138 100644 --- a/app/src/protyle/render/av/render.ts +++ b/app/src/protyle/render/av/render.ts @@ -161,8 +161,8 @@ style="width: ${column.width || "200px"}">${getCalcValue(column) || '${item.content}`; }); } else if (cell.valueType === "date") { - text = ''; const dataValue = cell.value ? cell.value.date : null; + text = ``; if (dataValue && dataValue.isNotEmpty) { text += dayjs(dataValue.content).format(dataValue.isNotTime ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm"); } @@ -171,8 +171,8 @@ style="width: ${column.width || "200px"}">${getCalcValue(column) || '`; if (dataValue && dataValue.isNotEmpty) { text += dayjs(dataValue.content).format("YYYY-MM-DD HH:mm"); } diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index a90f62286..5e0b44128 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -81,6 +81,7 @@ import {showColMenu} from "../render/av/col"; import {openViewMenu} from "../render/av/view"; import {avRender} from "../render/av/render"; import {checkFold} from "../../util/noRelyPCFunction"; +import {getCellText, updateCellsValue} from "../render/av/cell"; export class WYSIWYG { public lastHTMLs: { [key: string]: string } = {}; @@ -241,9 +242,10 @@ export class WYSIWYG { return; } const selectImgElement = nodeElement.querySelector(".img--select"); + const selectAVElement = nodeElement.querySelector(".av__row--select, .av__cell--select"); let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select")); if (selectElements.length === 0 && range.toString() === "" && !range.cloneContents().querySelector("img") && - !selectImgElement) { + !selectImgElement && !selectAVElement) { nodeElement.classList.add("protyle-wysiwyg--select"); countBlockWord([nodeElement.getAttribute("data-node-id")]); selectElements = [nodeElement]; @@ -282,6 +284,20 @@ export class WYSIWYG { } }); } + } else if (selectAVElement) { + const cellElements: Element[] = Array.from(nodeElement.querySelectorAll(".av__cell--select")) || []; + if (cellElements.length === 0) { + nodeElement.querySelectorAll(".av__row--select:not(.av__row--header)").forEach(rowElement => { + rowElement.querySelectorAll(".av__cell").forEach(cellElement => { + cellElements.push(cellElement) + }) + }); + } + cellElements.forEach((item: HTMLElement) => { + const cellText = getCellText(item); + html += cellText; + textPlain += cellText; + }); } else { const tempElement = document.createElement("div"); // https://github.com/siyuan-note/siyuan/issues/5540 @@ -1091,18 +1107,14 @@ export class WYSIWYG { event.preventDefault(); return; } - if (nodeElement.classList.contains("av")) { - updateAVName(protyle, nodeElement); - event.stopPropagation(); - return; - } event.stopPropagation(); event.preventDefault(); const selectImgElement = nodeElement.querySelector(".img--select"); + const selectAVElement = nodeElement.querySelector(".av__row--select, .av__cell--select"); let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select")); if (selectElements.length === 0 && range.toString() === "" && !range.cloneContents().querySelector("img") && - !selectImgElement) { + !selectImgElement && !selectAVElement) { nodeElement.classList.add("protyle-wysiwyg--select"); selectElements = [nodeElement]; } @@ -1131,6 +1143,8 @@ export class WYSIWYG { // Ctrl+X 剪切后光标应跳到下一行行首 https://github.com/siyuan-note/siyuan/issues/5485 focusBlock(nextElement); } + } else if (selectAVElement) { + html = updateCellsValue(protyle, nodeElement); } else { const id = nodeElement.getAttribute("data-node-id"); const oldHTML = nodeElement.outerHTML; @@ -1234,7 +1248,9 @@ export class WYSIWYG { tempElement.append(range.extractContents()); let parentElement: Element | false; // https://ld246.com/article/1647689760545 - if (nodeElement.classList.contains("table")) { + if (nodeElement.classList.contains("av")) { + updateAVName(protyle, nodeElement); + } else if (nodeElement.classList.contains("table")) { parentElement = hasClosestByMatchTag(range.startContainer, "TD") || hasClosestByMatchTag(range.startContainer, "TH"); } else { parentElement = getContenteditableElement(nodeElement); @@ -1267,7 +1283,7 @@ export class WYSIWYG { getContenteditableElement(nodeElement).removeAttribute("data-render"); highlightRender(nodeElement); } - if (nodeElement.parentElement.parentElement && !isFoldHeading) { + if (nodeElement.parentElement.parentElement && !isFoldHeading && !nodeElement.classList.contains("av")) { // 选中 heading 时,使用删除的 transaction updateTransaction(protyle, id, nodeElement.outerHTML, oldHTML); } diff --git a/app/src/protyle/wysiwyg/keydown.ts b/app/src/protyle/wysiwyg/keydown.ts index 89f94381f..87671c386 100644 --- a/app/src/protyle/wysiwyg/keydown.ts +++ b/app/src/protyle/wysiwyg/keydown.ts @@ -1398,19 +1398,6 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { return; } - // 支持非编辑块复制 https://ld246.com/article/1695353747104 - if ((matchHotKey("⌘X", event) || matchHotKey("⌘C", event)) && - selectText === "" && - !nodeElement.querySelector(".img--select")) { - if (protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select").length === 0) { - if (nodeElement.dataset.type !== "NodeHTMLBlock") { - // html 块不需要选中 https://github.com/siyuan-note/siyuan/issues/8706 - nodeElement.classList.add("protyle-wysiwyg--select"); - } - } - // 复制块不能单纯的 BlockDOM2StdMd,否则 https://github.com/siyuan-note/siyuan/issues/9362 - } - if (matchHotKey(window.siyuan.config.keymap.editor.general.vLayout.custom, event)) { event.preventDefault(); event.stopPropagation();