@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
277 lines (265 loc) • 12.7 kB
JavaScript
import _typeof from "@babel/runtime/helpers/typeof";
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, 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 o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
export var 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;
};
export var 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 = _slicedToArray(_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;
};
export var 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 = _toConsumableArray(selectedIds);
var deletedIds = new Set();
while (searchSet.length) {
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
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
export var 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 = _slicedToArray(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;
};
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var getNodeTargetsById = function getNodeTargetsById(id, allNodes) {
if (!id || !allNodes[id]) {
return [];
}
return allNodes[id].targets;
};
var getNodeNameById = function getNodeNameById(id, allNodes) {
if (_typeof(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;
};
export var 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 : '';
};