tiptap/packages/extension-link/src/link.ts
2021-04-07 18:29:16 +02:00

120 lines
2.6 KiB
TypeScript

import {
Command,
Mark,
markPasteRule,
mergeAttributes,
} from '@tiptap/core'
import { Plugin, PluginKey } from 'prosemirror-state'
export interface LinkOptions {
openOnClick: boolean,
HTMLAttributes: {
[key: string]: any
},
}
declare module '@tiptap/core' {
interface Commands {
link: {
/**
* Set a link mark
*/
setLink: (attributes: { href: string, target?: string }) => Command,
/**
* Toggle a link mark
*/
toggleLink: (attributes: { href: string, target?: string }) => Command,
/**
* Unset a link mark
*/
unsetLink: () => Command,
}
}
}
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 Link = Mark.create<LinkOptions>({
name: 'link',
priority: 1000,
inclusive: false,
defaultOptions: {
openOnClick: true,
HTMLAttributes: {
target: '_blank',
rel: 'noopener noreferrer nofollow',
},
},
addAttributes() {
return {
href: {
default: null,
},
target: {
default: this.options.HTMLAttributes.target,
},
}
},
parseHTML() {
return [
{ tag: 'a[href]' },
]
},
renderHTML({ HTMLAttributes }) {
return ['a', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
},
addCommands() {
return {
setLink: attributes => ({ commands }) => {
return commands.setMark('link', attributes)
},
toggleLink: attributes => ({ commands }) => {
return commands.toggleMark('link', attributes)
},
unsetLink: () => ({ commands }) => {
return commands.unsetMark('link')
},
}
},
addPasteRules() {
return [
markPasteRule(pasteRegex, this.type, (url: string) => ({ href: url })),
markPasteRule(pasteRegexWithBrackets, this.type, (url: string) => ({ href: url })),
]
},
addProseMirrorPlugins() {
if (!this.options.openOnClick) {
return []
}
return [
new Plugin({
key: new PluginKey('handleClick'),
props: {
handleClick: (view, pos, event) => {
const attrs = this.editor.getMarkAttributes('link')
if (attrs.href && event.target instanceof HTMLAnchorElement) {
window.open(attrs.href, attrs.target)
return false
}
return true
},
},
}),
]
},
})