import {updateTransaction} from "../wysiwyg/transaction";
import {getSelectionOffset, focusByWbr, focusByRange, focusBlock} from "./selection";
import {hasClosestBlock, hasClosestByMatchTag} from "./hasClosest";
import {matchHotKey} from "./hotKey";
import {isCtrl} from "./compatibility";
import {scrollCenter} from "../../util/highlightById";
import {insertEmptyBlock} from "../../block/util";
const scrollToView = (nodeElement: Element, rowElement: HTMLElement, protyle: IProtyle) => {
if (nodeElement.getAttribute("custom-pinthead") === "true") {
const tableElement = nodeElement.querySelector("table");
if (tableElement.clientHeight + tableElement.scrollTop < rowElement.offsetTop + rowElement.clientHeight) {
tableElement.scrollTop = rowElement.offsetTop - tableElement.clientHeight + rowElement.clientHeight + 1;
} else if (tableElement.scrollTop > rowElement.offsetTop - rowElement.clientHeight) {
tableElement.scrollTop = rowElement.offsetTop - rowElement.clientHeight + 1;
}
} else {
scrollCenter(protyle, rowElement);
}
}
export const getColIndex = (cellElement: HTMLElement) => {
let previousElement = cellElement.previousElementSibling;
let index = 0;
while (previousElement) {
index++;
previousElement = previousElement.previousElementSibling;
}
return index;
};
// 光标设置到前一个表格中
const goPreviousCell = (cellElement: HTMLElement, range: Range, isSelected = true) => {
let previousElement = cellElement.previousElementSibling;
if (!previousElement) {
if (cellElement.parentElement.previousElementSibling) {
previousElement = cellElement.parentElement.previousElementSibling.lastElementChild;
} else if (cellElement.parentElement.parentElement.tagName === "TBODY" &&
cellElement.parentElement.parentElement.previousElementSibling) {
previousElement = cellElement.parentElement
.parentElement.previousElementSibling.lastElementChild.lastElementChild;
} else {
previousElement = null;
}
}
if (previousElement) {
range.selectNodeContents(previousElement);
if (!isSelected) {
range.collapse(false);
}
focusByRange(range);
}
return previousElement;
};
export const setTableAlign = (protyle: IProtyle, cellElements: HTMLElement[], nodeElement: Element, type: string, range: Range) => {
range.insertNode(document.createElement("wbr"));
const html = nodeElement.outerHTML;
const tableElement = nodeElement.querySelector("table");
const columnCnt = tableElement.rows[0].cells.length;
const rowCnt = tableElement.rows.length;
const currentColumns: number[] = [];
for (let i = 0; i < rowCnt; i++) {
for (let j = 0; j < columnCnt; j++) {
if (tableElement.rows[i].cells[j].isSameNode(cellElements[currentColumns.length])) {
currentColumns.push(j);
}
}
if (currentColumns.length > 0) {
break;
}
}
for (let k = 0; k < rowCnt; k++) {
currentColumns.forEach(item => {
tableElement.rows[k].cells[item].setAttribute("align", type);
});
}
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
focusByWbr(tableElement, range);
};
export const insertRow = (protyle: IProtyle, range: Range, cellElement: HTMLElement, nodeElement: Element) => {
const wbrElement = document.createElement("wbr");
range.insertNode(wbrElement);
const html = nodeElement.outerHTML;
wbrElement.remove();
let rowHTML = "";
for (let m = 0; m < cellElement.parentElement.childElementCount; m++) {
rowHTML += `
| `;
}
let newRowElememt: HTMLTableRowElement;
if (cellElement.tagName === "TH") {
const tbodyElement = nodeElement.querySelector("tbody");
if (tbodyElement) {
tbodyElement.insertAdjacentHTML("afterbegin", `${rowHTML}
`);
newRowElememt = tbodyElement.firstElementChild as HTMLTableRowElement;
} else {
cellElement.parentElement.parentElement.insertAdjacentHTML("afterend", `${rowHTML}
`);
newRowElememt = cellElement.parentElement.parentElement.nextElementSibling.firstElementChild as HTMLTableRowElement;
}
} else {
cellElement.parentElement.insertAdjacentHTML("afterend", `${rowHTML}
`);
newRowElememt = cellElement.parentElement.nextElementSibling as HTMLTableRowElement;
}
range.selectNodeContents(newRowElememt.cells[getColIndex(cellElement)]);
range.collapse(true);
focusByRange(range);
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
scrollToView(nodeElement, newRowElememt, protyle);
};
export const insertRowAbove = (protyle: IProtyle, range: Range, cellElement: HTMLElement, nodeElement: Element) => {
const wbrElement = document.createElement("wbr");
range.insertNode(wbrElement);
const html = nodeElement.outerHTML;
wbrElement.remove();
let rowHTML = "";
let hasNone = false;
for (let m = 0; m < cellElement.parentElement.childElementCount; m++) {
const currentCellElement = cellElement.parentElement.children[m] as HTMLTableCellElement;
const className = currentCellElement.className;
if (className === "fn__none") {
hasNone = true;
}
// 不需要空格,否则列宽调整后在空格后插入图片会换行 https://github.com/siyuan-note/siyuan/issues/7631
if (cellElement.tagName === "TH") {
rowHTML += ` | `;
} else {
rowHTML += ` | `;
}
}
if (hasNone) {
let previousTrElement = cellElement.parentElement.previousElementSibling;
let rowCount = 1;
while (previousTrElement) {
rowCount++;
Array.from(previousTrElement.children).forEach((cell: HTMLTableCellElement) => {
if (cell.rowSpan >= rowCount && cell.rowSpan > 1) {
cell.rowSpan = cell.rowSpan + 1;
}
});
previousTrElement = previousTrElement.previousElementSibling;
}
}
let newRowElememt: HTMLTableRowElement;
if (cellElement.parentElement.parentElement.tagName === "THEAD" && !cellElement.parentElement.previousElementSibling) {
cellElement.parentElement.parentElement.insertAdjacentHTML("beforebegin", `${rowHTML}
`);
newRowElememt = nodeElement.querySelector("thead tr");
cellElement.parentElement.parentElement.nextElementSibling.insertAdjacentHTML("afterbegin", cellElement.parentElement.parentElement.innerHTML);
cellElement.parentElement.parentElement.remove();
} else {
cellElement.parentElement.insertAdjacentHTML("beforebegin", `${rowHTML}
`);
newRowElememt = cellElement.parentElement.previousElementSibling as HTMLTableRowElement;
}
range.selectNodeContents(newRowElememt.cells[getColIndex(cellElement)]);
range.collapse(true);
focusByRange(range);
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
scrollToView(nodeElement, newRowElememt, protyle);
};
export const insertColumn = (protyle: IProtyle, nodeElement: Element, cellElement: HTMLElement, type: InsertPosition, range: Range) => {
const wbrElement = document.createElement("wbr");
range.insertNode(wbrElement);
const html = nodeElement.outerHTML;
wbrElement.remove();
const index = getColIndex(cellElement);
const tableElement = nodeElement.querySelector("table");
for (let i = 0; i < tableElement.rows.length; i++) {
const colCellElement = tableElement.rows[i].cells[index];
const newCellElement = document.createElement(colCellElement.tagName);
colCellElement.insertAdjacentElement(type, newCellElement);
if (colCellElement.isSameNode(cellElement)) {
newCellElement.innerHTML = " ";
// 滚动条横向定位
if (newCellElement.offsetLeft + newCellElement.clientWidth > nodeElement.firstElementChild.scrollLeft + nodeElement.firstElementChild.clientWidth) {
nodeElement.firstElementChild.scrollLeft = newCellElement.offsetLeft + newCellElement.clientWidth - nodeElement.firstElementChild.clientWidth;
}
} else {
newCellElement.textContent = " ";
}
}
tableElement.querySelectorAll("col")[index].insertAdjacentHTML(type, "");
focusByWbr(nodeElement, range);
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
};
export const deleteRow = (protyle: IProtyle, range: Range, cellElement: HTMLElement, nodeElement: Element) => {
if (cellElement.parentElement.parentElement.tagName !== "THEAD") {
const wbrElement = document.createElement("wbr");
range.insertNode(wbrElement);
const html = nodeElement.outerHTML;
wbrElement.remove();
const index = getColIndex(cellElement);
const tbodyElement = cellElement.parentElement.parentElement;
let previousTrElement = tbodyElement.previousElementSibling.lastElementChild as HTMLTableRowElement;
if (cellElement.parentElement.previousElementSibling) {
previousTrElement = cellElement.parentElement.previousElementSibling as HTMLTableRowElement;
}
if (tbodyElement.childElementCount === 1) {
tbodyElement.remove();
} else {
cellElement.parentElement.remove();
}
range.selectNodeContents(previousTrElement.cells[index]);
range.collapse(true);
focusByRange(range);
scrollToView(nodeElement, previousTrElement, protyle);
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
}
};
export const deleteColumn = (protyle: IProtyle, range: Range, nodeElement: Element, cellElement: HTMLElement) => {
const wbrElement = document.createElement("wbr");
range.insertNode(wbrElement);
const html = nodeElement.outerHTML;
wbrElement.remove();
const index = getColIndex(cellElement);
const sideCellElement = (cellElement.previousElementSibling || cellElement.nextElementSibling) as HTMLElement;
if (sideCellElement) {
range.selectNodeContents(sideCellElement);
range.collapse(true);
// 滚动条横向定位
if (sideCellElement.offsetLeft + sideCellElement.clientWidth > nodeElement.firstElementChild.scrollLeft + nodeElement.firstElementChild.clientWidth) {
nodeElement.firstElementChild.scrollLeft = sideCellElement.offsetLeft + sideCellElement.clientWidth - nodeElement.firstElementChild.clientWidth;
}
}
const tableElement = nodeElement.querySelector("table");
for (let i = 0; i < tableElement.rows.length; i++) {
const cells = tableElement.rows[i].cells;
if (cells.length === 1) {
tableElement.remove();
break;
}
cells[index].remove();
}
nodeElement.querySelectorAll("col")[index]?.remove();
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
focusByRange(range);
};
export const moveRowToUp = (protyle: IProtyle, range: Range, cellElement: HTMLElement, nodeElement: Element) => {
const rowElement = cellElement.parentElement;
if (rowElement.parentElement.tagName === "THEAD") {
return;
}
range.insertNode(document.createElement("wbr"));
const html = nodeElement.outerHTML;
if (rowElement.previousElementSibling) {
rowElement.after(rowElement.previousElementSibling);
} else {
const headElement = rowElement.parentElement.previousElementSibling.firstElementChild;
headElement.querySelectorAll("th").forEach(item => {
const tdElement = document.createElement("td");
tdElement.innerHTML = item.innerHTML;
item.parentNode.replaceChild(tdElement, item);
});
rowElement.querySelectorAll("td").forEach(item => {
const thElement = document.createElement("th");
thElement.innerHTML = item.innerHTML;
item.parentNode.replaceChild(thElement, item);
});
rowElement.after(headElement);
rowElement.parentElement.previousElementSibling.append(rowElement);
}
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
focusByWbr(nodeElement, range);
scrollCenter(protyle, rowElement);
};
export const moveRowToDown = (protyle: IProtyle, range: Range, cellElement: HTMLElement, nodeElement: Element) => {
const rowElement = cellElement.parentElement;
if ((rowElement.parentElement.tagName === "TBODY" && !rowElement.nextElementSibling) ||
(rowElement.parentElement.tagName === "THEAD" && !rowElement.parentElement.nextElementSibling)) {
return;
}
range.insertNode(document.createElement("wbr"));
const html = nodeElement.outerHTML;
if (rowElement.nextElementSibling) {
rowElement.before(rowElement.nextElementSibling);
} else {
const firstRowElement = rowElement.parentElement.nextElementSibling.firstElementChild;
firstRowElement.querySelectorAll("td").forEach(item => {
const thElement = document.createElement("th");
thElement.innerHTML = item.innerHTML;
item.parentNode.replaceChild(thElement, item);
});
rowElement.querySelectorAll("th").forEach(item => {
const tdElement = document.createElement("td");
tdElement.innerHTML = item.innerHTML;
item.parentNode.replaceChild(tdElement, item);
});
rowElement.after(firstRowElement);
rowElement.parentElement.nextElementSibling.insertAdjacentElement("afterbegin", rowElement);
}
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
focusByWbr(nodeElement, range);
scrollCenter(protyle, rowElement);
};
export const moveColumnToLeft = (protyle: IProtyle, range: Range, cellElement: HTMLElement, nodeElement: Element) => {
if (!cellElement.previousElementSibling) {
return;
}
range.insertNode(document.createElement("wbr"));
const html = nodeElement.outerHTML;
let cellIndex = 0;
Array.from(cellElement.parentElement.children).find((item, index) => {
if (cellElement.isSameNode(item)) {
cellIndex = index;
return true;
}
});
nodeElement.querySelectorAll("tr").forEach((trElement) => {
trElement.cells[cellIndex].after(trElement.cells[cellIndex - 1]);
});
// 滚动条横向定位
if (cellElement.offsetLeft < nodeElement.firstElementChild.scrollLeft) {
nodeElement.firstElementChild.scrollLeft = cellElement.offsetLeft;
}
const colElements = nodeElement.querySelectorAll("col");
colElements[cellIndex].after(colElements[cellIndex - 1]);
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
focusByWbr(nodeElement, range);
};
export const moveColumnToRight = (protyle: IProtyle, range: Range, cellElement: HTMLElement, nodeElement: Element) => {
if (!cellElement.nextElementSibling) {
return;
}
range.insertNode(document.createElement("wbr"));
const html = nodeElement.outerHTML;
let cellIndex = 0;
Array.from(cellElement.parentElement.children).find((item, index) => {
if (cellElement.isSameNode(item)) {
cellIndex = index;
return true;
}
});
nodeElement.querySelectorAll("tr").forEach((trElement) => {
trElement.cells[cellIndex].before(trElement.cells[cellIndex + 1]);
});
// 滚动条横向定位
if (cellElement.offsetLeft + cellElement.clientWidth > nodeElement.firstElementChild.scrollLeft + nodeElement.firstElementChild.clientWidth) {
nodeElement.firstElementChild.scrollLeft = cellElement.offsetLeft + cellElement.clientWidth - nodeElement.firstElementChild.clientWidth;
}
const colElements = nodeElement.querySelectorAll("col");
colElements[cellIndex].before(colElements[cellIndex + 1]);
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
focusByWbr(nodeElement, range);
};
export const fixTable = (protyle: IProtyle, event: KeyboardEvent, range: Range) => {
const cellElement = hasClosestByMatchTag(range.startContainer, "TD") || hasClosestByMatchTag(range.startContainer, "TH");
const nodeElement = hasClosestBlock(range.startContainer) as HTMLTableElement;
if (!cellElement || !nodeElement) {
return false;
}
if (nodeElement.classList.contains("protyle-wysiwyg--select")) {
return false;
}
// shift+enter 软换行
if (event.key === "Enter" && event.shiftKey && !isCtrl(event) && !event.altKey) {
const wbrElement = document.createElement("wbr");
range.insertNode(wbrElement);
const oldHTML = nodeElement.outerHTML;
wbrElement.remove();
if (cellElement && !cellElement.innerHTML.endsWith("
")) {
cellElement.insertAdjacentHTML("beforeend", "
");
}
range.extractContents();
const types = protyle.toolbar.getCurrentType(range);
if (types.includes("code") && range.startContainer.nodeType !== 3) {
// https://github.com/siyuan-note/siyuan/issues/4169
const brElement = document.createElement("br");
(range.startContainer as HTMLElement).after(brElement);
range.setStartAfter(brElement);
} else {
range.insertNode(document.createElement("br"));
}
range.collapse(false);
scrollCenter(protyle);
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, oldHTML);
event.preventDefault();
return true;
}
// enter 光标跳转到下一行同列
if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Enter") {
event.preventDefault();
const trElement = cellElement.parentElement as HTMLTableRowElement;
if ((!trElement.nextElementSibling && trElement.parentElement.tagName === "TBODY") ||
(trElement.parentElement.tagName === "THEAD" && !trElement.parentElement.nextElementSibling)) {
return true;
}
let nextElement = trElement.nextElementSibling as HTMLTableRowElement;
if (!nextElement) {
nextElement = trElement.parentElement.nextElementSibling.firstChild as HTMLTableRowElement;
}
if (!nextElement) {
return true;
}
range.selectNodeContents(nextElement.cells[getColIndex(cellElement)]);
range.collapse(true);
scrollCenter(protyle);
return true;
}
// 表格后无内容时,按右键需新建空块
if (event.key === "ArrowRight" && range.toString() === "" &&
!nodeElement.nextElementSibling &&
cellElement.isSameNode(nodeElement.querySelector("table").lastElementChild.lastElementChild.lastElementChild) &&
getSelectionOffset(cellElement, protyle.wysiwyg.element, range).start === cellElement.textContent.length) {
event.preventDefault();
insertEmptyBlock(protyle, "afterend", nodeElement.getAttribute("data-node-id"));
return true;
}
// tab:光标移向下一个 cell
if (event.key === "Tab" && !event.ctrlKey) {
if (event.shiftKey) {
// shift + tab 光标移动到前一个 cell
goPreviousCell(cellElement, range);
event.preventDefault();
return true;
}
let nextElement = cellElement.nextElementSibling;
if (!nextElement) {
if (cellElement.parentElement.nextElementSibling) {
nextElement = cellElement.parentElement.nextElementSibling.firstElementChild;
} else if (cellElement.parentElement.parentElement.tagName === "THEAD" &&
cellElement.parentElement.parentElement.nextElementSibling) {
nextElement =
cellElement.parentElement.parentElement.nextElementSibling.firstElementChild.firstElementChild;
} else {
nextElement = null;
}
}
if (nextElement) {
range.selectNodeContents(nextElement);
} else {
insertRow(protyle, range, cellElement, nodeElement);
range.selectNodeContents(nodeElement.querySelector("tbody").lastElementChild.firstElementChild);
}
event.preventDefault();
return true;
}
if (event.key === "ArrowUp" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
const startContainer = range.startContainer as HTMLElement;
let previousBrElement;
if (startContainer.nodeType !== 3 && (startContainer.tagName === "TH" || startContainer.tagName === "TD")) {
previousBrElement = (startContainer.childNodes[Math.max(0, range.startOffset - 1)] as HTMLElement)?.previousElementSibling;
} else if (startContainer.parentElement.tagName === "SPAN") {
previousBrElement = startContainer.parentElement.previousElementSibling;
} else {
previousBrElement = startContainer.previousElementSibling;
}
while (previousBrElement) {
if (previousBrElement.tagName === "BR") {
return false;
}
previousBrElement = previousBrElement.previousElementSibling;
}
const trElement = cellElement.parentElement as HTMLTableRowElement;
let previousElement = trElement.previousElementSibling as HTMLTableRowElement;
if (!previousElement) {
previousElement = trElement.parentElement.previousElementSibling.lastElementChild as HTMLTableRowElement;
}
if (!previousElement || previousElement?.tagName === "COL") {
return false;
}
range.selectNodeContents(previousElement.cells[getColIndex(cellElement)]);
range.collapse(false);
scrollCenter(protyle);
event.preventDefault();
return true;
}
if (event.key === "ArrowDown" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
const endContainer = range.endContainer as HTMLElement;
let nextBrElement;
if (endContainer.nodeType !== 3 && (endContainer.tagName === "TH" || endContainer.tagName === "TD")) {
nextBrElement = (endContainer.childNodes[Math.max(0, range.endOffset - 1)] as HTMLElement)?.nextElementSibling;
} else if (endContainer.parentElement.tagName === "SPAN") {
nextBrElement = endContainer.parentElement.nextElementSibling;
} else {
nextBrElement = endContainer.nextElementSibling;
}
while (nextBrElement) {
if (nextBrElement.tagName === "BR" && nextBrElement.nextSibling) {
return false;
}
nextBrElement = nextBrElement.nextElementSibling;
}
const trElement = cellElement.parentElement as HTMLTableRowElement;
if ((!trElement.nextElementSibling && trElement.parentElement.tagName === "TBODY") ||
(trElement.parentElement.tagName === "THEAD" && !trElement.parentElement.nextElementSibling)) {
return false;
}
let nextElement = trElement.nextElementSibling as HTMLTableRowElement;
if (!nextElement) {
nextElement = trElement.parentElement.nextElementSibling.firstChild as HTMLTableRowElement;
}
if (!nextElement) {
return false;
}
range.selectNodeContents(nextElement.cells[getColIndex(cellElement)]);
range.collapse(true);
scrollCenter(protyle);
event.preventDefault();
return true;
}
// Backspace:光标移动到前一个 cell
if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace"
&& getSelectionOffset(cellElement, protyle.wysiwyg.element, range).start === 0 && range.toString() === "" &&
// 空换行无法删除 https://github.com/siyuan-note/siyuan/issues/2732
(range.startOffset === 0 || (range.startOffset === 1 && cellElement.querySelectorAll("br").length === 1))) {
const previousCellElement = goPreviousCell(cellElement, range, false);
if (!previousCellElement && nodeElement.previousElementSibling) {
focusBlock(nodeElement.previousElementSibling, undefined, false);
}
scrollCenter(protyle);
event.preventDefault();
return true;
}
// 居左
if (matchHotKey(window.siyuan.config.keymap.editor.general.alignLeft.custom, event)) {
setTableAlign(protyle, [cellElement], nodeElement, "left", range);
event.preventDefault();
return true;
}
// 居中
if (matchHotKey(window.siyuan.config.keymap.editor.general.alignCenter.custom, event)) {
setTableAlign(protyle, [cellElement], nodeElement, "center", range);
event.preventDefault();
return true;
}
// 居右
if (matchHotKey(window.siyuan.config.keymap.editor.general.alignRight.custom, event)) {
setTableAlign(protyle, [cellElement], nodeElement, "right", range);
event.preventDefault();
return true;
}
const tableElement = nodeElement.querySelector("table");
const hasNone = cellElement.parentElement.querySelector(".fn__none");
let hasColSpan = false;
let hasRowSpan = false;
Array.from(cellElement.parentElement.children).forEach((item: HTMLTableCellElement) => {
if (item.colSpan > 1) {
hasColSpan = true;
}
if (item.rowSpan > 1) {
hasRowSpan = true;
}
});
let previousHasNone: false | Element = false;
let previousHasColSpan = false;
let previousHasRowSpan = false;
let previousRowElement = cellElement.parentElement.previousElementSibling;
if (!previousRowElement && cellElement.parentElement.parentElement.tagName === "TBODY") {
previousRowElement = tableElement.querySelector("thead").lastElementChild;
}
if (previousRowElement) {
previousHasNone = previousRowElement.querySelector(".fn__none");
Array.from(previousRowElement.children).forEach((item: HTMLTableCellElement) => {
if (item.colSpan > 1) {
previousHasColSpan = true;
}
if (item.rowSpan > 1) {
previousHasRowSpan = true;
}
});
}
let nextHasNone: false | Element = false;
let nextHasColSpan = false;
let nextHasRowSpan = false;
let nextRowElement = cellElement.parentElement.nextElementSibling;
if (!nextRowElement && cellElement.parentElement.parentElement.tagName === "THEAD") {
nextRowElement = tableElement.querySelector("tbody")?.firstElementChild;
}
if (nextRowElement) {
nextHasNone = nextRowElement.querySelector(".fn__none");
Array.from(nextRowElement.children).forEach((item: HTMLTableCellElement) => {
if (item.colSpan > 1) {
nextHasColSpan = true;
}
if (item.rowSpan > 1) {
nextHasRowSpan = true;
}
});
}
const colIndex = getColIndex(cellElement);
let colIsPure = true;
Array.from(tableElement.rows).find(item => {
const cellElement = item.cells[colIndex];
if (cellElement.classList.contains("fn__none") || cellElement.colSpan > 1 || cellElement.rowSpan > 1) {
colIsPure = false;
return true;
}
});
let nextColIsPure = true;
Array.from(tableElement.rows).find(item => {
const cellElement = item.cells[colIndex + 1];
if (cellElement && (cellElement.classList.contains("fn__none") || cellElement.colSpan > 1 || cellElement.rowSpan > 1)) {
nextColIsPure = false;
return true;
}
});
let previousColIsPure = true;
Array.from(tableElement.rows).find(item => {
const cellElement = item.cells[colIndex - 1];
if (cellElement && (cellElement.classList.contains("fn__none") || cellElement.colSpan > 1 || cellElement.rowSpan > 1)) {
previousColIsPure = false;
return true;
}
});
if (matchHotKey(window.siyuan.config.keymap.editor.table.moveToUp.custom, event)) {
if ((!hasNone || (hasNone && !hasRowSpan && hasColSpan)) &&
(!previousHasNone || (previousHasNone && !previousHasRowSpan && previousHasColSpan))) {
moveRowToUp(protyle, range, cellElement, nodeElement);
}
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.table.moveToDown.custom, event)) {
if ((!hasNone || (hasNone && !hasRowSpan && hasColSpan)) &&
(!nextHasNone || (nextHasNone && !nextHasRowSpan && nextHasColSpan))) {
moveRowToDown(protyle, range, cellElement, nodeElement);
}
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.table.moveToLeft.custom, event)) {
if (colIsPure && previousColIsPure) {
moveColumnToLeft(protyle, range, cellElement, nodeElement);
}
event.preventDefault();
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.table.moveToRight.custom, event)) {
if (colIsPure && nextColIsPure) {
moveColumnToRight(protyle, range, cellElement, nodeElement);
}
event.preventDefault();
return true;
}
// 上方新添加一行
if (matchHotKey(window.siyuan.config.keymap.editor.table.insertRowAbove.custom, event)) {
insertRowAbove(protyle, range, cellElement, nodeElement);
event.preventDefault();
event.stopPropagation();
return true;
}
// 下方新添加一行 https://github.com/Vanessa219/vditor/issues/46
if (matchHotKey(window.siyuan.config.keymap.editor.table.insertRowBelow.custom, event)) {
if (!nextHasNone || (nextHasNone && !nextHasRowSpan && nextHasColSpan)) {
insertRow(protyle, range, cellElement, nodeElement);
}
event.preventDefault();
return true;
}
// 左方新添加一列
if (matchHotKey(window.siyuan.config.keymap.editor.table.insertColumnLeft.custom, event)) {
if (colIsPure || previousColIsPure) {
insertColumn(protyle, nodeElement, cellElement, "beforebegin", range);
}
event.preventDefault();
return true;
}
// 后方新添加一列
if (matchHotKey(window.siyuan.config.keymap.editor.table.insertColumnRight.custom, event)) {
if (colIsPure || nextColIsPure) {
insertColumn(protyle, nodeElement, cellElement, "afterend", range);
}
event.preventDefault();
return true;
}
// 删除当前行
if (matchHotKey(window.siyuan.config.keymap.editor.table["delete-row"].custom, event)) {
if ((!hasNone && !hasRowSpan) || //https://github.com/siyuan-note/siyuan/issues/5045
(hasNone && !hasRowSpan && hasColSpan)) {
deleteRow(protyle, range, cellElement, nodeElement);
}
event.preventDefault();
event.stopPropagation();
return true;
}
// 删除当前列
if (matchHotKey(window.siyuan.config.keymap.editor.table["delete-column"].custom, event)) {
if (colIsPure) {
deleteColumn(protyle, range, nodeElement, cellElement);
}
event.preventDefault();
return true;
}
};