UNPKG

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

Version:

Paste options toolbar for @atlaskit/editor-core

137 lines (127 loc) 4.8 kB
/** * 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; } }; /** * Returns true if the slice represents a single smart-link card node. * Handles two shapes: * - paragraph > inlineCard|blockCard (smartlink from editor/renderer, wrapped in a paragraph) * - inlineCard|blockCard (top-level card with no paragraph wrapper) */ var isSingleSmartLinkCard = function isSingleSmartLinkCard(slice) { var isSupportedCard = function isSupportedCard(node) { return node.type.name === 'inlineCard' || node.type.name === 'blockCard'; }; if (slice.content.childCount !== 1) { return false; } var topNode = slice.content.child(0); // Top-level inlineCard/blockCard (no paragraph wrapper) if (isSupportedCard(topNode)) { return true; } // paragraph > inlineCard/blockCard if (topNode.type.name !== 'paragraph') { return false; } if (topNode.childCount !== 1) { return false; } return isSupportedCard(topNode.child(0)); }; /** * 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 if the slice represents a single bare link with no label. * Handles two shapes: * - paragraph > text(link mark) (standard rich-text paste, wrapped in a paragraph) * - text(link mark) (top-level text node with no paragraph wrapper) * Whitespace-only sibling text nodes are ignored in both cases. */ var isSingleBareLink = function isSingleBareLink(slice) { // Top-level text node with a link mark (no paragraph wrapper) var significantTopChildren = significantChildren(slice.content); if (significantTopChildren.length === 1 && isUrlOnlyLinkTextNode(significantTopChildren[0])) { return true; } // paragraph > text(link mark) if (slice.content.childCount !== 1) { return false; } var topNode = slice.content.child(0); if (topNode.type.name !== 'paragraph') { return false; } var children = significantChildren(topNode.content); if (children.length !== 1) { return false; } return isUrlOnlyLinkTextNode(children[0]); }; /** * 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); };