@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
279 lines (267 loc) • 13.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.removeConnectedNodes = exports.isReferencedSource = exports.getNodeName = exports.getConnections = exports.getChildrenInfo = void 0;
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
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 isReferencedSource = exports.isReferencedSource = function isReferencedSource(state, node) {
var _node$attrs, _node$marks;
if (!node) {
return false;
}
var found = false;
// Handle nodes having 2 uuids. They could have a localId or a fragment. Regardless this needs
// to check if either id is used by a data consumer.
var localIds = new Set([(_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.localId, (_node$marks = node.marks) === null || _node$marks === void 0 || (_node$marks = _node$marks.find(function (mark) {
return mark.type === state.schema.marks.fragment;
})) === null || _node$marks === void 0 || (_node$marks = _node$marks.attrs) === null || _node$marks === void 0 ? void 0 : _node$marks.localId].filter(Boolean));
// If there are no uuids on the node then it's not possible for it to be referenced anywhere.
if (!localIds.size) {
return false;
}
state.doc.descendants(function (node) {
var _dataConsumer$attrs$s, _dataConsumer$attrs$s2;
if (found) {
return false;
}
var dataConsumer = node.marks.find(function (mark) {
return mark.type === state.schema.marks.dataConsumer;
});
if (!dataConsumer) {
return true;
}
found = (_dataConsumer$attrs$s = (_dataConsumer$attrs$s2 = dataConsumer.attrs.sources) === null || _dataConsumer$attrs$s2 === void 0 ? void 0 : _dataConsumer$attrs$s2.some(function (src) {
return localIds.has(src);
})) !== null && _dataConsumer$attrs$s !== void 0 ? _dataConsumer$attrs$s : false;
return !found;
});
return found;
};
var getConnections = exports.getConnections = function getConnections(state) {
var result = {};
var doc = state.doc,
schema = state.schema;
// Keeps a map of all raw ids -> to their preferred normalised varient. A node with both fragmentMark & localId will
// have both ids mapped here to the same normalized version.
var normalizedIds = new Map();
var dataConsumerSources = new Map();
// Perform a prelim scan creating the initial id to connection link mappings.
// This will also save a list of data sources consumed per node.
doc.descendants(function (node, pos) {
var _node$attrs2, _fragmentMark$attrs$l, _fragmentMark, _node$attrs3, _fragmentMark2, _node$attrs4, _fragmentMark3;
var dataConsumer;
var fragmentMark;
node.marks.some(function (mark) {
if (mark.type === schema.marks.dataConsumer) {
dataConsumer = mark;
} else if (mark.type === schema.marks.fragment) {
fragmentMark = mark;
}
// Stop searching marks if we've found both consumer and fragment.
return !!dataConsumer && !!fragmentMark;
});
// If node cannot be referenced by any means then abort.
if (!fragmentMark && !((_node$attrs2 = node.attrs) !== null && _node$attrs2 !== void 0 && _node$attrs2.localId)) {
return true;
}
var normalizedId = (_fragmentMark$attrs$l = (_fragmentMark = fragmentMark) === null || _fragmentMark === void 0 || (_fragmentMark = _fragmentMark.attrs) === null || _fragmentMark === void 0 ? void 0 : _fragmentMark.localId) !== null && _fragmentMark$attrs$l !== void 0 ? _fragmentMark$attrs$l : (_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.localId;
if (!normalizedId) {
return true;
}
if (!!((_fragmentMark2 = fragmentMark) !== null && _fragmentMark2 !== void 0 && (_fragmentMark2 = _fragmentMark2.attrs) !== null && _fragmentMark2 !== void 0 && _fragmentMark2.localId)) {
normalizedIds.set(fragmentMark.attrs.localId, normalizedId);
}
if (!!((_node$attrs4 = node.attrs) !== null && _node$attrs4 !== void 0 && _node$attrs4.localId)) {
normalizedIds.set(node.attrs.localId, normalizedId);
}
if (!!result[normalizedId]) {
// Duplicate ID has been found, we'll care about the first one for now.
return true;
}
result[normalizedId] = {
localId: normalizedId,
name: (_fragmentMark3 = fragmentMark) === null || _fragmentMark3 === void 0 || (_fragmentMark3 = _fragmentMark3.attrs) === null || _fragmentMark3 === void 0 ? void 0 : _fragmentMark3.name,
node: node,
pos: pos,
targets: []
};
if (!!dataConsumer && dataConsumer.attrs.sources.length) {
dataConsumerSources.set(normalizedId, dataConsumer.attrs.sources);
}
// Do not descend into children of a node which has a dataConsumer attached. This assumes all children of the node cannot
// be referenced by another node.
return !dataConsumer;
});
// This 2nd-pass only looks at the consumer sources and updates all connections with the correct id refs.
var _iterator = _createForOfIteratorHelper(dataConsumerSources),
_step;
try {
var _loop = function _loop() {
var _step$value = (0, _slicedToArray2.default)(_step.value, 2),
localId = _step$value[0],
sources = _step$value[1];
// This is a ref to the node (connection link) which contains the consumer.
sources.forEach(function (src) {
var _normalizedIds$get;
var normalizedId = (_normalizedIds$get = normalizedIds.get(src)) !== null && _normalizedIds$get !== void 0 ? _normalizedIds$get : src;
var srcLink = result[normalizedId];
if (srcLink && normalizedId !== localId) {
srcLink.targets.push(localId);
}
});
};
for (_iterator.s(); !(_step = _iterator.n()).done;) {
_loop();
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return result;
};
var removeConnectedNodes = exports.removeConnectedNodes = function removeConnectedNodes(state, node) {
if (!node) {
return state.tr;
}
var selectedLocalIds = getSelectedLocalIds(state, node);
var allNodes = getConnections(state);
var idsToBeDeleted = getIdsToBeDeleted(selectedLocalIds, allNodes);
if (!(idsToBeDeleted !== null && idsToBeDeleted !== void 0 && idsToBeDeleted.length)) {
return state.tr;
}
var tr = state.tr;
var newTr = tr;
idsToBeDeleted.forEach(function (id) {
if (!allNodes[id]) {
return;
}
var _allNodes$id = allNodes[id],
node = _allNodes$id.node,
pos = _allNodes$id.pos;
newTr = newTr.delete(newTr.mapping.map(pos), newTr.mapping.map(node.nodeSize + pos));
});
return newTr;
};
// find all ids need to be remove connected to selected extension
var getIdsToBeDeleted = function getIdsToBeDeleted(selectedIds, allNodes) {
if (!selectedIds.size) {
return [];
}
var searchSet = (0, _toConsumableArray2.default)(selectedIds);
var deletedIds = new Set();
while (searchSet.length) {
var id = searchSet.pop();
if (allNodes[id]) {
var _allNodes$id$targets$, _allNodes$id2;
deletedIds.add(allNodes[id].localId);
searchSet = searchSet.concat((_allNodes$id$targets$ = (_allNodes$id2 = allNodes[id]) === null || _allNodes$id2 === void 0 ? void 0 : _allNodes$id2.targets.filter(function (targetId) {
var _allNodes$targetId;
return !deletedIds.has((_allNodes$targetId = allNodes[targetId]) === null || _allNodes$targetId === void 0 ? void 0 : _allNodes$targetId.localId);
})) !== null && _allNodes$id$targets$ !== void 0 ? _allNodes$id$targets$ : []);
}
}
return Array.from(deletedIds);
};
// for get children info for confirmation dialog
var getChildrenInfo = exports.getChildrenInfo = function getChildrenInfo(state, node) {
var allChildrenHadName = true;
if (!node) {
return [];
}
var childrenIdSet = new Set();
var childrenInfoArray = [];
var allNodes = getConnections(state);
var selectedNodeIds = getSelectedLocalIds(state, node);
selectedNodeIds.forEach(function (id) {
if (allNodes[id]) {
allNodes[id].targets.forEach(childrenIdSet.add, childrenIdSet);
}
});
var _iterator2 = _createForOfIteratorHelper(childrenIdSet),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var id = _step2.value;
if (!getNodeNameById(id, allNodes)) {
allChildrenHadName = false;
break;
} else {
childrenInfoArray.push({
id: id,
name: getNodeNameById(id, allNodes),
amount: getChildrenNodeAmount(id, allNodes)
});
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return allChildrenHadName ? childrenInfoArray : [];
};
var getChildrenNodeAmount = function getChildrenNodeAmount(id, allNodes) {
var searchTerms = new Set([id]);
var traverseHistory = new Map();
var childrenIds = new Set();
traverseHistory.set(id, false);
while (searchTerms.size > 0) {
var _searchTerms = (0, _slicedToArray2.default)(searchTerms, 1),
currTerm = _searchTerms[0];
var targets = getNodeTargetsById(currTerm, allNodes);
targets.forEach(function (target) {
var isTargetCounted = traverseHistory.get(target);
if (!isTargetCounted) {
searchTerms.add(target);
childrenIds.add(target);
}
target !== id && childrenIds.add(target);
});
traverseHistory.set(currTerm, true);
searchTerms.delete(currTerm);
}
return childrenIds.size;
};
var getNodeTargetsById = function getNodeTargetsById(id, allNodes) {
if (!id || !allNodes[id]) {
return [];
}
return allNodes[id].targets;
};
var getNodeNameById = function getNodeNameById(id, allNodes) {
if ((0, _typeof2.default)(id) === 'object') {
var name;
id.forEach(function (localId) {
var _name, _allNodes$localId;
name = (_name = name) !== null && _name !== void 0 ? _name : (_allNodes$localId = allNodes[localId]) === null || _allNodes$localId === void 0 ? void 0 : _allNodes$localId.name;
});
return name || null;
}
if (!id || !allNodes[id]) {
return null;
}
return allNodes[id].name;
};
var getSelectedLocalIds = function getSelectedLocalIds(state, node) {
var _node$attrs5, _node$marks2;
if (!node) {
return new Set([]);
}
var localIds = new Set([(_node$attrs5 = node.attrs) === null || _node$attrs5 === void 0 ? void 0 : _node$attrs5.localId, (_node$marks2 = node.marks) === null || _node$marks2 === void 0 || (_node$marks2 = _node$marks2.find(function (mark) {
return mark.type === state.schema.marks.fragment;
})) === null || _node$marks2 === void 0 || (_node$marks2 = _node$marks2.attrs) === null || _node$marks2 === void 0 ? void 0 : _node$marks2.localId].filter(Boolean));
return localIds;
};
var getNodeName = exports.getNodeName = function getNodeName(state, node) {
var _node$marks$find$attr, _node$marks3;
return (_node$marks$find$attr = node === null || node === void 0 || (_node$marks3 = node.marks) === null || _node$marks3 === void 0 || (_node$marks3 = _node$marks3.find(function (mark) {
return mark.type === state.schema.marks.fragment;
})) === null || _node$marks3 === void 0 || (_node$marks3 = _node$marks3.attrs) === null || _node$marks3 === void 0 ? void 0 : _node$marks3.name) !== null && _node$marks$find$attr !== void 0 ? _node$marks$find$attr : '';
};