diff --git a/app/src/protyle/render/av/cell.ts b/app/src/protyle/render/av/cell.ts index b7d9d8155..ff81ae6c3 100644 --- a/app/src/protyle/render/av/cell.ts +++ b/app/src/protyle/render/av/cell.ts @@ -130,6 +130,18 @@ export const genCellValue = (colType: TAVCol, value: string | any) => { checked: true } }; + } else if (colType === "date") { + cellValue = { + type: colType, + date: { + content: null, + isNotEmpty: false, + content2: null, + isNotEmpty2: false, + hasEndDate: false, + isNotTime: true, + } + }; } } else if (typeof value === "undefined" || !value) { if (colType === "number") { diff --git a/app/src/protyle/render/av/keydown.ts b/app/src/protyle/render/av/keydown.ts index 9bebe79da..3e9ae0079 100644 --- a/app/src/protyle/render/av/keydown.ts +++ b/app/src/protyle/render/av/keydown.ts @@ -23,6 +23,11 @@ export const avKeydown = (event: KeyboardEvent, nodeElement: HTMLElement, protyl if (!rowElement) { return false; } + if (event.key === "Backspace" || event.key === "Delete") { + updateCellsValue(protyle, nodeElement, undefined, Array.from(nodeElement.querySelectorAll(".av__cell--active, .av__cell--select"))); + event.preventDefault(); + return true; + } // 复制、粘贴 if (!event.ctrlKey && !event.metaKey) { nodeElement.querySelectorAll(".av__cell--active").forEach(item => { @@ -41,11 +46,6 @@ export const avKeydown = (event: KeyboardEvent, nodeElement: HTMLElement, protyl event.preventDefault(); return true; } - if (event.key === "Backspace" || event.key === "Delete") { - updateCellsValue(protyle, nodeElement, undefined, [selectCellElement]); - event.preventDefault(); - return true; - } let newCellElement; if (event.key === "ArrowLeft" || matchHotKey("⇧⇥", event)) { const previousRowElement = rowElement.previousElementSibling; diff --git a/app/src/protyle/util/insertHTML.ts b/app/src/protyle/util/insertHTML.ts index e336857f5..f8fc576fe 100644 --- a/app/src/protyle/util/insertHTML.ts +++ b/app/src/protyle/util/insertHTML.ts @@ -6,11 +6,113 @@ import {fixTableRange, focusBlock, focusByWbr, getEditorRange} from "./selection import {Constants} from "../../constants"; import {highlightRender} from "../render/highlightRender"; import {scrollCenter} from "../../util/highlightById"; -import {updateAVName} from "../render/av/action"; -import {updateCellsValue} from "../render/av/cell"; +import {updateAttrViewCellAnimation, updateAVName} from "../render/av/action"; +import { + genCellValue, + genCellValueByElement, + getTypeByCellElement, + updateCellsValue +} from "../render/av/cell"; import {input} from "../wysiwyg/input"; +import {objEquals} from "../../util/functions"; -const processAV = (range: Range, html: string, protyle: IProtyle, blockElement: Element) => { +const processAV = (range: Range, html: string, protyle: IProtyle, blockElement: HTMLElement) => { + if (html.endsWith("]") && html.startsWith("[")) { + try { + const values = JSON.parse(html); + const cellElements: Element[] = Array.from(blockElement.querySelectorAll(".av__cell--active, .av__cell--select")) || []; + if (cellElements.length === 0) { + blockElement.querySelectorAll(".av__row--select:not(.av__row--header)").forEach(rowElement => { + rowElement.querySelectorAll(".av__cell").forEach(cellElement => { + cellElements.push(cellElement); + }); + }); + } + const doOperations: IOperation[] = []; + const undoOperations: IOperation[] = []; + + const avID = blockElement.dataset.avId; + const id = blockElement.dataset.nodeId; + cellElements.forEach((item: HTMLElement, elementIndex) => { + let cellValue: IAVCellValue = values[elementIndex] + if (!cellValue) { + return; + } + const rowElement = hasClosestByClassName(item, "av__row"); + if (!rowElement) { + return; + } + if (!blockElement.contains(item)) { + item = cellElements[elementIndex] = blockElement.querySelector(`.av__row[data-id="${rowElement.dataset.id}"] .av__cell[data-col-id="${item.dataset.colId}"]`) as HTMLElement; + } + const type = getTypeByCellElement(item) || item.dataset.type as TAVCol; + if (["created", "updated", "template", "rollup"].includes(type)) { + return; + } + + const rowID = rowElement.getAttribute("data-id"); + const cellId = item.getAttribute("data-id"); + const colId = item.getAttribute("data-col-id"); + + const oldValue = genCellValueByElement(type, item); + if (cellValue.type !== type) { + if (type === "date") { + // 类型不能转换时就不进行替换 + return; + } + const content = cellValue[cellValue.type as "text"].content + if (!content) { + return; + } + cellValue = genCellValue(type, cellValue[cellValue.type as "text"].content.toString()); + } else if (cellValue.type === "block") { + cellValue.isDetached = true; + delete cellValue.block.id; + } + cellValue.id = cellId; + if ((cellValue.type === "date" && typeof cellValue.date === "string") || + (cellValue.type === "relation" && typeof cellValue.relation === "string")) { + return; + } + if (objEquals(cellValue, oldValue)) { + return; + } + doOperations.push({ + action: "updateAttrViewCell", + id: cellId, + avID, + keyID: colId, + rowID, + data: cellValue + }); + undoOperations.push({ + action: "updateAttrViewCell", + id: cellId, + avID, + keyID: colId, + rowID, + data: oldValue + }); + updateAttrViewCellAnimation(item, cellValue); + }); + if (doOperations.length > 0) { + doOperations.push({ + action: "doUpdateUpdated", + id, + data: dayjs().format("YYYYMMDDHHmmss"), + }); + undoOperations.push({ + action: "doUpdateUpdated", + id, + data: blockElement.getAttribute("updated"), + }); + transaction(protyle, doOperations, undoOperations); + } + return; + } catch (e) { + console.warn("insert cell: JSON.parse error") + } + } const text = protyle.lute.BlockDOM2EscapeMarkerContent(html); const cellsElement: HTMLElement[] = Array.from(blockElement.querySelectorAll(".av__cell--select")); const rowsElement = blockElement.querySelector(".av__row--select"); @@ -56,7 +158,7 @@ export const insertHTML = (html: string, protyle: IProtyle, isBlock = false, } if (blockElement.classList.contains("av")) { range.deleteContents(); - processAV(range, html, protyle, blockElement); + processAV(range, html, protyle, blockElement as HTMLElement); return; } let id = blockElement.getAttribute("data-node-id"); diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index 5195b1980..926ce2dd3 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -374,7 +374,7 @@ export class WYSIWYG { textPlain = textPlain || protyle.lute.BlockDOM2StdMd(html).trimEnd(); textPlain = textPlain.replace(/\u00A0/g, " "); // Replace non-breaking spaces with normal spaces when copying https://github.com/siyuan-note/siyuan/issues/9382 event.clipboardData.setData("text/plain", textPlain); - event.clipboardData.setData("text/html", selectAVElement ? html : protyle.lute.BlockDOM2HTML(html)); + event.clipboardData.setData("text/html", protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html)); event.clipboardData.setData("text/siyuan", html); }); @@ -1452,7 +1452,7 @@ export class WYSIWYG { } textPlain = textPlain.replace(/\u00A0/g, " "); // Replace non-breaking spaces with normal spaces when copying https://github.com/siyuan-note/siyuan/issues/9382 event.clipboardData.setData("text/plain", textPlain); - event.clipboardData.setData("text/html", selectAVElement ? html : protyle.lute.BlockDOM2HTML(html)); + event.clipboardData.setData("text/html", protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html)); event.clipboardData.setData("text/siyuan", html); }); diff --git a/app/src/util/highlightById.ts b/app/src/util/highlightById.ts index e566b9a10..406c51d09 100644 --- a/app/src/util/highlightById.ts +++ b/app/src/util/highlightById.ts @@ -39,19 +39,27 @@ export const highlightById = (protyle: IProtyle, id: string, top = false) => { }; export const scrollCenter = (protyle: IProtyle, nodeElement?: Element, top = false, behavior: ScrollBehavior = "auto") => { - if (!protyle.disabled && !top && getSelection().rangeCount > 0 && hasClosestBlock(getSelection().getRangeAt(0).startContainer)) { - const editorElement = protyle.contentElement; - const cursorTop = getSelectionPosition(editorElement).top - editorElement.getBoundingClientRect().top; - let top = 0; - if (cursorTop < 0) { - top = editorElement.scrollTop + cursorTop; - } else if (cursorTop > editorElement.clientHeight - 74) { // 74 = 移动端底部 + 段落块高度 - top = editorElement.scrollTop + (cursorTop + 74 - editorElement.clientHeight); + if (!protyle.disabled && !top && getSelection().rangeCount > 0) { + const blockElement = hasClosestBlock(getSelection().getRangeAt(0).startContainer); + if (blockElement) { + // undo 时禁止数据库滚动 + if (blockElement.classList.contains("av") && blockElement.dataset.render === "true" && + (blockElement.querySelector(".av__row--header").getAttribute("style").indexOf("transform") > -1 || blockElement.querySelector(".av__row--footer").getAttribute("style").indexOf("transform") > -1)) { + return; + } + const editorElement = protyle.contentElement; + const cursorTop = getSelectionPosition(editorElement).top - editorElement.getBoundingClientRect().top; + let scrollTop = 0; + if (cursorTop < 0) { + scrollTop = editorElement.scrollTop + cursorTop; + } else if (cursorTop > editorElement.clientHeight - 74) { // 74 = 移动端底部 + 段落块高度 + scrollTop = editorElement.scrollTop + (cursorTop + 74 - editorElement.clientHeight); + } + if (scrollTop !== 0) { + editorElement.scroll({top: scrollTop, behavior}); + } + return; } - if (top !== 0) { - editorElement.scroll({top, behavior}); - } - return; } if (!nodeElement) {