@atlaskit/editor-plugin-card
Version:
Card plugin for @atlaskit/editor-core
94 lines • 3.18 kB
JavaScript
import { getNativeEmbedUrl, isNativeEmbedNode } from './nativeEmbedNode';
export const DISPLAY_AS_OPTIONS = ['url', 'inline', 'block', 'embed'];
const cardAtPos = (node, pos) => {
switch (node === null || node === void 0 ? void 0 : node.type.name) {
case 'inlineCard':
return {
appearance: 'inline',
pos
};
case 'blockCard':
return {
appearance: 'block',
pos
};
case 'embedCard':
return {
appearance: 'embed',
pos
};
default:
return isNativeEmbedNode(node) ? {
appearance: 'embed',
isNativeEmbed: true,
pos
} : undefined;
}
};
const getNodeUrl = node => {
var _attrs$url, _attrs$data;
if (isNativeEmbedNode(node)) {
return getNativeEmbedUrl(node);
}
const attrs = node.attrs;
const url = (_attrs$url = attrs === null || attrs === void 0 ? void 0 : attrs.url) !== null && _attrs$url !== void 0 ? _attrs$url : attrs === null || attrs === void 0 ? void 0 : (_attrs$data = attrs.data) === null || _attrs$data === void 0 ? void 0 : _attrs$data.url;
return typeof url === 'string' ? url : undefined;
};
/**
* Finds the card that a paste produced.
*
* The paste range is recorded when the paste happens and then mapped through every later
* transaction, so by the time the link has resolved into a card the range can point just
* past that card. `pastedUrl` resolves the ambiguity: when it is known, a candidate
* holding that URL wins over one that merely sits in the range, which stops a pre-existing
* neighbouring card from being reported as the pasted one.
*/
export const getCardAtPasteRange = (state, pasteStartPos, pasteEndPos, pastedUrl) => {
const docContentSize = state.doc.content.size;
const clampedStart = Math.max(0, Math.min(pasteStartPos, docContentSize));
const clampedEnd = Math.max(0, Math.min(pasteEndPos, docContentSize));
const from = Math.min(clampedStart, clampedEnd);
const to = Math.max(clampedStart, clampedEnd);
try {
var _inRange;
const candidateAt = pos => {
if (pos < 0 || pos >= docContentSize) {
return undefined;
}
const node = state.doc.nodeAt(pos);
const card = cardAtPos(node, pos);
return node && card ? {
card,
url: getNodeUrl(node)
} : undefined;
};
const adjacent = [candidateAt(from - 1), candidateAt(from)].filter(candidate => Boolean(candidate));
const inRange = [];
state.doc.nodesBetween(from, to, (node, pos) => {
const card = cardAtPos(node, pos);
if (card) {
inRange.push({
card,
url: getNodeUrl(node)
});
return false;
}
return true;
});
if (pastedUrl) {
const match = [...adjacent, ...inRange].find(candidate => candidate.url === pastedUrl);
if (match) {
return match.card;
}
}
if (from === to) {
const [firstAdjacent] = adjacent;
if (firstAdjacent) {
return firstAdjacent.card;
}
}
return (_inRange = inRange[inRange.length - 1]) === null || _inRange === void 0 ? void 0 : _inRange.card;
} catch {
return undefined;
}
};