diff --git a/app/src/protyle/util/insertHTML.ts b/app/src/protyle/util/insertHTML.ts
index 0b28250e9..40c631c5b 100644
--- a/app/src/protyle/util/insertHTML.ts
+++ b/app/src/protyle/util/insertHTML.ts
@@ -7,7 +7,7 @@ import {
focusBlock,
focusByWbr,
getEditorRange,
- getSelectionOffset,
+ getSelectionOffset, setLastNodeRange,
} from "./selection";
import {Constants} from "../../constants";
import {highlightRender} from "../render/highlightRender";
@@ -199,6 +199,33 @@ const processAV = (range: Range, html: string, protyle: IProtyle, blockElement:
});
};
+const processTable = (range: Range, html: string, protyle: IProtyle, blockElement: HTMLElement) => {
+ const tempElement = document.createElement("template");
+ tempElement.innerHTML = html;
+ const cellElements = tempElement.content.querySelectorAll("th, td");
+ if (cellElements.length === 0) {
+ return false;
+ }
+ const scrollLeft = blockElement.firstElementChild.scrollLeft;
+ const tableSelectElement = blockElement.querySelector(".table__select") as HTMLElement;
+ let index = 0;
+ const oldHTML = blockElement.outerHTML;
+ blockElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
+ blockElement.querySelectorAll("th, td").forEach((item: HTMLTableCellElement) => {
+ if (!item.classList.contains("fn__none") &&
+ item.offsetLeft + 6 > tableSelectElement.offsetLeft + scrollLeft && item.offsetLeft + item.clientWidth - 6 < tableSelectElement.offsetLeft + scrollLeft + tableSelectElement.clientWidth &&
+ item.offsetTop + 6 > tableSelectElement.offsetTop && item.offsetTop + item.clientHeight - 6 < tableSelectElement.offsetTop + tableSelectElement.clientHeight &&
+ cellElements.length > index) {
+ item.innerHTML = cellElements[index].innerHTML;
+ index++;
+ setLastNodeRange(item, range, false);
+ }
+ });
+ range.collapse(false);
+ updateTransaction(protyle, blockElement.getAttribute("data-node-id"), blockElement.outerHTML, oldHTML);
+ return true;
+}
+
export const insertHTML = (html: string, protyle: IProtyle, isBlock = false,
// 移动端插入嵌入块时,获取到的 range 为旧值
useProtyleRange = false,
@@ -217,13 +244,13 @@ export const insertHTML = (html: string, protyle: IProtyle, isBlock = false,
isBlock = true;
}
}
- let blockElement = hasClosestBlock(range.startContainer) as Element;
+ let blockElement = hasClosestBlock(range.startContainer) as HTMLElement;
if (!blockElement) {
// 使用鼠标点击选则模版提示列表后 range 丢失
if (protyle.toolbar.range) {
- blockElement = hasClosestBlock(protyle.toolbar.range.startContainer) as Element;
+ blockElement = hasClosestBlock(protyle.toolbar.range.startContainer) as HTMLElement;
} else {
- blockElement = protyle.wysiwyg.element.firstElementChild as Element;
+ blockElement = protyle.wysiwyg.element.firstElementChild as HTMLElement;
}
}
if (!blockElement) {
@@ -234,6 +261,10 @@ export const insertHTML = (html: string, protyle: IProtyle, isBlock = false,
processAV(range, html, protyle, blockElement as HTMLElement);
return;
}
+ if (blockElement.classList.contains("table") && blockElement.querySelector(".table__select").clientWidth > 0 &&
+ processTable(range, html, protyle, blockElement)) {
+ return;
+ }
let id = blockElement.getAttribute("data-node-id");
range.insertNode(document.createElement("wbr"));
let oldHTML = blockElement.outerHTML;
diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts
index 134713e6f..6ea8cd9cd 100644
--- a/app/src/protyle/wysiwyg/index.ts
+++ b/app/src/protyle/wysiwyg/index.ts
@@ -1,4 +1,4 @@
-import {getTextStar, paste} from "../util/paste";
+import {getTextStar, paste, pasteText} from "../util/paste";
import {
hasClosestBlock,
hasClosestByAttribute,
@@ -62,7 +62,7 @@ import {openGlobalSearch} from "../../search/util";
import {popSearch} from "../../mobile/menu/search";
/// #endif
import {BlockPanel} from "../../block/Panel";
-import {isInIOS, isOnlyMeta} from "../util/compatibility";
+import {isInIOS, isOnlyMeta, readText} from "../util/compatibility";
import {MenuItem} from "../../menus/Menu";
import {fetchPost} from "../../util/fetch";
import {onGet} from "../util/onGet";
@@ -274,9 +274,10 @@ export class WYSIWYG {
}
const selectImgElement = nodeElement.querySelector(".img--select");
const selectAVElement = nodeElement.querySelector(".av__row--select, .av__cell--select");
+ const selectTableElement = nodeElement.querySelector(".table__select")?.clientWidth > 0;
let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select"));
if (selectElements.length === 0 && range.toString() === "" && !range.cloneContents().querySelector("img") &&
- !selectImgElement && !selectAVElement) {
+ !selectImgElement && !selectAVElement && !selectTableElement) {
nodeElement.classList.add("protyle-wysiwyg--select");
countBlockWord([nodeElement.getAttribute("data-node-id")]);
selectElements = [nodeElement];
@@ -331,6 +332,31 @@ export class WYSIWYG {
textPlain = textPlain.substring(0, textPlain.length - 2);
html = html.substring(0, html.length - 1) + "]";
}
+ } else if (selectTableElement) {
+ const selectCellElements: HTMLTableCellElement[] = [];
+ const scrollLeft = nodeElement.firstElementChild.scrollLeft;
+ const tableSelectElement = nodeElement.querySelector(".table__select") as HTMLElement;
+ html = '
'
+ nodeElement.querySelectorAll("th, td").forEach((item: HTMLTableCellElement) => {
+ if (!item.classList.contains("fn__none") &&
+ item.offsetLeft + 6 > tableSelectElement.offsetLeft + scrollLeft && item.offsetLeft + item.clientWidth - 6 < tableSelectElement.offsetLeft + scrollLeft + tableSelectElement.clientWidth &&
+ item.offsetTop + 6 > tableSelectElement.offsetTop && item.offsetTop + item.clientHeight - 6 < tableSelectElement.offsetTop + tableSelectElement.clientHeight) {
+ selectCellElements.push(item);
+ }
+ });
+ selectCellElements.forEach((item, index) => {
+ if (index === 0 || !item.previousElementSibling ||
+ !item.previousElementSibling.isSameNode(selectCellElements[index - 1])) {
+ html += ""
+ }
+ html += item.outerHTML;
+ if (!item.nextElementSibling || !selectCellElements[index + 1] ||
+ !item.nextElementSibling.isSameNode(selectCellElements[index + 1])) {
+ html += "
";
+ }
+ })
+ html += '
'
+ textPlain = protyle.lute.HTML2Md(html);
} else {
const tempElement = document.createElement("div");
// https://github.com/siyuan-note/siyuan/issues/5540
@@ -394,8 +420,8 @@ 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", protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html));
- event.clipboardData.setData("text/siyuan", html);
+ event.clipboardData.setData("text/html", selectTableElement ? html : protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html));
+ event.clipboardData.setData("text/siyuan", selectTableElement ? protyle.lute.HTML2BlockDOM(html) : html);
});
this.element.addEventListener("mousedown", (event: MouseEvent) => {
@@ -1222,6 +1248,28 @@ export class WYSIWYG {
}
}).element);
window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element);
+ window.siyuan.menus.menu.append(new MenuItem({
+ icon: "iconCopy",
+ accelerator: "⌘C",
+ label: window.siyuan.languages.copy,
+ click() {
+ if (tableBlockElement) {
+ focusByRange(getEditorRange(tableBlockElement));
+ document.execCommand("copy");
+ }
+ }
+ }).element);
+ window.siyuan.menus.menu.append(new MenuItem({
+ icon: "iconCut",
+ accelerator: "⌘X",
+ label: window.siyuan.languages.cut,
+ click() {
+ if (tableBlockElement) {
+ focusByRange(getEditorRange(tableBlockElement));
+ document.execCommand("cut");
+ }
+ }
+ }).element);
window.siyuan.menus.menu.append(new MenuItem({
label: window.siyuan.languages.clear,
icon: "iconTrashcan",
@@ -1238,6 +1286,7 @@ export class WYSIWYG {
});
tableSelectElement.removeAttribute("style");
const oldHTML = tableBlockElement.outerHTML;
+ tableBlockElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
selectCellElements.forEach(item => {
item.innerHTML = "";
});
@@ -1245,6 +1294,23 @@ export class WYSIWYG {
}
}
}).element);
+ window.siyuan.menus.menu.append(new MenuItem({
+ label: window.siyuan.languages.paste,
+ icon: "iconPaste",
+ accelerator: "⌘V",
+ async click() {
+ if (document.queryCommandSupported("paste")) {
+ document.execCommand("paste");
+ } else if (tableBlockElement) {
+ try {
+ const clipText = await readText();
+ pasteText(protyle, clipText, tableBlockElement);
+ } catch (e) {
+ console.log(e);
+ }
+ }
+ }
+ }).element);
window.siyuan.menus.menu.popup({x: mouseUpEvent.clientX - 8, y: mouseUpEvent.clientY - 16});
}
}
@@ -1359,9 +1425,10 @@ export class WYSIWYG {
event.preventDefault();
const selectImgElement = nodeElement.querySelector(".img--select");
const selectAVElement = nodeElement.querySelector(".av__row--select, .av__cell--select");
+ const selectTableElement = nodeElement.querySelector(".table__select")?.clientWidth > 0;
let selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select"));
if (selectElements.length === 0 && range.toString() === "" && !range.cloneContents().querySelector("img") &&
- !selectImgElement && !selectAVElement) {
+ !selectImgElement && !selectAVElement && !selectTableElement) {
nodeElement.classList.add("protyle-wysiwyg--select");
selectElements = [nodeElement];
}
@@ -1395,6 +1462,35 @@ export class WYSIWYG {
const cellsValue = updateCellsValue(protyle, nodeElement);
html = JSON.stringify(cellsValue.json);
textPlain = cellsValue.text;
+ } else if (selectTableElement) {
+ const selectCellElements: HTMLTableCellElement[] = [];
+ const scrollLeft = nodeElement.firstElementChild.scrollLeft;
+ const tableSelectElement = nodeElement.querySelector(".table__select") as HTMLElement;
+ html = ''
+ const oldHTML = nodeElement.outerHTML;
+ nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
+ nodeElement.querySelectorAll("th, td").forEach((item: HTMLTableCellElement) => {
+ if (!item.classList.contains("fn__none") &&
+ item.offsetLeft + 6 > tableSelectElement.offsetLeft + scrollLeft && item.offsetLeft + item.clientWidth - 6 < tableSelectElement.offsetLeft + scrollLeft + tableSelectElement.clientWidth &&
+ item.offsetTop + 6 > tableSelectElement.offsetTop && item.offsetTop + item.clientHeight - 6 < tableSelectElement.offsetTop + tableSelectElement.clientHeight) {
+ selectCellElements.push(item);
+ }
+ });
+ selectCellElements.forEach((item, index) => {
+ if (index === 0 || !item.previousElementSibling ||
+ !item.previousElementSibling.isSameNode(selectCellElements[index - 1])) {
+ html += ""
+ }
+ html += item.outerHTML;
+ if (!item.nextElementSibling || !selectCellElements[index + 1] ||
+ !item.nextElementSibling.isSameNode(selectCellElements[index + 1])) {
+ html += "
";
+ }
+ item.innerHTML = "";
+ })
+ html += '
'
+ textPlain = protyle.lute.HTML2Md(html);
+ updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, oldHTML);
} else {
const id = nodeElement.getAttribute("data-node-id");
const oldHTML = nodeElement.outerHTML;
@@ -1550,8 +1646,8 @@ 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", protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html));
- event.clipboardData.setData("text/siyuan", html);
+ event.clipboardData.setData("text/html", selectTableElement ? html : protyle.lute.BlockDOM2HTML(selectAVElement ? textPlain : html));
+ event.clipboardData.setData("text/siyuan", selectTableElement ? protyle.lute.HTML2BlockDOM(html) : html);
});
let beforeContextmenuRange: Range;
diff --git a/app/src/types/protyle.d.ts b/app/src/types/protyle.d.ts
index a000df009..fdc667430 100644
--- a/app/src/types/protyle.d.ts
+++ b/app/src/types/protyle.d.ts
@@ -276,6 +276,10 @@ declare class Lute {
public BlockDOM2InlineBlockDOM(html: string): string;
public BlockDOM2HTML(html: string): string;
+
+ public HTML2Md(html: string): string;
+
+ public HTML2BlockDOM(html: string): string;
}
declare const webkitAudioContext: {