@syncfusion/ej2-richtexteditor
Version:
Essential JS 2 RichTextEditor component
660 lines (656 loc) • 32 kB
JavaScript
import { closest } from '@syncfusion/ej2-base';
import { getCorrespondingColumns, getCorrespondingIndex, insertColGroupWithSizes } from './../../common/util';
/**
* Handles table pasting operations within the editor
*
* This class provides functionality for pasting table content from one location to another,
* handling complex scenarios such as:
* - Merging and splitting cells
* - Preserving row and column spans
* - Managing cell content and styles
* - Preventing overflow when pasting into selected regions
* - Adjusting table structure to accommodate pasted content
*
* @hidden
*/
var TablePasting = /** @class */ (function () {
function TablePasting() {
this.allCells = [];
this.hasCellsUpdated = false;
this.preventOverflowCells = false;
}
/**
* Handles pasting a table into the target table at the specified cell
*
* This method processes the inserted table and integrates it into the target location,
* handling cell merging, content preservation, and structural adjustments.
* When multiple cells are selected, it ensures proper distribution of content.
*
* @param {HTMLTableElement} insertedTable - The table being pasted
* @param {NodeListOf<Element>} targetCells - Collection of cells where the paste operation targets
* @returns {void}
* @hidden
*/
TablePasting.prototype.handleTablePaste = function (insertedTable, targetCells) {
if (!insertedTable || !targetCells || targetCells.length < 1) {
return;
}
this.hasCellsUpdated = false;
var targetCell = targetCells[0];
this.preventOverflowCells = targetCells.length > 1;
var targetTable = this.getClosestTable(targetCell);
if (!targetTable) {
return;
}
var pastedRows = this.getTableRows(insertedTable);
var startRowIndex = this.getRowIndex(targetCell);
// Fix missing cells in existing rows
this.allCells = getCorrespondingColumns(targetTable);
var startCellIndex = this.getCellIndex(targetCell, startRowIndex);
var pastedTableAllCells = getCorrespondingColumns(insertedTable);
this.pasteMultipleRows(targetTable, pastedRows, startRowIndex, startCellIndex, pastedTableAllCells);
if (this.hasCellsUpdated) {
insertColGroupWithSizes(targetTable, true);
}
};
/* Gets the closest parent table of the given cell */
TablePasting.prototype.getClosestTable = function (cell) {
return closest(cell, 'table');
};
/* Gets all table rows from the given table */
TablePasting.prototype.getTableRows = function (table) {
var rows = [];
var totalRows = table.rows.length;
for (var i = 0; i < totalRows; i++) {
var row = table.rows.item(i);
if (row !== null) {
rows.push(row);
}
}
return rows;
};
/* Gets the row index of a cell */
TablePasting.prototype.getRowIndex = function (cell) {
var row = cell.parentElement;
return row !== null ? row.rowIndex : 0;
};
/* Gets the cell index of a cell */
TablePasting.prototype.getCellIndex = function (selectedCell, startRowIndex) {
if (startRowIndex === void 0) { startRowIndex = 0; }
for (var rowIndex = startRowIndex; rowIndex < this.allCells.length; rowIndex++) {
var row = this.allCells[rowIndex];
for (var colIndex = 0; colIndex < row.length; colIndex++) {
if (this.allCells[rowIndex][colIndex] === selectedCell) {
return colIndex;
}
}
}
return selectedCell.cellIndex >= 0 ? selectedCell.cellIndex : 0;
};
/* Pastes multiple rows into the target table, creating rows/columns if needed */
TablePasting.prototype.pasteMultipleRows = function (targetTable, pastedRows, startRowIndex, startCellIndex, pastedTableAllCells) {
for (var i = 0; i < pastedRows.length; i++) {
var pastedRow = pastedRows[i];
this.pasteRowContent(targetTable, pastedRow, startCellIndex, startRowIndex, pastedTableAllCells);
}
};
/* Ensures the row has at least the required number of cells */
TablePasting.prototype.ensureCellCount = function (row, requiredCellCount, presentCellCount) {
if (presentCellCount < requiredCellCount) {
this.hasCellsUpdated = true;
while (presentCellCount < requiredCellCount) {
var newCell = row.insertCell();
newCell.innerHTML = '<br>';
presentCellCount++;
}
}
};
/* Gets or creates a row at the given index */
TablePasting.prototype.getOrCreateRow = function (table, rowIndex) {
if (rowIndex < table.rows.length) {
return table.rows.item(rowIndex);
}
if (!this.preventOverflowCells) {
var newRow = table.insertRow();
this.fillRowWithEmptyCells(newRow, this.getMaxColumnCount(table.rows[0].cells));
this.allCells = getCorrespondingColumns(table);
return newRow;
}
return null;
};
/* Fills a row with empty cells to match a given column count */
TablePasting.prototype.fillRowWithEmptyCells = function (row, columnCount) {
for (var i = 0; i < columnCount; i++) {
var newCell = row.insertCell();
newCell.innerHTML = '<br>';
}
};
/* Returns the maximum number of columns in the table */
TablePasting.prototype.getMaxColumnCount = function (cellColl) {
var cellCount = 0;
for (var cell = 0; cell < cellColl.length; cell++) {
cellCount += cellColl[cell].colSpan;
}
return cellCount;
};
/* Pastes the content from the pasted row into the target row starting from a specific cell */
TablePasting.prototype.pasteRowContent = function (targetTable, pastedRow, startCellIndex, startRowIndex, pastedTableAllCells) {
var pastedCells = this.getRowCells(pastedRow);
this.allCells = getCorrespondingColumns(targetTable);
if (!this.preventOverflowCells) {
this.ensureTargetTableCapacity(targetTable, startCellIndex, pastedTableAllCells);
}
for (var i = 0; i < pastedCells.length; i++) {
var pastedCell = pastedCells[i];
this.allCells = getCorrespondingColumns(targetTable);
var cellIndex = getCorrespondingIndex(pastedCell, pastedTableAllCells);
var currentTargetRowIndex = startRowIndex + cellIndex[0];
var colIndex = startCellIndex + cellIndex[1];
if (this.preventOverflowCells) {
this.adjustCellSpans(pastedCell, currentTargetRowIndex, colIndex, targetTable);
}
var targetRow = this.getOrCreateRow(targetTable, currentTargetRowIndex);
if (!targetRow) {
continue;
}
var targetCell = this.allCells[currentTargetRowIndex][colIndex];
if (!targetCell || this.shouldSkipCell(targetCell)) {
continue;
}
this.copyCellAttributes(targetCell, pastedCell, currentTargetRowIndex, colIndex, targetTable, targetRow);
}
};
/*
* Adjusts rowspan and colspan attributes of a cell to prevent overflow
*/
TablePasting.prototype.adjustCellSpans = function (cell, rowIndex, colIndex, targetTable) {
var rowSpan = parseInt(cell.getAttribute('rowspan') || '1', 10);
var colSpan = parseInt(cell.getAttribute('colspan') || '1', 10);
// Adjust rowspan if needed
if (rowSpan > 1) {
var adjustedRowSpan = this.calculateAdjustedRowSpan(cell, rowIndex, colIndex, rowSpan, targetTable);
cell.setAttribute('rowspan', adjustedRowSpan.toString());
}
// Adjust colspan if needed
if (colSpan > 1) {
var adjustedColSpan = this.calculateAdjustedColSpan(rowIndex, colIndex, colSpan);
cell.setAttribute('colspan', adjustedColSpan.toString());
}
};
/*
* Calculates the adjusted rowspan value based on available target cells
*/
TablePasting.prototype.calculateAdjustedRowSpan = function (cell, rowIndex, colIndex, originalRowSpan, targetTable) {
var adjustedRowSpan = originalRowSpan;
for (var offset = 1; offset < originalRowSpan; offset++) {
var targetRowIndex = rowIndex + offset;
var targetRow = this.getOrCreateRow(targetTable, targetRowIndex);
if (!targetRow) {
--adjustedRowSpan;
}
else {
var nextTargetCell = this.allCells[targetRowIndex][colIndex];
if (!nextTargetCell || this.shouldSkipCell(nextTargetCell)) {
--adjustedRowSpan;
}
}
}
var rowSpanDifference = originalRowSpan - adjustedRowSpan;
if (rowSpanDifference > 0) {
this.adjustCellHeights(cell, null, adjustedRowSpan, rowSpanDifference);
}
return adjustedRowSpan;
};
/*
* Calculates the adjusted colspan value based on available target cells
*/
TablePasting.prototype.calculateAdjustedColSpan = function (rowIndex, colIndex, originalColSpan) {
var adjustedColSpan = originalColSpan;
for (var colOffset = 0; colOffset < originalColSpan; colOffset++) {
var columnIndex = colIndex + colOffset;
var nextTargetCell = this.allCells[rowIndex][columnIndex];
if (!nextTargetCell || this.shouldSkipCell(nextTargetCell)) {
--adjustedColSpan;
}
}
return adjustedColSpan;
};
/*
* Ensures the target table has enough cells to accommodate the pasted content
*/
TablePasting.prototype.ensureTargetTableCapacity = function (table, startCellIndex, pastedCells) {
if (!pastedCells[0]) {
return;
}
for (var i = 0; i < table.rows.length; i++) {
var row = table.rows[i];
var presentCellCount = this.allCells[i].length;
var requiredCellCount = startCellIndex + pastedCells[0].length;
this.ensureCellCount(row, requiredCellCount, presentCellCount);
}
};
/*
* Determines if a cell should be skipped during paste operation
*/
TablePasting.prototype.shouldSkipCell = function (cell) {
return this.preventOverflowCells &&
!(cell.classList.contains('e-cell-select') &&
cell.classList.contains('e-multi-cells-select'));
};
/* Gets all cells from a row */
TablePasting.prototype.getRowCells = function (row) {
var cells = [];
var totalCells = row.cells.length;
for (var i = 0; i < totalCells; i++) {
var cell = row.cells.item(i);
if (cell !== null) {
cells.push(cell);
}
}
return cells;
};
/*
* Copies the attributes and styles from a source table cell to a target cell,
* handling both rowspan and colspan, and updating the table structure accordingly.
*/
TablePasting.prototype.copyCellAttributes = function (targetCell, sourceCell, rowIndex, targetCellIndex, targetTable, targetRow) {
if (!sourceCell) {
return;
}
// Handle cell insertion location
targetCell = this.handleCellInsertLocation(targetCell, targetRow, rowIndex, targetCellIndex);
// Handle parent element mismatch
targetCell = this.handleInsertRowMismatch(targetCell, targetRow, rowIndex, targetCellIndex, targetTable);
// Get span attributes
var spanAttributes = this.getCellSpanAttributes(targetCell, sourceCell);
// Handle colspan changes
targetCell = this.handleColspanChanges(targetCell, spanAttributes.oldColSpan, spanAttributes.newColSpan, rowIndex, targetCellIndex, targetRow, targetTable);
// Handle rowspan changes
targetCell = this.handleRowspanChanges(targetCell, spanAttributes.oldRowSpan, spanAttributes.newRowSpan, rowIndex, targetCellIndex, targetTable, spanAttributes.newColSpan);
// Apply content and styles
targetCell.innerHTML = sourceCell.innerHTML;
targetCell.style.cssText = sourceCell.style.cssText;
};
/*
* Gets span attributes from cells
*/
TablePasting.prototype.getCellSpanAttributes = function (targetCell, sourceCell) {
return {
oldRowSpan: parseInt(targetCell.getAttribute('rowspan') || '1', 10),
oldColSpan: parseInt(targetCell.getAttribute('colspan') || '1', 10),
newRowSpan: parseInt(sourceCell.getAttribute('rowspan') || '1', 10),
newColSpan: parseInt(sourceCell.getAttribute('colspan') || '1', 10)
};
};
/*
* Handles cell insertion location adjustments
*/
TablePasting.prototype.handleCellInsertLocation = function (targetCell, targetRow, rowIndex, targetCellIndex) {
var cellInsertLocation = this.getInsertionColIndex(targetCellIndex, targetRow, rowIndex);
if (cellInsertLocation < targetCellIndex) {
var currentColSpan = parseInt(targetCell.getAttribute('colspan') || '1', 10);
var newColSpan = currentColSpan - (targetCellIndex - cellInsertLocation);
if (newColSpan > 0) {
var insertAt = cellInsertLocation + 1;
var newCell = targetRow.insertCell(insertAt);
newCell.innerHTML = '<br>'; // fill with empty
newCell.style.cssText = targetCell.style.cssText;
newCell.className = targetCell.className;
targetCell.setAttribute('colspan', (currentColSpan - newColSpan).toString());
this.allCells[rowIndex][targetCellIndex] = newCell;
newCell.setAttribute('colspan', newColSpan.toString());
if (targetCell.hasAttribute('rowspan')) {
newCell.setAttribute('rowspan', targetCell.getAttribute('rowspan'));
}
return newCell;
}
}
return targetCell;
};
/*
* Handles parent element mismatch between cell and row
*/
TablePasting.prototype.handleInsertRowMismatch = function (targetCell, targetRow, rowIndex, targetCellIndex, targetTable) {
if (targetCell.parentElement !== targetRow) {
var rowSpan = parseInt(targetCell.getAttribute('rowspan') || '1', 10);
var targetRowIndex = this.getRowIndex(targetCell);
var remainingRowSpan = rowSpan - (rowIndex - targetRowIndex);
var newRowSpan = rowSpan - remainingRowSpan;
if (rowSpan > 1) {
this.removeRowspanAttributes(targetTable, rowIndex, targetCellIndex);
var newCell = this.allCells[rowIndex][targetCellIndex];
newCell.innerHTML = targetCell.innerHTML;
newCell.style.cssText = targetCell.style.cssText;
newCell.className = targetCell.className;
if (targetCell.hasAttribute('colspan')) {
newCell.setAttribute('colspan', targetCell.getAttribute('colspan'));
}
if (remainingRowSpan === 1) {
newCell.removeAttribute('rowspan');
}
else {
newCell.setAttribute('rowspan', remainingRowSpan.toString());
}
if (newRowSpan > 1) {
targetCell.setAttribute('rowspan', newRowSpan.toString());
}
else {
targetCell.removeAttribute('rowspan');
}
this.adjustCellHeights(targetCell, newCell, newRowSpan, remainingRowSpan);
return newCell;
}
}
return targetCell;
};
/*
* Adjusts cell heights based on rowspan distribution
*/
TablePasting.prototype.adjustCellHeights = function (targetCell, newCell, newRowSpan, remainingRowSpan) {
if (targetCell.style.height) {
var heightStr = targetCell.style.height;
var heightValue = parseFloat(heightStr);
// Check if we got a valid number
if (!isNaN(heightValue) && heightValue > 0) {
var totalRowSpan = newRowSpan + remainingRowSpan;
var height = heightValue / totalRowSpan;
targetCell.style.height = (newRowSpan * height) + 'px';
if (newCell) {
newCell.style.height = (remainingRowSpan * height) + 'px';
}
}
}
};
/*
* Handles rowspan changes between old and new values
*/
TablePasting.prototype.handleRowspanChanges = function (targetCell, oldRowSpan, newRowSpan, rowIndex, targetCellIndex, targetTable, newColSpan) {
// Decrease rowspan to 1
if (oldRowSpan > 1 && newRowSpan <= 1) {
var remainingRowSpan = oldRowSpan - newRowSpan;
var nextRowIndex = rowIndex + 1;
this.removeRowspanAttributes(targetTable, nextRowIndex, targetCellIndex);
var newCell = this.allCells[nextRowIndex][targetCellIndex];
newCell.innerHTML = targetCell.innerHTML;
newCell.style.cssText = targetCell.style.cssText;
newCell.className = targetCell.className;
if (targetCell.hasAttribute('colspan')) {
newCell.setAttribute('colspan', targetCell.getAttribute('colspan'));
}
if (remainingRowSpan === 1) {
newCell.removeAttribute('rowspan');
}
else {
newCell.setAttribute('rowspan', remainingRowSpan.toString());
}
targetCell.removeAttribute('rowspan');
this.adjustCellHeights(targetCell, newCell, newRowSpan, remainingRowSpan);
}
// Both have rowspan > 1
else if (oldRowSpan > 1 && newRowSpan > 1) {
var delta = newRowSpan - oldRowSpan;
if (delta > 0) { // Increase rowspan
this.applyRowspanAttributes(targetTable, rowIndex, targetCellIndex, newRowSpan, newColSpan);
targetCell.setAttribute('rowspan', newRowSpan.toString());
}
else if (delta < 0) { // Decrease rowspan
var nextRowIndex = rowIndex + newRowSpan;
this.removeRowspanAttributes(targetTable, nextRowIndex, targetCellIndex);
var newCell = this.allCells[nextRowIndex][targetCellIndex];
newCell.innerHTML = targetCell.innerHTML;
newCell.style.cssText = targetCell.style.cssText;
newCell.className = targetCell.className;
if (targetCell.hasAttribute('colspan')) {
newCell.setAttribute('colspan', targetCell.getAttribute('colspan'));
}
if (-delta === 1) {
newCell.removeAttribute('rowspan');
}
else {
newCell.setAttribute('rowspan', (-delta).toString());
}
targetCell.setAttribute('rowspan', newRowSpan.toString());
this.adjustCellHeights(targetCell, newCell, newRowSpan, -delta);
}
}
// Increase rowspan from 1
else if (newRowSpan > 1 && oldRowSpan <= 1) {
this.applyRowspanAttributes(targetTable, rowIndex, targetCellIndex, newRowSpan, newColSpan);
targetCell.setAttribute('rowspan', newRowSpan.toString());
}
return targetCell;
};
/*
* Handles colspan changes between old and new values
*/
TablePasting.prototype.handleColspanChanges = function (targetCell, oldColSpan, newColSpan, rowIndex, targetCellIndex, targetRow, targetTable) {
// Decrease colspan to 1
if (oldColSpan > 1 && newColSpan <= 1) {
var targetNewCellSpan = oldColSpan - newColSpan;
this.insertFollowingSiblings(targetRow, targetCellIndex, rowIndex, newColSpan);
if (targetNewCellSpan === 1) {
targetCell.removeAttribute('colspan');
}
else {
targetCell.setAttribute('colspan', targetNewCellSpan.toString());
}
targetCell.innerHTML = '';
var newCell = this.allCells[rowIndex][targetCellIndex];
newCell.className = targetCell.className;
targetCell = newCell;
}
// Increase colspan from 1
else if (newColSpan > 1 && oldColSpan <= 1) {
var deleteCellCount = newColSpan - oldColSpan;
if (deleteCellCount > 0) {
this.removeFollowingSiblings(this.allCells[rowIndex], targetCellIndex + oldColSpan, deleteCellCount, targetTable, targetRow, rowIndex);
targetCell.setAttribute('colspan', newColSpan.toString());
}
}
// Both have colspan > 1
else if (newColSpan > 1 && oldColSpan > 1) {
var colSpanDiff = newColSpan - oldColSpan;
if (colSpanDiff > 0) { // Increase colspan
this.removeFollowingSiblings(this.allCells[rowIndex], targetCellIndex + oldColSpan, colSpanDiff, targetTable, targetRow, rowIndex);
targetCell.setAttribute('colspan', newColSpan.toString());
}
else if (colSpanDiff < 0) { // Decrease colspan
this.insertFollowingSiblings(targetRow, targetCellIndex, rowIndex, 1);
targetCell.setAttribute('colspan', (-colSpanDiff).toString());
targetCell.innerHTML = '';
var newCell = this.allCells[rowIndex][targetCellIndex];
newCell.className = targetCell.className;
targetCell = newCell;
targetCell.setAttribute('colspan', newColSpan.toString());
}
}
return targetCell;
};
/* Applies rowspan logic by removing redundant cells and tracking rowspan spans */
TablePasting.prototype.applyRowspanAttributes = function (targetTable, baseRowIndex, startCellIndex, rowSpan, colSpan) {
for (var offset = 1; offset < rowSpan; offset++) {
var targetRowIndex = baseRowIndex + offset;
for (var colOffset = 0; colOffset < colSpan; colOffset++) {
var columnIndex = startCellIndex + colOffset;
this.processRowspanCell(targetTable, targetRowIndex, columnIndex);
}
}
};
/* Processes a single cell for rowspan application */
TablePasting.prototype.processRowspanCell = function (targetTable, targetRowIndex, columnIndex) {
var targetRow = this.getOrCreateRow(targetTable, targetRowIndex);
var cellToRemove = this.allCells[targetRowIndex][columnIndex];
var index = Array.prototype.indexOf.call(targetRow.cells, cellToRemove);
if (!cellToRemove || !cellToRemove.parentElement || index === -1) {
return;
}
var currentColSpan = parseInt(cellToRemove.getAttribute('colspan') || '1', 10);
var currentRowSpan = parseInt(cellToRemove.getAttribute('rowspan') || '1', 10);
var shouldRemoveCompletely = currentColSpan <= 1 && currentRowSpan <= 1;
if (!shouldRemoveCompletely) {
this.handleComplexCellRemoval(targetTable, targetRow, cellToRemove, targetRowIndex, columnIndex, currentColSpan, currentRowSpan);
}
targetRow.removeChild(cellToRemove);
this.allCells[targetRowIndex][columnIndex] = null;
};
/* Handles removal of cells with colspan or rowspan */
TablePasting.prototype.handleComplexCellRemoval = function (targetTable, targetRow, cellToRemove, targetRowIndex, columnIndex, currentColSpan, currentRowSpan) {
if (currentColSpan > 1) {
this.handleColspanCellRemoval(targetRow, cellToRemove, targetRowIndex, columnIndex, currentColSpan);
}
if (currentRowSpan > 1) {
this.handleRowspanCellRemoval(targetTable, cellToRemove, targetRowIndex, columnIndex, currentRowSpan);
}
};
/* Handles removal of a cell with colspan */
TablePasting.prototype.handleColspanCellRemoval = function (targetRow, cellToRemove, targetRowIndex, columnIndex, currentColSpan) {
this.insertFollowingSiblings(targetRow, columnIndex, targetRowIndex, 1);
var newColSpan = currentColSpan - 1;
var newCell = this.allCells[targetRowIndex][columnIndex];
newCell.innerHTML = '<br>';
newCell.style.cssText = cellToRemove.style.cssText;
newCell.className = cellToRemove.className;
if (newColSpan === 1) {
newCell.removeAttribute('colspan');
}
else {
newCell.setAttribute('colspan', newColSpan.toString());
}
};
/* Handles removal of a cell with rowspan */
TablePasting.prototype.handleRowspanCellRemoval = function (targetTable, cellToRemove, targetRowIndex, columnIndex, currentRowSpan) {
this.removeRowspanAttributes(targetTable, targetRowIndex + 1, columnIndex);
var newCell = this.allCells[targetRowIndex + 1][columnIndex];
var newRowSpan = currentRowSpan - 1;
newCell.innerHTML = cellToRemove.innerHTML;
newCell.style.cssText = cellToRemove.style.cssText;
newCell.className = cellToRemove.className;
if (newRowSpan === 1) {
newCell.removeAttribute('rowspan');
}
else {
newCell.setAttribute('rowspan', newRowSpan.toString());
}
this.adjustCellHeights(cellToRemove, newCell, currentRowSpan, newRowSpan);
};
/* Removes rowspan logic by adding cells to rows that were previously spanned */
TablePasting.prototype.removeRowspanAttributes = function (targetTable, nextRowIndex, targetCellIndex) {
var nextRow = this.getOrCreateRow(targetTable, nextRowIndex);
var insertionColIndex = this.getInsertionColIndex(targetCellIndex, nextRow, nextRowIndex);
var newCell = nextRow.insertCell(insertionColIndex);
this.allCells[nextRowIndex][targetCellIndex] = newCell;
};
/* Retrieves or creates a row at the specified index in the table */
TablePasting.prototype.getInsertionColIndex = function (targetCellIndex, nextRow, rowIndex) {
// Handle empty rows
if (!nextRow || nextRow.cells.length === 0) {
return 0;
}
var insertionColIndex = targetCellIndex;
var rowCells = this.allCells[rowIndex] || [];
// Try to find a matching cell by incrementing the index
insertionColIndex = this.findMatchingCellIndex(rowCells, nextRow, insertionColIndex, true);
var visualStartIndex = rowCells.indexOf(nextRow.cells[0]);
// If no match found or index out of bounds, try decrementing approach
if (rowCells.length <= insertionColIndex ||
(nextRow.cells.length <= targetCellIndex && visualStartIndex !== -1 && visualStartIndex < insertionColIndex)) {
insertionColIndex = targetCellIndex;
insertionColIndex = this.findMatchingCellIndex(rowCells, nextRow, insertionColIndex, false);
}
// Get the actual cell index if a cell was found
if (rowCells[insertionColIndex]) {
var cell = rowCells[insertionColIndex];
insertionColIndex = cell.cellIndex;
// Adjust index for cases where target exceeds available cells
if (nextRow.cells.length <= targetCellIndex && visualStartIndex !== -1 && targetCellIndex > visualStartIndex) {
insertionColIndex++;
}
}
else {
// Fallback to the original target index
insertionColIndex = targetCellIndex;
}
return insertionColIndex;
};
/*
* Finds a matching cell index by incrementing or decrementing from the starting index
*/
TablePasting.prototype.findMatchingCellIndex = function (rowCells, nextRow, startIndex, increment) {
var index = startIndex;
while (rowCells &&
index >= 0 &&
rowCells[index] &&
nextRow &&
Array.prototype.indexOf.call(nextRow.cells, rowCells[index]) === -1) {
index = increment ? index + 1 : index - 1;
}
return index;
};
/* Removes (colSpan - 1) cells following the given cell index in a row */
TablePasting.prototype.removeFollowingSiblings = function (row, deleteCellIndex, colSpan, targetTable, targetRow, targetRowIndex) {
for (var offset = 0; offset < colSpan; offset++) {
var cellToRemove = row[deleteCellIndex];
if (cellToRemove && cellToRemove.parentElement) {
var currentColSpan = parseInt(cellToRemove.getAttribute('colspan') || '1', 10);
var currentRowSpan = parseInt(cellToRemove.getAttribute('rowspan') || '1', 10);
var shouldRemoveCompletely = currentColSpan <= 1 && currentRowSpan <= 1;
if (!shouldRemoveCompletely) {
this.handleComplexCellRemoval(targetTable, targetRow, cellToRemove, targetRowIndex, deleteCellIndex, currentColSpan, currentRowSpan);
}
cellToRemove.parentElement.removeChild(cellToRemove);
row[deleteCellIndex] = null;
}
}
};
TablePasting.prototype.insertFollowingSiblings = function (row, startCellIndex, rowIndex, oldColSpan) {
var cellInsertLocation = this.getInsertionColIndex(startCellIndex, row, rowIndex);
for (var offset = 0; offset < oldColSpan; offset++) {
var newCell = row.insertCell(cellInsertLocation);
newCell.innerHTML = '<br>'; // fill with empty
this.allCells[rowIndex][startCellIndex] = newCell;
}
};
/**
* Retrieves a valid table element from the pasted content if it exists and is valid
*
* This method examines the pasted content to find a table element. It handles three scenarios:
* 1. The inserted node is already a table
* 2. The inserted node contains a table that needs to be extracted
* 3. The inserted node contains a table with wrapper elements that should be preserved
*
* If the content is not a valid table or a valid wrapper around a table, returns null.
*
* @param {HTMLElement} insertedNode - The node that was pasted into the editor
* @returns {HTMLElement | null} - The valid table element or wrapper, or null if no valid table found
* @hidden
*/
TablePasting.prototype.getValidTableFromPaste = function (insertedNode) {
if (insertedNode.nodeName.toLowerCase() === 'table') {
return insertedNode;
}
var tableElement = insertedNode.querySelector('table');
if (!tableElement) {
return null;
}
return this.getWrapperNodeForTable(insertedNode, tableElement);
};
/*
* Retrieves the wrapper node around the table if it is valid (only the table inside a single wrapper element).
* If the wrapper is invalid or contains extra elements, returns null.
*/
TablePasting.prototype.getWrapperNodeForTable = function (container, tableElement) {
var currentNode = container;
while (currentNode !== tableElement) {
var nonCommentChildren = Array.from(currentNode.childNodes)
.filter(function (node) { return node.nodeType !== Node.COMMENT_NODE &&
!(node.nodeType === Node.TEXT_NODE && node.textContent.trim() === ''); });
if (nonCommentChildren.length !== 1) {
return null;
}
currentNode = nonCommentChildren[0];
}
return currentNode;
};
return TablePasting;
}());
export { TablePasting };