import { Schema, Node, Slice, Fragment, NodeType } from 'prosemirror-model';
import { isFromMso, convertMsoParagraphsToList } from '@/wysiwyg/clipboard/pasteMsoList';
import { getTableContentFromSlice } from '@/wysiwyg/helper/table';
import { ALTERNATIVE_TAG_FOR_BR } from '@/utils/constants';
const START_FRAGMENT_COMMENT = '';
const END_FRAGMENT_COMMENT = '';
function getContentBetweenFragmentComments(html: string) {
const startFragmentIndex = html.indexOf(START_FRAGMENT_COMMENT);
const endFragmentIndex = html.lastIndexOf(END_FRAGMENT_COMMENT);
if (startFragmentIndex > -1 && endFragmentIndex > -1) {
html = html.slice(startFragmentIndex + START_FRAGMENT_COMMENT.length, endFragmentIndex);
}
return html.replace(/
]*>/g, ALTERNATIVE_TAG_FOR_BR);
}
function convertMsoTableToCompletedTable(html: string) {
// wrap with
if html contains dangling | tags
// dangling | tag is that tag does not have |
as parent node
if (/<\/td>((?!<\/tr>)[\s\S])*$/i.test(html)) {
html = `
${html}
`;
}
// wrap with if html contains dangling tags
// dangling
tag is that tag does not have as parent node
if (/<\/tr>((?!<\/table>)[\s\S])*$/i.test(html)) {
html = ``;
}
return html;
}
export function changePastedHTML(html: string) {
html = getContentBetweenFragmentComments(html);
html = convertMsoTableToCompletedTable(html);
if (isFromMso(html)) {
html = convertMsoParagraphsToList(html);
}
return html;
}
function getMaxColumnCount(rows: Node[]) {
const row = rows.reduce((prevRow, currentRow) =>
prevRow.childCount > currentRow.childCount ? prevRow : currentRow
);
return row.childCount;
}
function createCells(orgRow: Node, maxColumnCount: number, cell: NodeType) {
const cells = [];
const cellCount = orgRow.childCount;
for (let colIdx = 0; colIdx < cellCount; colIdx += 1) {
if (!orgRow.child(colIdx).attrs.extended) {
const copiedCell =
colIdx < cellCount
? cell.create(orgRow.child(colIdx).attrs, orgRow.child(colIdx).content)
: cell.createAndFill()!;
cells.push(copiedCell);
}
}
return cells;
}
export function copyTableHeadRow(orgRow: Node, maxColumnCount: number, schema: Schema) {
const { tableRow, tableHeadCell } = schema.nodes;
const cells = createCells(orgRow, maxColumnCount, tableHeadCell);
return tableRow.create(null, cells);
}
export function copyTableBodyRow(orgRow: Node, maxColumnCount: number, schema: Schema) {
const { tableRow, tableBodyCell } = schema.nodes;
const cells = createCells(orgRow, maxColumnCount, tableBodyCell);
return tableRow.create(null, cells);
}
function creatTableBodyDummyRow(columnCount: number, schema: Schema) {
const { tableRow, tableBodyCell } = schema.nodes;
const cells = [];
for (let columnIndex = 0; columnIndex < columnCount; columnIndex += 1) {
const dummyCell = tableBodyCell.createAndFill()!;
cells.push(dummyCell);
}
return tableRow.create({ dummyRowForPasting: true }, cells);
}
export function createRowsFromPastingTable(tableContent: Fragment) {
const tableHeadRows: Node[] = [];
const tableBodyRows: Node[] = [];
if (tableContent.firstChild!.type.name === 'tableHead') {
const tableHead = tableContent.firstChild!;
tableHead.forEach((row) => tableHeadRows.push(row));
}
if (tableContent.lastChild!.type.name === 'tableBody') {
const tableBody = tableContent.lastChild!;
tableBody.forEach((row) => tableBodyRows.push(row));
}
return [...tableHeadRows, ...tableBodyRows];
}
function createTableHead(tableHeadRow: Node, maxColumnCount: number, schema: Schema) {
const copiedRow = copyTableHeadRow(tableHeadRow, maxColumnCount, schema);
return schema.nodes.tableHead.create(null, copiedRow);
}
function createTableBody(tableBodyRows: Node[], maxColumnCount: number, schema: Schema) {
const copiedRows = tableBodyRows.map((tableBodyRow) =>
copyTableBodyRow(tableBodyRow, maxColumnCount, schema)
);
if (!tableBodyRows.length) {
const dummyTableRow = creatTableBodyDummyRow(maxColumnCount, schema);
copiedRows.push(dummyTableRow);
}
return schema.nodes.tableBody.create(null, copiedRows);
}
function createTableFromPastingTable(
rows: Node[],
schema: Schema,
startFromBody: boolean,
isInTable: boolean
) {
const columnCount = getMaxColumnCount(rows);
if (startFromBody && isInTable) {
return schema.nodes.table.create(null, [createTableBody(rows, columnCount, schema)]);
}
const [tableHeadRow] = rows;
const tableBodyRows = rows.slice(1);
const nodes = [createTableHead(tableHeadRow, columnCount, schema)];
if (tableBodyRows.length) {
nodes.push(createTableBody(tableBodyRows, columnCount, schema));
}
return schema.nodes.table.create(null, nodes);
}
export function changePastedSlice(slice: Slice, schema: Schema, isInTable: boolean) {
const nodes: Node[] = [];
const { content, openStart, openEnd } = slice;
content.forEach((node) => {
if (node.type.name === 'table') {
const tableContent = getTableContentFromSlice(new Slice(Fragment.from(node), 0, 0));
if (tableContent) {
const rows = createRowsFromPastingTable(tableContent);
const startFromBody = tableContent.firstChild!.type.name === 'tableBody';
const table = createTableFromPastingTable(rows, schema, startFromBody, isInTable);
nodes.push(table);
}
} else {
nodes.push(node);
}
});
return new Slice(Fragment.from(nodes), openStart, openEnd);
}