diff --git a/docs/src/docPages/api/marks/link.md b/docs/src/docPages/api/marks/link.md index 10fe4235..8a94d207 100644 --- a/docs/src/docPages/api/marks/link.md +++ b/docs/src/docPages/api/marks/link.md @@ -18,10 +18,11 @@ yarn add @tiptap/extension-link ``` ## Settings -| Option | Type | Default | Description | -| -------------- | --------- | ----------------------------------------------------------- | --------------------------------------------------------------------- | -| HTMLAttributes | `Object` | `{ target: '_blank', rel: 'noopener noreferrer nofollow' }` | Custom HTML attributes that should be added to the rendered HTML tag. | -| openOnClick | `Boolean` | `true` | If enabled, links will be opened on click. | +| Option | Type | Default | Description | +| -------------- | --------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------- | +| HTMLAttributes | `Object` | `{ target: '_blank', rel: 'noopener noreferrer nofollow' }` | Custom HTML attributes that should be added to the rendered HTML tag. | +| openOnClick | `Boolean` | `true` | If enabled, links will be opened on click. | +| linkOnPaste | `Boolean` | `true` | Adds a link to the current selection if the pasted content only contains an url. | ## Commands | Command | Parameters | Description | diff --git a/packages/extension-link/src/link.ts b/packages/extension-link/src/link.ts index 2274c438..515f8d55 100644 --- a/packages/extension-link/src/link.ts +++ b/packages/extension-link/src/link.ts @@ -7,7 +7,17 @@ import { import { Plugin, PluginKey } from 'prosemirror-state' export interface LinkOptions { + /** + * If enabled, links will be opened on click. + */ openOnClick: boolean, + /** + * Adds a link to the current selection if the pasted content only contains an url. + */ + linkOnPaste: boolean, + /** + * A list of HTML attributes to be rendered. + */ HTMLAttributes: Record, } @@ -32,6 +42,7 @@ declare module '@tiptap/core' { export const pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi export const pasteRegexWithBrackets = /(?:\()https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/()]*)(?:\))/gi +export const pasteRegexExact = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)$/gi export const Link = Mark.create({ name: 'link', @@ -42,6 +53,7 @@ export const Link = Mark.create({ defaultOptions: { openOnClick: true, + linkOnPaste: true, HTMLAttributes: { target: '_blank', rel: 'noopener noreferrer nofollow', @@ -91,28 +103,65 @@ export const Link = Mark.create({ }, addProseMirrorPlugins() { - if (!this.options.openOnClick) { - return [] + const plugins = [] + + if (this.options.openOnClick) { + plugins.push( + new Plugin({ + key: new PluginKey('handleClickLink'), + props: { + handleClick: (view, pos, event) => { + const attrs = this.editor.getMarkAttributes('link') + const link = (event.target as HTMLElement)?.closest('a') + + if (link && attrs.href) { + window.open(attrs.href, attrs.target) + + return true + } + + return false + }, + }, + }), + ) } - return [ - new Plugin({ - key: new PluginKey('handleClick'), - props: { - handleClick: (view, pos, event) => { - const attrs = this.editor.getMarkAttributes('link') - const link = (event.target as HTMLElement)?.closest('a') + if (this.options.linkOnPaste) { + plugins.push( + new Plugin({ + key: new PluginKey('handlePasteLink'), + props: { + handlePaste: (view, event, slice) => { + const { state } = view + const { selection } = state + const { empty } = selection - if (link && attrs.href) { - window.open(attrs.href, attrs.target) + if (empty) { + return false + } + + let textContent = '' + + slice.content.forEach(node => { + textContent += node.textContent + }) + + if (!textContent || !textContent.match(pasteRegexExact)) { + return false + } + + this.editor.commands.setMark(this.type, { + href: textContent, + }) return true - } - - return false + }, }, - }, - }), - ] + }), + ) + } + + return plugins }, })