@atlaskit/adf-schema
Version:
Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs
381 lines (365 loc) • 18 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AddColumnStep = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _prosemirrorTransform = require("prosemirror-transform");
var _cellsAtColumn = require("./utils/cells-at-column");
var _findColumn = require("./utils/find-column");
var _getTableRectFromDoc = require("./utils/get-table-rect-from-doc");
var _cellStep = require("./utils/cell-step");
var _sideEffects = require("./utils/side-effects/side-effects");
var _memoizeOne = _interopRequireDefault(require("memoize-one"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
var ADD_COLUMN_STEP = 'ak-add-column';
function printColumnInfo(columnInfo) {
var cellsFrom = [];
var _iterator = _createForOfIteratorHelper(columnInfo.values()),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var cellInfo = _step.value;
cellsFrom.push(cellInfo.from);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return "[".concat(cellsFrom.join(','), "]");
}
function createColumnInfo(cellsInfo) {
return new Map(cellsInfo.map(function (cellInfo) {
return [cellInfo.from, cellInfo];
}));
}
var getTableRectAndColumnFactory = function getTableRectAndColumnFactory(doc, pos, columnInfo) {
return (0, _memoizeOne.default)(function () {
var rect = (0, _getTableRectFromDoc.getTableRectFromDoc)(doc, pos);
var column = (0, _findColumn.findColumn)(columnInfo, rect);
if (column === null) {
throw new Error('no column');
}
return {
rect: rect,
column: column
};
});
};
/**
* Index and positions looks like
* 0 1 2 3 -> Add Column Index
* | 5 | 10 | 15 | -> Table with Positions
* | 20 | 25 | 30 |
* 0 1 2 x -> Remove Column Index
*
*/
var AddColumnStep = /*#__PURE__*/function (_Step) {
(0, _inherits2.default)(AddColumnStep, _Step);
var _super = _createSuper(AddColumnStep);
function AddColumnStep(tablePos, addColumnStepInfo) {
var _this;
var isDelete = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
(0, _classCallCheck2.default)(this, AddColumnStep);
_this = _super.call(this);
_this.tablePos = tablePos;
_this.isDelete = isDelete;
_this.sideEffectsHandler = new _sideEffects.SideEffectsHandler(addColumnStepInfo.sideEffects);
_this.columnInfo = createColumnInfo(addColumnStepInfo.cells);
return _this;
}
/**
* Detect the column based on all the cells step in column info.
* Recreate columnInfo based on the current document. We might need to add new cells added by insert row or unmerge cells.
* If isDelete
* Decrease colspan if one row has merged cell
* Remove all the cells using columnInfo.cellStep[].from
* else
* Increase colspan if one row had merged cell
* Add all new cells at columnInfo.cellStep[].from,
* if there is columnInfo.cellStep[].newCell use it
* else create an empty cell
*
* @param doc Current document
*/
(0, _createClass2.default)(AddColumnStep, [{
key: "apply",
value: function apply(doc) {
var tablePos = this.tablePos;
// Create transform base on the doc
var tr = new _prosemirrorTransform.Transform(doc);
if (this.sideEffectsHandler.table.handleAddTable(tr, this.isDelete)) {
return _prosemirrorTransform.StepResult.ok(tr.doc);
}
var tableRect;
try {
tableRect = (0, _getTableRectFromDoc.getTableRectFromDoc)(doc, tablePos);
} catch (e) {
return _prosemirrorTransform.StepResult.fail(e.message);
}
var column = (0, _findColumn.findColumn)(this.columnInfo, tableRect);
if (column === null) {
return _prosemirrorTransform.StepResult.fail("No column for this cells \"".concat(printColumnInfo(this.columnInfo), "\" in table at position \"").concat(tablePos, "\"."));
}
if (this.sideEffectsHandler.table.handleRemoveTable(tr, this.tablePos, tableRect, column, this.isDelete)) {
return _prosemirrorTransform.StepResult.ok(tr.doc);
}
this.columnInfo = this.applyCellSteps(tr, tableRect, column, this.isDelete);
// Return the document modified.
return _prosemirrorTransform.StepResult.ok(tr.doc);
}
/**
* Update tablePos with the new position. If tablePos doesnt exist any more remove the step
* Update all the cellStep inside columnInfo. If cellStep.from position gets deleted removed it from column info
* if cellStep.length === 0 remove the step
* Create a new step with all the position updated
* @param mapping
*/
}, {
key: "map",
value: function map(mapping) {
var tablePosResult = mapping.mapResult(this.tablePos);
if (tablePosResult.deleted) {
// If table was deleted remove the step
return null;
}
var cellSteps = [];
var _iterator2 = _createForOfIteratorHelper(this.columnInfo.values()),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var oldCellStep = _step2.value;
var fromResult = mapping.mapResult(oldCellStep.from);
var toResult = mapping.mapResult(oldCellStep.to);
if (fromResult.deleted && toResult.deleted) {
continue;
}
var cellStep = _objectSpread(_objectSpread({}, oldCellStep), {}, {
from: fromResult.pos,
to: toResult.pos
});
if (oldCellStep.mergeWith !== undefined) {
cellStep.mergeWith = mapping.map(oldCellStep.mergeWith);
}
cellSteps.push(cellStep);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
if (cellSteps.length === 0) {
return null;
}
var sideEffects = this.sideEffectsHandler.map(mapping);
return new AddColumnStep(tablePosResult.pos, {
cells: cellSteps,
sideEffects: sideEffects
}, this.isDelete);
}
/**
* if isDelete
* Get the original cell node at columnInfo.cellStep[].from to columnInfo.cellStep[].to
* Create a copy of the node
* Create a new cellStep with the same positions but with the clone node as a content
* return new step inverted
* else
* Remove the content from each columnInfo.cellStep[].content
* return new step inverted
* @param originalDoc
*/
}, {
key: "invert",
value: function invert(originalDoc) {
var _this2 = this;
var stepMap = this.getMap();
// Memoize function to be called only on delete scenarios
var getTableRectAndColumn = getTableRectAndColumnFactory(originalDoc, this.tablePos, this.columnInfo);
// This is needed because the real pos of the cell in the generated document is affected by the previous operations.
var newCellSteps = Array.from(this.columnInfo.values(), function (oldCellStep) {
var newCellStep = (0, _cellStep.invertCellStep)(originalDoc, getTableRectAndColumn, oldCellStep, _this2.isDelete, stepMap);
return newCellStep;
});
var sideEffects = this.sideEffectsHandler.invert(originalDoc, this.isDelete, stepMap);
return new AddColumnStep(this.tablePos, {
cells: newCellSteps,
sideEffects: sideEffects
}, !this.isDelete);
}
/**
* StepMap is created based on columnInfo.
* ColumnInfo is created on constructor and once is applied (the document could have new cells that weren't part of the original set)
* if isDelete
* Create range array based on cell info where each range is [cellStep.from, cellStep.from - cellStep.to, 0]
* else
* Create range array base on cell info where each range is [cellStep.from, 0, cellStep.content ? cellStep.content.nodeSize : defaultEmptyCellNodeSize]
*
* Ranges in ProseMirror are represented by each 3 elements in an array.
* As [pos, currentSize, newSize, pos2, currentSize2, newSize2] where:
* pos: Position in the document
* currentSize: Represent the affected range, this will be pos + currentSize
* newSize: Represent the new values, pos + newSize
*/
}, {
key: "getMap",
value: function getMap() {
var tableMap = this.sideEffectsHandler.getTableMap(this.isDelete);
if (tableMap) {
return tableMap;
}
var ranges = [];
var _iterator3 = _createForOfIteratorHelper(this.columnInfo.values()),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var _ranges;
var cellStep = _step3.value;
(_ranges = ranges).push.apply(_ranges, (0, _toConsumableArray2.default)((0, _cellStep.getMapFromCellStep)(cellStep, this.isDelete)));
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
ranges = this.sideEffectsHandler.rows.addRowRanges(ranges, this.isDelete);
// If no steps, I create am empty stepMap
return new _prosemirrorTransform.StepMap(ranges);
}
/**
* Try to merge this step with another one, to be applied directly
* after it. Returns the merged step when possible, null if the
* steps can't be merged.
*/
}, {
key: "merge",
value: function merge(other) {
// We cannot merge add column step at the moment
return null;
}
/**
* Create a JSON-serializeable representation of this step. When
* defining this for a custom subclass, make sure the result object
* includes the step type's [JSON id](#transform.Step^jsonID) under
* the `stepType` property.
*/
}, {
key: "toJSON",
value: function toJSON() {
var addColumnStepJson = {
stepType: ADD_COLUMN_STEP,
tablePos: this.tablePos,
cells: Array.from(this.columnInfo.values(), function (cellStep) {
var cellStepJson = {
from: cellStep.from,
to: cellStep.to
};
if (cellStep.mergeWith !== undefined) {
cellStepJson.mergeWith = cellStep.mergeWith;
}
if (cellStep.newCell !== undefined) {
cellStepJson.newCell = cellStep.newCell.toJSON();
}
return cellStepJson;
}),
isDelete: this.isDelete
};
var sideEffectsJSON = this.sideEffectsHandler.toJSON();
if (sideEffectsJSON) {
addColumnStepJson.sideEffects = sideEffectsJSON;
}
return addColumnStepJson;
}
/**
* Deserialize a step from its JSON representation. Will call
* through to the step class' own implementation of this method.
*/
}, {
key: "applyCellSteps",
value: function applyCellSteps(tr, tableRect, column, isDelete) {
var newColumnInfo = new Map();
var rowsHandler = this.sideEffectsHandler.rows.start(this.isDelete);
var iter = (0, _cellsAtColumn.cellsAtColumn)(tableRect, column);
var next = iter.next();
// Iterate for all the cells in the current document
while (!next.done) {
var cell = next.value;
var previousCellStep = this.columnInfo.get(cell.from);
var newCellStep = (0, _cellStep.createCellStep)(cell, column, isDelete, previousCellStep);
// If is the last cell in the row and doesnt have colspan I need to remove the whole row.
var removeRowResult = rowsHandler.handle(tr, tableRect, cell.row, column, cell);
if (removeRowResult.handled) {
next = iter.next(removeRowResult.skipRows);
continue;
}
// Apply the step, to the pseudo document, get rows to skip, and the cellstep (might be modified, for example, a merge cell that remove the cell instead)
var _applyCellStep = (0, _cellStep.applyCellStep)(tr, tableRect, cell, newCellStep, isDelete, column),
skipRows = _applyCellStep.skipRows,
cellStep = _applyCellStep.cellStep;
// Store the new cell step. This could be an existing one or a new cell.
newColumnInfo.set(newCellStep.from, cellStep);
next = iter.next(skipRows);
}
rowsHandler.end(tr, tableRect, column);
return newColumnInfo;
}
}], [{
key: "fromJSON",
value: function fromJSON(schema, json) {
// TODO: Add validation. Return null if it is invalid. Check in review if this is necessary
var cells = json.cells.map(function (cellsJson) {
var cell = _objectSpread(_objectSpread({}, cellsJson), {}, {
newCell: cellsJson.newCell ? schema.nodeFromJSON(cellsJson.newCell) : undefined
});
return cell;
});
var sideEffects;
if (json.sideEffects) {
sideEffects = _sideEffects.SideEffectsHandler.fromJSON(schema, json.sideEffects);
}
return new AddColumnStep(json.tablePos, {
cells: cells,
sideEffects: sideEffects
}, json.isDelete);
}
}, {
key: "create",
value: function create(doc, tablePos, column) {
var isDelete = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var tableRect = (0, _getTableRectFromDoc.getTableRectFromDoc)(doc, tablePos);
// By default add column will rely on default behaviour (add empty cell).
// There is no need to add content
var cells = [];
var iter = (0, _cellsAtColumn.cellsAtColumn)(tableRect, column);
var next = iter.next();
while (!next.done) {
var cell = next.value;
cells.push((0, _cellStep.createCellStep)(cell, column, isDelete));
var skipRows = 0;
if (cell.attrs && cell.attrs.rowspan) {
skipRows = cell.attrs.rowspan - 1;
}
next = iter.next(skipRows);
}
return new AddColumnStep(tablePos, {
cells: cells
}, isDelete);
}
}]);
return AddColumnStep;
}(_prosemirrorTransform.Step);
exports.AddColumnStep = AddColumnStep;
_prosemirrorTransform.Step.jsonID(ADD_COLUMN_STEP, AddColumnStep);