UNPKG

@atlaskit/editor-plugin-paste-options-toolbar

Version:

Paste options toolbar for @atlaskit/editor-core

113 lines (107 loc) 4.33 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; /** * Returns true if the given text node's sole mark is a `link` mark whose href * matches the node's text content exactly (i.e. the link label IS the URL). * Or if the text content is a parseable URL. */ var isUrlOnlyLinkTextNode = function isUrlOnlyLinkTextNode(node) { var _node$marks$0$attrs$h, _node$marks$0$attrs, _node$text; if (!node.isText) { return false; } if (node.marks.length !== 1 || node.marks[0].type.name !== 'link') { return false; } var href = (_node$marks$0$attrs$h = (_node$marks$0$attrs = node.marks[0].attrs) === null || _node$marks$0$attrs === void 0 ? void 0 : _node$marks$0$attrs.href) !== null && _node$marks$0$attrs$h !== void 0 ? _node$marks$0$attrs$h : ''; // Check if the text content is a URL var textOfNode = (_node$text = node.text) !== null && _node$text !== void 0 ? _node$text : ''; var parseableUrl = isParseableUrl(textOfNode); return node.text === href || parseableUrl; }; /** * Checks if a given string is parseable as a URL. */ var isParseableUrl = function isParseableUrl(text) { var _URL; if (typeof ((_URL = URL) === null || _URL === void 0 ? void 0 : _URL.canParse) === 'function') { return URL.canParse(text); } // Fallback for older environments try { new URL(text); return true; } catch (e) { return false; } }; var isSupportedCard = function isSupportedCard(node) { return node.type.name === 'inlineCard' || node.type.name === 'blockCard' || node.type.name === 'embedCard'; }; var transparentSingleChildContainerNodeTypes = new Set(['paragraph', 'listItem', 'bulletList', 'orderedList']); /** * Returns the children of a Fragment, filtering out whitespace-only text nodes. * This handles trailing/leading spaces that browsers sometimes include when * copying a link (e.g. `<a href="...">URL</a> `). */ var significantChildren = function significantChildren(fragment) { var children = []; fragment.forEach(function (child) { var _child$text; if (child.isText && ((_child$text = child.text) === null || _child$text === void 0 ? void 0 : _child$text.trim()) === '') { return; } children.push(child); }); return children; }; /** * Returns true when the fragment contains exactly one meaningful leaf that * satisfies `isSupportedLeaf`. * * Transparent single-child containers (paragraph, listItem, bulletList, and * orderedList) are traversed recursively. Whitespace-only sibling text nodes * are ignored at each level. */ var _containsExactlyOneMeaningfulLeaf = function containsExactlyOneMeaningfulLeaf(fragment, isSupportedLeaf) { var children = significantChildren(fragment); if (children.length !== 1) { return false; } var _children = _slicedToArray(children, 1), child = _children[0]; if (isSupportedLeaf(child)) { return true; } if (!transparentSingleChildContainerNodeTypes.has(child.type.name)) { return false; } return _containsExactlyOneMeaningfulLeaf(child.content, isSupportedLeaf); }; var isSingleSmartLinkCard = function isSingleSmartLinkCard(slice) { return _containsExactlyOneMeaningfulLeaf(slice.content, isSupportedCard); }; var isSingleBareLink = function isSingleBareLink(slice) { return _containsExactlyOneMeaningfulLeaf(slice.content, isUrlOnlyLinkTextNode); }; /** * Returns `true` when the pasted content is NOT a single standalone link. * * A paste is considered a "single link" (returns `false`) when: * - The slice contains exactly one paragraph with one text node whose text * equals its `link` mark href (bare URL link, no custom label), OR * - The slice contains exactly one paragraph with a single `inlineCard` node * (smartlink from the renderer or editor). * * Returns `true` (not a single link) when: * - The pasted link has a custom label (text ≠ href) * - There are multiple paragraphs or sibling nodes * - There is additional text alongside the link in the same paragraph * - The slice is absent (plain-text paste) */ export var isNotSingleLink = function isNotSingleLink(slice) { if (!slice || !slice.content.size) { // No rich-text slice → plain text paste, not a single link in the relevant sense return true; } return !isSingleBareLink(slice) && !isSingleSmartLinkCard(slice); };