@cairn214/fluent-editor
Version:
A rich text editor based on Quill 2.0, which extends rich modules and formats on the basis of Quill. It's powerful and out-of-the-box.
1,040 lines (1,039 loc) • 37.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const Quill = require("quill");
const editor_utils = require("../../config/editor.utils.cjs.js");
const method = require("../../utils/method.cjs.js");
const tableConfig = require("../table-config.cjs.js");
const index = require("../utils/index.cjs.js");
const header = require("./header.cjs.js");
const list = require("./list.cjs.js");
const Break = Quill.imports["blots/break"];
const Block = Quill.imports["blots/block"];
const Container = Quill.imports["blots/container"];
class TableCellLine extends Block {
static create(value) {
const node = super.create(value);
if (value.tdBgColor) {
node.setAttribute(`data-parent-bg`, value.tdBgColor);
delete value.tdBgColor;
}
tableConfig.CELL_IDENTITY_KEYS.forEach((key) => {
const identityMaker = key === "row" ? rowId : cellId;
node.setAttribute(`data-${key}`, value[key] || identityMaker());
});
tableConfig.CELL_ATTRIBUTES.forEach((attrName) => {
const keyValue = value[attrName] || tableConfig.CELL_DEFAULT[attrName];
keyValue && node.setAttribute(`data-${attrName}`, keyValue);
});
if (value.height) {
node.setAttribute("height", value.height);
}
return node;
}
static formats(domNode) {
const formats = {};
if (formats.list) {
formats.list = domNode.classList.item(0);
}
return reduceFormats(domNode, formats);
}
toggleAttribute(name, value) {
if (value) {
this.domNode.setAttribute(name, value);
} else {
this.domNode.removeAttribute(name);
}
}
formatChildren(name, value) {
this.children.forEach((child) => {
child.format && child.format(name, value);
if (!child.domNode.style) {
return;
}
switch (name) {
case "cell-bg":
if (child.domNode.tagName === "SPAN" && value) {
child.domNode.style.backgroundColor = value;
} else {
child.domNode.style.backgroundColor = "initial";
}
break;
case "cell-border-color":
if (child.domNode.tagName === "SPAN" && value) {
child.domNode.style.border = value;
} else {
child.domNode.style.border = "initial";
}
break;
default:
break;
}
});
}
format(name, value) {
if ([...tableConfig.CELL_ATTRIBUTES, ...tableConfig.CELL_IDENTITY_KEYS, "parent-bg"].includes(name)) {
if (value) {
this.domNode.setAttribute(`data-${name}`, value);
} else {
this.domNode.removeAttribute(`data-${name}`);
}
} else if (name === "header") {
if (!value) {
return;
}
const { row, cell, rowspan, colspan } = TableCellLine.formats(this.domNode);
super.format(name, {
value,
row,
cell,
rowspan,
colspan
});
} else {
super.format(name, value);
}
switch (true) {
case name === "cell-bg":
{
this.toggleAttribute("data-cell-bg", value);
if (value) {
this.domNode.style.backgroundColor = value;
} else {
this.domNode.style.backgroundColor = "initial";
}
}
break;
case name === "cell-border-color":
{
this.toggleAttribute("data-cell-border-color", value);
if (value) {
this.domNode.style.border = value;
} else {
this.domNode.style.border = "initial";
}
}
break;
}
}
optimize(context) {
super.optimize(context);
const { row, cell, rowspan, colspan, cellBg } = this.domNode.dataset;
const formats = TableCellLine.formats(this.domNode);
const parentFormats = this.parent.formats();
if (this.statics.requiredContainer && !(this.parent instanceof this.statics.requiredContainer)) {
this.wrap(this.statics.requiredContainer.blotName, { row, cell, rowspan, colspan, cellBg });
} else if (!method.compare(formats, parentFormats)) {
this.parent.format("row", formats.row);
this.parent.format("cell", formats.cell);
this.parent.format("rowspan", formats.rowspan);
this.parent.format("colspan", formats.colspan);
formats["cell-bg"] && this.parent.setCellBg(formats["cell-bg"]);
formats["cell-border-color"] && this.parent.setCellBorderColor(formats["cell-border-color"]);
}
const parentHeight = this.domNode.getAttribute("height");
if (parentHeight) {
this.parent.domNode.style.height = parentHeight;
}
}
tableCell() {
return this.parent;
}
}
TableCellLine.blotName = "table-cell-line";
TableCellLine.className = "qlbt-cell-line";
TableCellLine.tagName = "DIV";
class TableCell extends Container {
static create(value = { row: rowId() }) {
const node = super.create(value);
tableConfig.CELL_IDENTITY_KEYS.forEach((key) => {
node.setAttribute(`data-${key}`, value[key]);
});
tableConfig.CELL_ATTRIBUTES.forEach((attrName) => {
if (value[attrName]) {
node.setAttribute(attrName, value[attrName]);
}
});
return node;
}
static formats(domNode) {
const formats = {
height: void 0,
row: void 0
};
formats.height = domNode.getAttribute("height") || void 0;
if (domNode.hasAttribute("data-row")) {
formats.row = domNode.getAttribute("data-row");
}
if (domNode.hasAttribute("data-cell-bg")) {
formats["cell-bg"] = domNode.getAttribute("data-cell-bg") || void 0;
}
if (domNode.hasAttribute("data-cell-border-color")) {
formats["cell-border-color"] = domNode.getAttribute("data-cell-border-color") || void 0;
}
return tableConfig.CELL_ATTRIBUTES.reduce((formats2, attribute) => {
if (domNode.hasAttribute(attribute)) {
formats2[attribute] = domNode.getAttribute(attribute);
}
return formats2;
}, formats);
}
checkMerge() {
if (super.checkMerge() && !editor_utils.isNullOrUndefined(this.next.children.head)) {
const getCellId = (node) => {
return node.formats && node.formats()[node.statics.blotName] || {
cell: node.domNode.getAttribute("data-cell")
};
};
const thisHead = getCellId(this.children.head);
const thisTail = getCellId(this.children.tail);
const nextHead = getCellId(this.next.children.head);
const nextTail = getCellId(this.next.children.tail);
return thisHead.cell === thisTail.cell && thisHead.cell === nextHead.cell && thisHead.cell === nextTail.cell;
}
return false;
}
cellOffset() {
if (this.parent) {
return this.parent.children.indexOf(this);
}
return -1;
}
formats() {
const formats = {};
if (this.domNode.hasAttribute("data-row")) {
formats.row = this.domNode.getAttribute("data-row");
}
if (this.domNode.hasAttribute("data-cell")) {
formats.cell = this.domNode.getAttribute("data-cell");
}
return tableConfig.CELL_ATTRIBUTES.reduce((tableFormats, attribute) => {
if (this.domNode.hasAttribute(attribute)) {
tableFormats[attribute] = this.domNode.getAttribute(attribute);
}
return tableFormats;
}, formats);
}
toggleAttribute(name, value) {
if (value) {
this.domNode.setAttribute(name, value);
} else {
this.domNode.removeAttribute(name);
}
}
formatChildren(name, value) {
this.children.forEach((child) => {
child.format(name, value);
});
}
/**
* this method is for TableCellLine to change cell background color
* if use `format('cell-bg', value)` will loop trigger
* TableCellLine.optimize -> TableCell.format -> TableCellLine.optimize ...
*/
setCellBg(value) {
if (value) {
this.domNode.style.backgroundColor = value;
} else {
this.domNode.style.backgroundColor = "initial";
}
}
setCellBorderColor(value) {
if (value) {
this.domNode.style.border = value;
const table = this.domNode.closest("table");
const rows = Array.from(table.querySelectorAll("tr"));
const rowIndex = rows.findIndex((row) => row.contains(this.domNode));
const cellIndex = Array.from(rows[rowIndex].children).indexOf(this.domNode);
if (rowIndex > 0) {
const upperCell = rows[rowIndex - 1].children[cellIndex];
if (upperCell) {
upperCell.style.borderBottom = value;
}
}
if (rowIndex < rows.length - 1) {
const lowerCell = rows[rowIndex + 1].children[cellIndex];
if (lowerCell) {
lowerCell.style.borderTop = value;
}
}
if (cellIndex > 0) {
const leftCell = rows[rowIndex].children[cellIndex - 1];
leftCell.style.borderRight = value;
}
if (cellIndex < rows[rowIndex].children.length - 1) {
const rightCell = rows[rowIndex].children[cellIndex + 1];
rightCell.style.borderLeft = value;
}
} else {
this.domNode.style.border = "initial";
}
}
format(name, value) {
const quill = Quill.find(this.scroll.domNode.parentNode);
switch (true) {
case name === "cell-bg": {
this.toggleAttribute("data-cell-bg", value);
this.toggleAttribute("data-parent-bg", value);
this.formatChildren(name, value);
this.setCellBg(value);
break;
}
case name === "cell-border-color": {
this.toggleAttribute("data-cell-border-color", value);
this.setCellBorderColor(value);
break;
}
case tableConfig.CELL_ATTRIBUTES.includes(name):
this.toggleAttribute(name, value);
break;
case ["row", "cell"].includes(name):
this.toggleAttribute(`data-${name}`, value);
break;
case name === "background": {
const hasBgColor = this.domNode.querySelectorAll("div.qlbt-cell-line[data-parent-bg]");
hasBgColor.forEach((child) => child.removeAttribute("data-parent-bg"));
this.domNode.style.background = "";
this.domNode.style.backgroundColor = value;
this.children.head.format("parent-bg", value);
break;
}
case name === "size": {
const start = quill.getIndex(this.children.head);
const total = quill.getIndex(this.children.tail) + this.children.tail.length();
const length = total - start > 0 ? total - start : 0;
quill.setSelection(start, length, Quill.sources.USER);
quill.format(name, value, Quill.sources.USER);
quill.setSelection(start);
break;
}
}
}
optimize(context) {
const hasBg = Array.from(this.domNode.childNodes).find((item) => item.getAttribute("data-parent-bg"));
const bgColor = hasBg && hasBg.getAttribute("data-parent-bg");
if (bgColor && bgColor !== this.domNode.style.backgroundColor) {
this.domNode.style.backgroundColor = bgColor;
}
const rId = this.domNode.getAttribute("data-row");
if (this.statics.requiredContainer && !(this.parent instanceof this.statics.requiredContainer)) {
this.wrap(this.statics.requiredContainer.blotName, {
row: rId
});
} else if (rId !== this.parent.formats().row) {
this.parent.format("row", rId);
}
this.children.forEach((child) => {
if (editor_utils.isNullOrUndefined(child.next)) {
return;
}
const childFormats = this.getFormat(child.domNode);
const nextFormats = this.getFormat(child.next.domNode);
if (childFormats.cell !== nextFormats.cell) {
const next = this.splitAfter(child);
if (next) {
next.optimize();
}
if (this.prev) {
this.prev.optimize();
}
}
});
super.optimize(context);
}
// 兼容读取TableCell中的子blot,包括table-cell-line、line、head
getFormat(domNode) {
const formats = {};
const firstChild = domNode.childNodes[0];
if (firstChild && domNode.tagName === "OL") {
formats.list = firstChild.classList.item(0);
}
return reduceFormats(domNode, formats);
}
row() {
return this.parent;
}
rowOffset() {
if (this.row()) {
return -1;
}
return this.row().rowOffset();
}
table() {
return this.row() && this.row().table();
}
}
TableCell.blotName = "table";
TableCell.tagName = "TD";
class TableRow extends Container {
static create(value) {
const node = super.create(value);
if (value.row) {
node.setAttribute("data-row", value.row);
}
return node;
}
checkMerge() {
if (super.checkMerge() && !editor_utils.isNullOrUndefined(this.next.children.head)) {
const thisHead = this.children.head.formats();
const thisTail = this.children.tail.formats();
const nextHead = this.next.children.head.formats();
const nextTail = this.next.children.tail.formats();
return thisHead.row === thisTail.row && thisHead.row === nextHead.row && thisHead.row === nextTail.row;
}
return false;
}
formats() {
return ["row"].reduce((formats, attrName) => {
if (this.domNode.hasAttribute(`data-${attrName}`)) {
formats[attrName] = this.domNode.getAttribute(`data-${attrName}`);
}
return formats;
}, {});
}
format(key, value) {
this.domNode.setAttribute(`data-${key}`, value);
}
optimize(context) {
if (this.statics.requiredContainer && !(this.parent instanceof this.statics.requiredContainer)) {
this.wrap(this.statics.requiredContainer.blotName);
}
this.children.forEach((child) => {
if (editor_utils.isNullOrUndefined(child.next)) {
return;
}
const childFormats = child.formats();
const nextFormats = child.next.formats();
if (childFormats.row !== nextFormats.row) {
const next = this.splitAfter(child);
if (next) {
next.optimize();
}
if (this.prev) {
this.prev.optimize();
}
}
});
super.optimize(context);
}
rowOffset() {
if (!this.parent) {
return -1;
}
return this.parent.children.indexOf(this);
}
table() {
return this.parent && this.parent.parent;
}
}
TableRow.blotName = "table-row";
TableRow.tagName = "TR";
class TableBody extends Container {
}
TableBody.blotName = "table-body";
TableBody.tagName = "TBODY";
class TableCol extends Block {
static create(value) {
const node = super.create(value);
tableConfig.COL_ATTRIBUTES.forEach((attrName) => {
node.setAttribute(`${attrName}`, value[attrName] || tableConfig.COL_DEFAULT[attrName]);
});
return node;
}
static formats(domNode) {
return tableConfig.COL_ATTRIBUTES.reduce((formats, attribute) => {
if (domNode.hasAttribute(`${attribute}`)) {
formats[attribute] = domNode.getAttribute(`${attribute}`) || void 0;
}
return formats;
}, {});
}
format(name, value) {
if (tableConfig.COL_ATTRIBUTES.includes(name)) {
this.domNode.setAttribute(`${name}`, value || tableConfig.COL_DEFAULT[name]);
} else {
super.format(name, value);
}
}
html() {
return this.domNode.outerHTML;
}
}
TableCol.blotName = "table-col";
TableCol.tagName = "col";
class TableColGroup extends Container {
optimize(context) {
super.optimize(context);
if (this.parent && this.statics.requiredContainer && this.parent instanceof this.statics.requiredContainer) {
this.parent.updateTableWidth();
}
if (this.parent.parent.domNode.className === "quill-better-table-wrapper" && this.parent.parent.domNode.tagName === "DIV" && this.parent.domNode.children.length >= 2 && this.parent.domNode.children[0].tagName === "COLGROUP" && this.parent.domNode.children[1].tagName === "TBODY") {
let trId = "";
let colSpan = 0;
let colgroupNumber = 0;
for (let i = 0; i < this.parent.domNode.children.length; i++) {
if (this.parent.domNode.children[i].tagName === "TBODY") {
if (trId === "") {
trId = this.parent.domNode.children[i].children[0].getAttribute("data-row");
}
colSpan = this.findTdColspanInTbody(this.parent.domNode.children[i], trId);
} else if (this.parent.domNode.children[i].tagName === "COLGROUP") {
colgroupNumber = this.parent.domNode.children[i].children.length;
}
}
let elementSibling = this.parent.domNode.nextElementSibling;
while (elementSibling && elementSibling.tagName === "TABLE") {
for (let i = 0; i < elementSibling.children.length; i++) {
if (elementSibling.children[i].tagName === "TBODY") {
colSpan += this.findTdColspanInTbody(elementSibling.children[i], trId);
}
}
elementSibling = elementSibling.nextElementSibling;
}
if (colgroupNumber < colSpan) {
const length = colSpan - colgroupNumber;
for (let i = 0; i < length; i++) {
const newCol = document.createElement("col");
newCol.width = this.parent.domNode.children[0].children[this.parent.domNode.children[0].children.length - 1].width;
const newBr = document.createElement("br");
newCol.appendChild(newBr);
this.parent.domNode.children[0].appendChild(newCol);
this.parent.domNode.style.width += newCol.width;
}
}
}
}
// this.parent.domNode.children[1].children[0].children[0].colSpan
findTdColspanInTbody(tbody, trId) {
let colSpan = 0;
for (let i = 0; i < tbody.children.length; i++) {
if (tbody.children[i].getAttribute("data-row") !== trId) {
return colSpan;
}
for (let j = 0; j < tbody.children[i].children.length; j++) {
if (tbody.children[i].children[j].colSpan) {
colSpan += tbody.children[i].children[j].colSpan;
}
}
}
return colSpan;
}
}
TableColGroup.blotName = "table-col-group";
TableColGroup.tagName = "colgroup";
class TableContainer extends Container {
static create() {
const node = super.create();
return node;
}
constructor(scroll, domNode) {
super(scroll, domNode);
domNode.setAttribute("contenteditable", false);
this.updateTableWidth();
}
updateTableWidth() {
let colGroup = this.colGroup();
if (!colGroup) {
if (this.parent && this.parent.children.head && this.domNode.hasAttribute("style")) {
colGroup = this.parent.children.head.children.head;
this.domNode = this.parent.children.head.domNode;
} else if (this.domNode.tagName === "TABLE") {
return;
} else {
return;
}
}
const tableWidth = colGroup.children.reduce((sumWidth, col) => {
const tableCol = col.formats()[TableCol.blotName];
let tableColWidth = tableConfig.COL_DEFAULT.width;
if (tableCol && tableCol.width) {
tableColWidth = Number.parseInt(tableCol.width, 10);
}
sumWidth = sumWidth + tableColWidth;
return sumWidth;
}, 0);
this.domNode.removeAttribute("style");
this.domNode.style.width = `${tableWidth}px`;
if (colGroup.next) {
setTimeout(() => {
let tdIndex = 0;
let maxTds;
const colNum = colGroup.children.length;
const tableRows = this.descendants(TableRow);
for (let i = 0; i < tableRows.length; i++) {
const tds = tableRows[i].domNode.querySelectorAll("td");
if (tds.length === colNum) {
maxTds = tds;
break;
}
}
colGroup.children.forEach((col) => {
if (maxTds && col.domNode.width === "auto") {
const width = getComputedStyle(maxTds[tdIndex]).width;
const num = Number.parseInt(width, 10);
col.domNode.width = num < tableConfig.COL_DEFAULT.width && tableConfig.COL_DEFAULT.width || num;
}
tdIndex++;
});
});
}
}
cells(column) {
return this.rows().map((row) => row.children.at(column));
}
colGroup() {
return this.children.head;
}
deleteColumns(compareRect, delIndexes = [], editorWrapper) {
const [body] = this.descendants(TableBody);
if (editor_utils.isNullOrUndefined(body) || editor_utils.isNullOrUndefined(body.children.head)) {
return;
}
const tableCells = this.descendants(TableCell);
const removedCells = [];
const modifiedCells = [];
tableCells.forEach((cell) => {
const cellRect = index.getRelativeRect(cell.domNode.getBoundingClientRect(), editorWrapper);
if (cellRect.x + tableConfig.ERROR_LIMIT > compareRect.x && cellRect.x1 - tableConfig.ERROR_LIMIT < compareRect.x1) {
removedCells.push(cell);
} else if (cellRect.x < compareRect.x + tableConfig.ERROR_LIMIT && cellRect.x1 > compareRect.x1 - tableConfig.ERROR_LIMIT) {
modifiedCells.push(cell);
}
});
if (removedCells.length === tableCells.length) {
this.tableDestroy();
return true;
}
delIndexes.forEach(() => {
const col = this.colGroup().children.at(delIndexes[0]);
if (!col || this.colGroup().children.at(delIndexes[0]).domNode !== this.colGroup().domNode.children[delIndexes[0]]) {
this.colGroup().domNode.removeChild(this.colGroup().domNode.children[delIndexes[0]]);
} else {
col.remove();
}
});
removedCells.forEach((cell) => {
cell.remove();
});
modifiedCells.forEach((cell) => {
const cellColspan = Number.parseInt(cell.formats().colspan, 10);
cell.format("colspan", cellColspan - delIndexes.length);
});
this.updateTableWidth();
}
deleteRow(compareRect, editorWrapper) {
const [body] = this.descendants(TableBody);
if (editor_utils.isNullOrUndefined(body) || editor_utils.isNullOrUndefined(body.children.head)) {
return;
}
const tableCells = this.descendants(TableCell);
const tableRows = this.descendants(TableRow);
const removedCells = [];
const modifiedCells = [];
const fallCells = [];
tableCells.forEach((cell) => {
const cellRect = index.getRelativeRect(cell.domNode.getBoundingClientRect(), editorWrapper);
if (cellRect.y > compareRect.y - tableConfig.ERROR_LIMIT && cellRect.y1 < compareRect.y1 + tableConfig.ERROR_LIMIT) {
removedCells.push(cell);
} else if (cellRect.y < compareRect.y + tableConfig.ERROR_LIMIT && cellRect.y1 > compareRect.y1 - tableConfig.ERROR_LIMIT) {
modifiedCells.push(cell);
if (Math.abs(cellRect.y - compareRect.y) < tableConfig.ERROR_LIMIT) {
fallCells.push(cell);
}
}
});
if (removedCells.length === tableCells.length) {
this.tableDestroy();
return;
}
const removedRowsLength = this.rows().reduce((sum, row) => {
const rowRect = index.getRelativeRect(row.domNode.getBoundingClientRect(), editorWrapper);
if (rowRect.y > compareRect.y - tableConfig.ERROR_LIMIT && rowRect.y1 < compareRect.y1 + tableConfig.ERROR_LIMIT) {
sum += 1;
}
return sum;
}, 0);
fallCells.forEach((cell) => {
const cellRect = index.getRelativeRect(cell.domNode.getBoundingClientRect(), editorWrapper);
const nextRow = cell.parent.next;
const cellsInNextRow = nextRow.children;
const refCell = cellsInNextRow.reduce((ref, compareCell) => {
const compareCellRect = index.getRelativeRect(compareCell.domNode.getBoundingClientRect(), editorWrapper);
if (cellRect.x1 - compareCellRect.x < tableConfig.ERROR_LIMIT) {
ref = compareCell;
}
return ref;
}, null);
nextRow.insertBefore(cell, refCell);
const curRowId = nextRow.formats().row;
cell.format("row", curRowId);
cell.children.forEach((cellLine) => {
cellLine.format("row", curRowId);
});
});
modifiedCells.forEach((cell) => {
const cellRowspan = Number.parseInt(cell.formats().rowspan, 10);
const curRowspan = cellRowspan - removedRowsLength;
cell.domNode.removeAttribute("style");
cell.format("rowspan", curRowspan);
cell.children.forEach((cellLine) => {
cellLine.format("rowspan", curRowspan);
});
});
removedCells.forEach((cell) => {
cell.remove();
});
tableRows.forEach((row) => {
if (row.children.length === 0) {
row.remove();
}
});
}
tableDestroy() {
const quill = Quill.find(this.scroll.domNode.parentNode);
const tableModule = quill.getModule("better-table");
this.remove();
tableModule.hideTableTools();
quill.update(Quill.sources.USER);
}
insertCell(tableRow, ref, bg = "") {
const id = cellId();
const rId = tableRow.formats().row;
const tableCell = this.scroll.create(
TableCell.blotName,
{ ...tableConfig.CELL_DEFAULT, row: rId }
);
tableCell.domNode.style.backgroundColor = bg;
const cellLine = this.scroll.create(TableCellLine.blotName, {
row: rId,
cell: id
});
tableCell.appendChild(cellLine);
if (ref) {
tableRow.insertBefore(tableCell, ref);
} else {
tableRow.appendChild(tableCell);
}
}
insertColumn(compareRect, colIndex, isRight = true, editorWrapper) {
const [body] = this.descendants(TableBody);
const [tableColGroup] = this.descendants(TableColGroup);
const tableCols = this.descendants(TableCol);
const addAsideCells = [];
const modifiedCells = [];
const affectedCells = [];
if (editor_utils.isNullOrUndefined(body) || editor_utils.isNullOrUndefined(body.children.head)) {
return;
}
const tableCells = this.descendants(TableCell);
tableCells.forEach((cell) => {
const cellRect = index.getRelativeRect(cell.domNode.getBoundingClientRect(), editorWrapper);
if (isRight) {
if (Math.abs(cellRect.x1 - compareRect.x1) < tableConfig.ERROR_LIMIT) {
addAsideCells.push(cell);
} else if (compareRect.x1 - cellRect.x > tableConfig.ERROR_LIMIT && compareRect.x1 - cellRect.x1 < -tableConfig.ERROR_LIMIT) {
modifiedCells.push(cell);
}
} else {
if (Math.abs(cellRect.x - compareRect.x) < tableConfig.ERROR_LIMIT) {
addAsideCells.push(cell);
} else if (compareRect.x - cellRect.x > tableConfig.ERROR_LIMIT && compareRect.x - cellRect.x1 < -tableConfig.ERROR_LIMIT) {
modifiedCells.push(cell);
}
}
});
addAsideCells.forEach((cell) => {
const ref = isRight ? cell.next : cell;
const id = cellId();
const tableRow = cell.parent;
const rId = tableRow.formats().row;
const cellFormats = cell.formats();
const tableCell = this.scroll.create(
TableCell.blotName,
{ ...tableConfig.CELL_DEFAULT, row: rId, rowspan: cellFormats.rowspan }
);
const cellLine = this.scroll.create(TableCellLine.blotName, {
row: rId,
cell: id,
rowspan: cellFormats.rowspan
});
tableCell.appendChild(cellLine);
if (ref) {
tableRow.insertBefore(tableCell, ref);
} else {
tableRow.appendChild(tableCell);
}
affectedCells.push(tableCell);
});
const tableCol = this.scroll.create(TableCol.blotName, true);
let colRef;
if (isRight) {
colRef = tableCols[colIndex] && tableCols[colIndex].next;
} else {
colRef = tableCols[colIndex];
}
if (colRef) {
tableColGroup.insertBefore(tableCol, colRef);
} else {
tableColGroup.appendChild(tableCol);
}
modifiedCells.forEach((cell) => {
const cellColspan = cell.formats().colspan;
cell.format("colspan", Number.parseInt(cellColspan, 10) + 1);
affectedCells.push(cell);
});
affectedCells.sort((cellA, cellB) => {
const y1 = cellA.domNode.getBoundingClientRect().y;
const y2 = cellB.domNode.getBoundingClientRect().y;
return y1 - y2;
});
this.updateTableWidth();
return affectedCells;
}
insertRow(compareRect, isDown, editorWrapper) {
const [body] = this.descendants(TableBody);
if (editor_utils.isNullOrUndefined(body) || editor_utils.isNullOrUndefined(body.children.head)) {
return;
}
const tableCells = this.descendants(TableCell);
const rId = rowId();
const newRow = this.scroll.create(TableRow.blotName, {
row: rId
});
const addBelowCells = [];
const modifiedCells = [];
const affectedCells = [];
tableCells.forEach((cell) => {
const cellRect = index.getRelativeRect(cell.domNode.getBoundingClientRect(), editorWrapper);
if (isDown) {
if (Math.abs(cellRect.y1 - compareRect.y1) < tableConfig.ERROR_LIMIT) {
addBelowCells.push(cell);
} else if (compareRect.y1 - cellRect.y > tableConfig.ERROR_LIMIT && compareRect.y1 - cellRect.y1 < -tableConfig.ERROR_LIMIT) {
modifiedCells.push(cell);
}
} else {
if (Math.abs(cellRect.y - compareRect.y) < tableConfig.ERROR_LIMIT) {
addBelowCells.push(cell);
} else if (compareRect.y - cellRect.y > tableConfig.ERROR_LIMIT && compareRect.y - cellRect.y1 < -tableConfig.ERROR_LIMIT) {
modifiedCells.push(cell);
}
}
});
const sortFunc = (cellA, cellB) => {
const x1 = cellA.domNode.getBoundingClientRect().x;
const x2 = cellB.domNode.getBoundingClientRect().x;
return x1 - x2;
};
addBelowCells.sort(sortFunc);
addBelowCells.forEach((cell) => {
const cId = cellId();
const cellFormats = cell.formats();
const tableCell = this.scroll.create(
TableCell.blotName,
{ ...tableConfig.CELL_DEFAULT, row: rId, cell: cId, colspan: cellFormats.colspan }
);
const cellLine = this.scroll.create(TableCellLine.blotName, {
row: rId,
cell: cId,
colspan: cellFormats.colspan
});
const empty = this.scroll.create(Break.blotName);
cellLine.appendChild(empty);
tableCell.appendChild(cellLine);
newRow.appendChild(tableCell);
affectedCells.push(tableCell);
});
modifiedCells.forEach((cell) => {
const cellRowspan = Number.parseInt(cell.formats().rowspan, 10);
cell.format("rowspan", cellRowspan + 1);
affectedCells.push(cell);
});
const refRow = this.rows().find((row) => {
const rowRect = index.getRelativeRect(row.domNode.getBoundingClientRect(), editorWrapper);
if (isDown) {
return Math.abs(rowRect.y - compareRect.y - compareRect.height) < tableConfig.ERROR_LIMIT;
} else {
return Math.abs(rowRect.y - compareRect.y) < tableConfig.ERROR_LIMIT;
}
});
body.insertBefore(newRow, refRow);
affectedCells.sort(sortFunc);
return affectedCells;
}
mergeCells(_compareRect, mergingCells, rowspan, colspan, _editorWrapper) {
const mergedCell = mergingCells.reduce((result, tableCell, index2) => {
if (index2 !== 0) {
if (result) {
tableCell.moveChildren(result);
}
tableCell.remove();
} else {
tableCell.format("colspan", colspan);
tableCell.format("rowspan", rowspan);
result = tableCell;
if (rowspan > 1) {
const minHeight = tableConfig.CELL_MIN_HEIGHT * rowspan + rowspan - 1;
const cellHeight = Number.parseInt(tableCell.domNode.style.height, 10) || 0;
if (cellHeight < minHeight) {
tableCell.domNode.style.height = `${minHeight}px`;
}
}
}
return result;
}, null);
const rId = mergedCell.domNode.getAttribute("data-row");
const cId = mergedCell.children.head.domNode.getAttribute("data-cell");
mergedCell.children.forEach((cellLine) => {
cellLine.domNode.setAttribute("data-parent-bg", mergedCell.domNode.style.backgroundColor);
if (cellLine.children.head.domNode.style) {
cellLine.children.head.domNode.style.backgroundColor = mergedCell.domNode.style.backgroundColor;
}
if (!cellLine.prev || cellLine.domNode.textContent.trim()) {
cellLine.format("cell", cId);
cellLine.format("row", rId);
cellLine.format("colspan", colspan);
cellLine.format("rowspan", rowspan);
} else {
cellLine.remove();
}
});
return mergedCell;
}
unmergeCells(unmergingCells, editorWrapper) {
let cellFormats = {};
let cellRowspan = 1;
let cellColspan = 1;
unmergingCells.forEach((tableCell) => {
const tableCellBgColor = tableCell.domNode.style.backgroundColor;
cellFormats = tableCell.formats();
cellRowspan = cellFormats.rowspan;
cellColspan = cellFormats.colspan;
if (cellColspan > 1) {
const ref = tableCell.next;
const row = tableCell.row();
tableCell.format("colspan", 1);
if (tableCell.domNode.children && tableCell.domNode.children[0].tagName === "DIV" && tableCell.domNode.children[0].getAttribute("data-colspan")) {
tableCell.domNode.children[0].setAttribute("data-colspan", 1);
}
for (let colspanIndex = cellColspan; colspanIndex > 1; colspanIndex--) {
this.insertCell(row, ref, tableCellBgColor);
}
}
if (cellRowspan > 1) {
let rowspanIndex = cellRowspan;
let nextRow = tableCell.row().next;
while (rowspanIndex > 1) {
const refInNextRow = nextRow.children.reduce((result, cell) => {
const compareRect = index.getRelativeRect(tableCell.domNode.getBoundingClientRect(), editorWrapper);
const cellRect = index.getRelativeRect(cell.domNode.getBoundingClientRect(), editorWrapper);
if (Math.abs(compareRect.x1 - cellRect.x) < tableConfig.ERROR_LIMIT) {
result = cell;
}
return result;
}, null);
for (let colspanIndex = cellColspan; colspanIndex > 0; colspanIndex--) {
this.insertCell(nextRow, refInNextRow, tableCellBgColor);
}
rowspanIndex -= 1;
nextRow = nextRow.next;
}
tableCell.domNode.removeAttribute("style");
if (tableCell.domNode.children && tableCell.domNode.children[0].tagName === "DIV" && tableCell.domNode.children[0].getAttribute("data-rowspan")) {
tableCell.domNode.children[0].setAttribute("data-rowspan", 1);
}
tableCell.format("rowspan", 1);
}
});
}
emptyCells(selectedTds) {
selectedTds.forEach((selectedTd) => {
const cellFormats = selectedTd.formats();
const cellLine = this.scroll.create(TableCellLine.blotName, {
row: cellFormats.row || rowId(),
cell: cellFormats.cell || cellId(),
rowspan: cellFormats.rowspan,
colspan: cellFormats.colspan
});
const empty = this.scroll.create(Break.blotName);
cellLine.appendChild(empty);
selectedTd.domNode.innerHTML = "";
selectedTd.appendChild(cellLine);
});
}
rows() {
const body = this.children.tail;
if (editor_utils.isNullOrUndefined(body)) {
return [];
}
return body.children.map((row) => row);
}
}
TableContainer.blotName = "ql-table-container";
TableContainer.className = "quill-better-table";
TableContainer.tagName = "TABLE";
class TableViewWrapper extends Container {
constructor(scroll, domNode) {
super(scroll, domNode);
const quill = Quill.find(scroll.domNode.parentNode);
if (quill.options.readOnly) {
domNode.style.overflow = "auto";
}
domNode.addEventListener(
"scroll",
(e) => {
const tableModule = quill.getModule("better-table");
if (tableModule.columnTool) {
tableModule.columnTool.domNode.scrollLeft = e.target.scrollLeft;
}
if (tableModule.tableSelection && tableModule.tableSelection.selectedTds.length > 0) {
tableModule.tableSelection.repositionHelpLines();
}
},
false
);
}
}
TableViewWrapper.blotName = "table-view";
TableViewWrapper.className = "quill-better-table-wrapper";
TableViewWrapper.tagName = "DIV";
TableViewWrapper.allowedChildren = [TableContainer];
TableContainer.requiredContainer = TableViewWrapper;
TableContainer.allowedChildren = [TableBody, TableColGroup];
TableBody.requiredContainer = TableContainer;
TableBody.allowedChildren = [TableRow];
TableRow.requiredContainer = TableBody;
TableRow.allowedChildren = [TableCell];
TableCell.requiredContainer = TableRow;
TableCell.allowedChildren = [TableCellLine, header.default, list.default, list.ListContainer];
TableCellLine.requiredContainer = TableCell;
TableColGroup.allowedChildren = [TableCol];
TableColGroup.requiredContainer = TableContainer;
TableCol.requiredContainer = TableColGroup;
function rowId() {
const id = Math.random().toString(36).slice(2, 6);
return `row-${id}`;
}
function cellId() {
const id = Math.random().toString(36).slice(2, 6);
return `cell-${id}`;
}
function reduceFormats(domNode, formats) {
return [...tableConfig.CELL_ATTRIBUTES, ...tableConfig.CELL_IDENTITY_KEYS].reduce((tableFormats, attribute) => {
if (domNode.hasAttribute(`data-${attribute}`)) {
tableFormats[attribute] = domNode.getAttribute(`data-${attribute}`) || void 0;
}
return tableFormats;
}, formats);
}
exports.CELL_ATTRIBUTES = tableConfig.CELL_ATTRIBUTES;
exports.CELL_IDENTITY_KEYS = tableConfig.CELL_IDENTITY_KEYS;
exports.TableBody = TableBody;
exports.TableCell = TableCell;
exports.TableCellLine = TableCellLine;
exports.TableCol = TableCol;
exports.TableColGroup = TableColGroup;
exports.TableContainer = TableContainer;
exports.TableRow = TableRow;
exports.TableViewWrapper = TableViewWrapper;
exports.cellId = cellId;
exports.rowId = rowId;
//# sourceMappingURL=table.cjs.js.map