@atlaskit/adf-schema
Version:
Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs
257 lines (252 loc) • 6.82 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import { hasMergedColumns } from '../table-map';
function mergedRanges(first, second) {
const newRanges = [];
const firstLength = first.length;
const secondLength = second.length;
let i = 0;
let j = 0;
while (i < firstLength && j < secondLength) {
if (first[i] < second[j]) {
newRanges.push(first[i], first[i + 1], first[i + 2]);
i += 3;
} else {
newRanges.push(second[j], second[j + 1], second[j + 2]);
j += 3;
}
}
if (i < firstLength) {
newRanges.push(...first.slice(i));
}
if (j < secondLength) {
newRanges.push(...second.slice(i));
}
return newRanges;
}
function increaseRowSpan(tr, rect, row) {
const {
map,
tableStart
} = rect;
for (let col = 0; col < map.width; col++) {
let index = row * map.width + col;
let pos = map.map[index];
const mappedPos = tr.mapping.map(pos + tableStart);
let attrs = tr.doc.nodeAt(mappedPos).attrs;
tr.setNodeMarkup(mappedPos, undefined, {
...attrs,
rowspan: attrs.rowspan + 1
});
col += attrs.colspan - 1;
}
}
function decreaseRowspan(tr, rect, row, colToRemove) {
let skipRows = 0;
const {
map,
table,
tableStart
} = rect;
for (let col = 0; col < map.width; col++) {
let index = row * map.width + col;
let pos = map.map[index];
if (row > 0 && pos === map.map[index - map.width]) {
// If this cell starts in the row above, simply reduce its rowspan
const mappedPos = tr.mapping.map(pos + tableStart);
let attrs = tr.doc.nodeAt(mappedPos).attrs;
tr.setNodeMarkup(mappedPos, undefined, {
...attrs,
rowspan: attrs.rowspan - 1
});
col += attrs.colspan - 1;
} else if (col === colToRemove) {
skipRows = table.nodeAt(pos).attrs.rowspan - 1;
}
}
return skipRows;
}
function isLastCellInRow(rect, row, col) {
const rowNode = rect.table.child(row);
if (!rowNode) {
return false;
}
return rowNode.childCount === 1 && !hasMergedColumns(rect.map, row, col);
}
function removeRowWithLastCell(tr, rect, row, _col) {
// Get row pos
let from = rect.tableStart;
for (let i = 0; i < row; i++) {
from += rect.table.child(i).nodeSize;
}
const rowNode = rect.table.child(row);
let to = from + rowNode.nodeSize;
// Create sideEffect and delete the row
// We store original row position before modifications
tr.delete(tr.mapping.map(from), tr.mapping.map(to));
// Change rowspan of all cells except current col and get the rows to skip
const skipRows = decreaseRowspan(tr, rect, row, _col);
return {
skipRows,
row: {
from,
to,
rowNode: rowNode.copy(rowNode.content)
}
};
}
function addRow(tr, rect, prevRow, rowSideEffect) {
const cellNode = rowSideEffect.rowNode.child(0);
tr.insert(tr.mapping.map(rowSideEffect.from), rowSideEffect.rowNode);
increaseRowSpan(tr, rect, prevRow);
return cellNode.attrs.rowspan - 1;
}
export class RowsSideEffectHandler {
constructor(rowsSideEffect) {
_defineProperty(this, "deleteHandler", () => {
const newRows = [];
return {
handle: (tr, rect, row, col, cell) => {
if (!isLastCellInRow(rect, row, col)) {
return {
handled: false
};
}
const {
row: rowSideEffect,
skipRows
} = removeRowWithLastCell(tr, rect, row, col);
newRows.push(rowSideEffect);
return {
handled: true,
skipRows: skipRows
};
},
end: () => {
if (newRows.length > 0) {
this.rows = newRows;
} else {
this.rows = undefined;
}
}
};
});
_defineProperty(this, "addHandler", () => {
let lastCellFrom = 0;
let i = 0;
return {
handle: (tr, rect, row, col, cell) => {
// // If not sideEffects stored return;
if (!this.rows || i >= this.rows.length) {
return {
handled: false
};
}
// Next row to add;
let skipRows;
let nextRow;
while ((nextRow = this.rows[i]) && nextRow.from > lastCellFrom && nextRow.from < cell.from) {
// I am in between of the previous and next row in the table;
skipRows = addRow(tr, rect, row - 1, nextRow);
i++;
}
lastCellFrom = cell.from;
if (!skipRows || skipRows === 0) {
return {
handled: false
};
}
return {
handled: true,
skipRows: skipRows - 1
};
},
end: (tr, rect, col) => {
if (!this.rows || i >= this.rows.length) {
return;
}
// Add rows at the end of the table
let nextRow;
while (nextRow = this.rows[i]) {
addRow(tr, rect, rect.map.height - 1, nextRow);
i++;
}
}
};
});
this.rows = rowsSideEffect;
}
start(isDelete) {
if (isDelete) {
return this.deleteHandler();
}
return this.addHandler();
}
addRowRanges(ranges, isDelete) {
if (!this.rows) {
return ranges;
}
const rowRanges = [];
for (const row of this.rows) {
const {
from,
to
} = row;
if (isDelete) {
rowRanges.push(from, to - from, 0);
} else {
rowRanges.push(from, 0, to - from);
}
}
// Merged ranges
return mergedRanges(ranges, rowRanges);
}
map(mapping) {
return [];
}
invert(originalDoc, isDelete, map) {
if (!this.rows) {
return;
}
const invertedRows = [];
for (const row of this.rows) {
if (isDelete) {
// Moving from delete to add keep the inverted rows + offset
let offset = map.map(row.from) - row.from;
invertedRows.push({
...row,
from: row.from + offset,
to: row.from + offset
});
} else {
// Moving from add to delete keep
// TODO: I think we need to add the respective cell into the cellSteps...... not sure....
}
}
return invertedRows;
}
toJSON() {
if (!this.rows) {
return;
}
const rowsInJson = [];
for (const row of this.rows) {
rowsInJson.push({
from: row.from,
to: row.to,
rowNode: row.rowNode.toJSON()
});
}
return rowsInJson;
}
static fromJSON(schema, json) {
const rowSideEffects = [];
for (const row of json) {
rowSideEffects.push({
from: row.from,
to: row.to,
rowNode: schema.nodeFromJSON(row.rowNode)
});
}
return rowSideEffects;
}
}