UNPKG

@atlaskit/adf-schema

Version:

Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs

381 lines (365 loc) 18 kB
"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);