|  |  |  |  | (function (global, factory) { | 
					
						
							|  |  |  |  |   typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tiptap/core'), require('linkifyjs'), require('prosemirror-state')) : | 
					
						
							|  |  |  |  |   typeof define === 'function' && define.amd ? define(['exports', '@tiptap/core', 'linkifyjs', 'prosemirror-state'], factory) : | 
					
						
							|  |  |  |  |   (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@tiptap/extension-link"] = {}, global.core, global.linkifyjs, global.prosemirrorState)); | 
					
						
							|  |  |  |  | })(this, (function (exports, core, linkifyjs, prosemirrorState) { 'use strict'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function autolink(options) { | 
					
						
							|  |  |  |  |       return new prosemirrorState.Plugin({ | 
					
						
							|  |  |  |  |           key: new prosemirrorState.PluginKey('autolink'), | 
					
						
							|  |  |  |  |           appendTransaction: (transactions, oldState, newState) => { | 
					
						
							|  |  |  |  |               const docChanges = transactions.some(transaction => transaction.docChanged) | 
					
						
							|  |  |  |  |                   && !oldState.doc.eq(newState.doc); | 
					
						
							|  |  |  |  |               const preventAutolink = transactions.some(transaction => transaction.getMeta('preventAutolink')); | 
					
						
							|  |  |  |  |               if (!docChanges || preventAutolink) { | 
					
						
							|  |  |  |  |                   return; | 
					
						
							|  |  |  |  |               } | 
					
						
							|  |  |  |  |               const { tr } = newState; | 
					
						
							|  |  |  |  |               const transform = core.combineTransactionSteps(oldState.doc, [...transactions]); | 
					
						
							|  |  |  |  |               const { mapping } = transform; | 
					
						
							|  |  |  |  |               const changes = core.getChangedRanges(transform); | 
					
						
							|  |  |  |  |               changes.forEach(({ oldRange, newRange }) => { | 
					
						
							|  |  |  |  |                   // at first we check if we have to remove links
 | 
					
						
							|  |  |  |  |                   core.getMarksBetween(oldRange.from, oldRange.to, oldState.doc) | 
					
						
							|  |  |  |  |                       .filter(item => item.mark.type === options.type) | 
					
						
							|  |  |  |  |                       .forEach(oldMark => { | 
					
						
							|  |  |  |  |                       const newFrom = mapping.map(oldMark.from); | 
					
						
							|  |  |  |  |                       const newTo = mapping.map(oldMark.to); | 
					
						
							|  |  |  |  |                       const newMarks = core.getMarksBetween(newFrom, newTo, newState.doc) | 
					
						
							|  |  |  |  |                           .filter(item => item.mark.type === options.type); | 
					
						
							|  |  |  |  |                       if (!newMarks.length) { | 
					
						
							|  |  |  |  |                           return; | 
					
						
							|  |  |  |  |                       } | 
					
						
							|  |  |  |  |                       const newMark = newMarks[0]; | 
					
						
							|  |  |  |  |                       const oldLinkText = oldState.doc.textBetween(oldMark.from, oldMark.to, undefined, ' '); | 
					
						
							|  |  |  |  |                       const newLinkText = newState.doc.textBetween(newMark.from, newMark.to, undefined, ' '); | 
					
						
							|  |  |  |  |                       const wasLink = linkifyjs.test(oldLinkText); | 
					
						
							|  |  |  |  |                       const isLink = linkifyjs.test(newLinkText); | 
					
						
							|  |  |  |  |                       // remove only the link, if it was a link before too
 | 
					
						
							|  |  |  |  |                       // because we don’t want to remove links that were set manually
 | 
					
						
							|  |  |  |  |                       if (wasLink && !isLink) { | 
					
						
							|  |  |  |  |                           tr.removeMark(newMark.from, newMark.to, options.type); | 
					
						
							|  |  |  |  |                       } | 
					
						
							|  |  |  |  |                   }); | 
					
						
							|  |  |  |  |                   // now let’s see if we can add new links
 | 
					
						
							|  |  |  |  |                   const nodesInChangedRanges = core.findChildrenInRange(newState.doc, newRange, node => node.isTextblock); | 
					
						
							|  |  |  |  |                   let textBlock; | 
					
						
							|  |  |  |  |                   let textBeforeWhitespace; | 
					
						
							|  |  |  |  |                   if (nodesInChangedRanges.length > 1) { | 
					
						
							|  |  |  |  |                       // Grab the first node within the changed ranges (ex. the first of two paragraphs when hitting enter)
 | 
					
						
							|  |  |  |  |                       textBlock = nodesInChangedRanges[0]; | 
					
						
							|  |  |  |  |                       textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, textBlock.pos + textBlock.node.nodeSize, undefined, ' '); | 
					
						
							|  |  |  |  |                   } | 
					
						
							|  |  |  |  |                   else if (nodesInChangedRanges.length | 
					
						
							|  |  |  |  |                       // We want to make sure to include the block seperator argument to treat hard breaks like spaces
 | 
					
						
							|  |  |  |  |                       && newState.doc.textBetween(newRange.from, newRange.to, ' ', ' ').endsWith(' ')) { | 
					
						
							|  |  |  |  |                       textBlock = nodesInChangedRanges[0]; | 
					
						
							|  |  |  |  |                       textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, undefined, ' '); | 
					
						
							|  |  |  |  |                   } | 
					
						
							|  |  |  |  |                   if (textBlock && textBeforeWhitespace) { | 
					
						
							|  |  |  |  |                       const wordsBeforeWhitespace = textBeforeWhitespace.split(' ').filter(s => s !== ''); | 
					
						
							|  |  |  |  |                       if (wordsBeforeWhitespace.length <= 0) { | 
					
						
							|  |  |  |  |                           return false; | 
					
						
							|  |  |  |  |                       } | 
					
						
							|  |  |  |  |                       const lastWordBeforeSpace = wordsBeforeWhitespace[wordsBeforeWhitespace.length - 1]; | 
					
						
							|  |  |  |  |                       const lastWordAndBlockOffset = textBlock.pos + textBeforeWhitespace.lastIndexOf(lastWordBeforeSpace); | 
					
						
							|  |  |  |  |                       if (!lastWordBeforeSpace) { | 
					
						
							|  |  |  |  |                           return false; | 
					
						
							|  |  |  |  |                       } | 
					
						
							|  |  |  |  |                       linkifyjs.find(lastWordBeforeSpace) | 
					
						
							|  |  |  |  |                           .filter(link => link.isLink) | 
					
						
							|  |  |  |  |                           .filter(link => { | 
					
						
							|  |  |  |  |                           if (options.validate) { | 
					
						
							|  |  |  |  |                               return options.validate(link.value); | 
					
						
							|  |  |  |  |                           } | 
					
						
							|  |  |  |  |                           return true; | 
					
						
							|  |  |  |  |                       }) | 
					
						
							|  |  |  |  |                           // calculate link position
 | 
					
						
							|  |  |  |  |                           .map(link => ({ | 
					
						
							|  |  |  |  |                           ...link, | 
					
						
							|  |  |  |  |                           from: lastWordAndBlockOffset + link.start + 1, | 
					
						
							|  |  |  |  |                           to: lastWordAndBlockOffset + link.end + 1, | 
					
						
							|  |  |  |  |                       })) | 
					
						
							|  |  |  |  |                           // add link mark
 | 
					
						
							|  |  |  |  |                           .forEach(link => { | 
					
						
							|  |  |  |  |                           tr.addMark(link.from, link.to, options.type.create({ | 
					
						
							|  |  |  |  |                               href: link.href, | 
					
						
							|  |  |  |  |                           })); | 
					
						
							|  |  |  |  |                       }); | 
					
						
							|  |  |  |  |                   } | 
					
						
							|  |  |  |  |               }); | 
					
						
							|  |  |  |  |               if (!tr.steps.length) { | 
					
						
							|  |  |  |  |                   return; | 
					
						
							|  |  |  |  |               } | 
					
						
							|  |  |  |  |               return tr; | 
					
						
							|  |  |  |  |           }, | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function clickHandler(options) { | 
					
						
							|  |  |  |  |       return new prosemirrorState.Plugin({ | 
					
						
							|  |  |  |  |           key: new prosemirrorState.PluginKey('handleClickLink'), | 
					
						
							|  |  |  |  |           props: { | 
					
						
							|  |  |  |  |               handleClick: (view, pos, event) => { | 
					
						
							|  |  |  |  |                   var _a; | 
					
						
							|  |  |  |  |                   const attrs = core.getAttributes(view.state, options.type.name); | 
					
						
							|  |  |  |  |                   const link = (_a = event.target) === null || _a === void 0 ? void 0 : _a.closest('a'); | 
					
						
							|  |  |  |  |                   if (link && attrs.href) { | 
					
						
							|  |  |  |  |                       window.open(attrs.href, attrs.target); | 
					
						
							|  |  |  |  |                       return true; | 
					
						
							|  |  |  |  |                   } | 
					
						
							|  |  |  |  |                   return false; | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |           }, | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function pasteHandler(options) { | 
					
						
							|  |  |  |  |       return new prosemirrorState.Plugin({ | 
					
						
							|  |  |  |  |           key: new prosemirrorState.PluginKey('handlePasteLink'), | 
					
						
							|  |  |  |  |           props: { | 
					
						
							|  |  |  |  |               handlePaste: (view, event, slice) => { | 
					
						
							|  |  |  |  |                   const { state } = view; | 
					
						
							|  |  |  |  |                   const { selection } = state; | 
					
						
							|  |  |  |  |                   const { empty } = selection; | 
					
						
							|  |  |  |  |                   if (empty) { | 
					
						
							|  |  |  |  |                       return false; | 
					
						
							|  |  |  |  |                   } | 
					
						
							|  |  |  |  |                   let textContent = ''; | 
					
						
							|  |  |  |  |                   slice.content.forEach(node => { | 
					
						
							|  |  |  |  |                       textContent += node.textContent; | 
					
						
							|  |  |  |  |                   }); | 
					
						
							|  |  |  |  |                   const link = linkifyjs.find(textContent).find(item => item.isLink && item.value === textContent); | 
					
						
							|  |  |  |  |                   if (!textContent || !link) { | 
					
						
							|  |  |  |  |                       return false; | 
					
						
							|  |  |  |  |                   } | 
					
						
							|  |  |  |  |                   options.editor.commands.setMark(options.type, { | 
					
						
							|  |  |  |  |                       href: link.href, | 
					
						
							|  |  |  |  |                   }); | 
					
						
							|  |  |  |  |                   return true; | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |           }, | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   const Link = core.Mark.create({ | 
					
						
							|  |  |  |  |       name: 'link', | 
					
						
							|  |  |  |  |       priority: 1000, | 
					
						
							|  |  |  |  |       keepOnSplit: false, | 
					
						
							|  |  |  |  |       onCreate() { | 
					
						
							|  |  |  |  |           this.options.protocols.forEach(linkifyjs.registerCustomProtocol); | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       onDestroy() { | 
					
						
							|  |  |  |  |           linkifyjs.reset(); | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       inclusive() { | 
					
						
							|  |  |  |  |           return this.options.autolink; | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       addOptions() { | 
					
						
							|  |  |  |  |           return { | 
					
						
							|  |  |  |  |               openOnClick: true, | 
					
						
							|  |  |  |  |               linkOnPaste: true, | 
					
						
							|  |  |  |  |               autolink: true, | 
					
						
							|  |  |  |  |               protocols: [], | 
					
						
							|  |  |  |  |               HTMLAttributes: { | 
					
						
							|  |  |  |  |                   target: '_blank', | 
					
						
							|  |  |  |  |                   rel: 'noopener noreferrer nofollow', | 
					
						
							|  |  |  |  |                   class: null, | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |               validate: undefined, | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       addAttributes() { | 
					
						
							|  |  |  |  |           return { | 
					
						
							|  |  |  |  |               href: { | 
					
						
							|  |  |  |  |                   default: null, | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |               target: { | 
					
						
							|  |  |  |  |                   default: this.options.HTMLAttributes.target, | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |               class: { | 
					
						
							|  |  |  |  |                   default: this.options.HTMLAttributes.class, | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       parseHTML() { | 
					
						
							|  |  |  |  |           return [ | 
					
						
							|  |  |  |  |               { tag: 'a[href]:not([href *= "javascript:" i])' }, | 
					
						
							|  |  |  |  |           ]; | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       renderHTML({ HTMLAttributes }) { | 
					
						
							|  |  |  |  |           return [ | 
					
						
							|  |  |  |  |               'a', | 
					
						
							|  |  |  |  |               core.mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), | 
					
						
							|  |  |  |  |               0, | 
					
						
							|  |  |  |  |           ]; | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       addCommands() { | 
					
						
							|  |  |  |  |           return { | 
					
						
							|  |  |  |  |               setLink: attributes => ({ chain }) => { | 
					
						
							|  |  |  |  |                   return chain() | 
					
						
							|  |  |  |  |                       .setMark(this.name, attributes) | 
					
						
							|  |  |  |  |                       .setMeta('preventAutolink', true) | 
					
						
							|  |  |  |  |                       .run(); | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |               toggleLink: attributes => ({ chain }) => { | 
					
						
							|  |  |  |  |                   return chain() | 
					
						
							|  |  |  |  |                       .toggleMark(this.name, attributes, { extendEmptyMarkRange: true }) | 
					
						
							|  |  |  |  |                       .setMeta('preventAutolink', true) | 
					
						
							|  |  |  |  |                       .run(); | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |               unsetLink: () => ({ chain }) => { | 
					
						
							|  |  |  |  |                   return chain() | 
					
						
							|  |  |  |  |                       .unsetMark(this.name, { extendEmptyMarkRange: true }) | 
					
						
							|  |  |  |  |                       .setMeta('preventAutolink', true) | 
					
						
							|  |  |  |  |                       .run(); | 
					
						
							|  |  |  |  |               }, | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       addPasteRules() { | 
					
						
							|  |  |  |  |           return [ | 
					
						
							|  |  |  |  |               core.markPasteRule({ | 
					
						
							|  |  |  |  |                   find: text => linkifyjs.find(text) | 
					
						
							|  |  |  |  |                       .filter(link => { | 
					
						
							|  |  |  |  |                       if (this.options.validate) { | 
					
						
							|  |  |  |  |                           return this.options.validate(link.value); | 
					
						
							|  |  |  |  |                       } | 
					
						
							|  |  |  |  |                       return true; | 
					
						
							|  |  |  |  |                   }) | 
					
						
							|  |  |  |  |                       .filter(link => link.isLink) | 
					
						
							|  |  |  |  |                       .map(link => ({ | 
					
						
							|  |  |  |  |                       text: link.value, | 
					
						
							|  |  |  |  |                       index: link.start, | 
					
						
							|  |  |  |  |                       data: link, | 
					
						
							|  |  |  |  |                   })), | 
					
						
							|  |  |  |  |                   type: this.type, | 
					
						
							|  |  |  |  |                   getAttributes: match => { | 
					
						
							|  |  |  |  |                       var _a; | 
					
						
							|  |  |  |  |                       return ({ | 
					
						
							|  |  |  |  |                           href: (_a = match.data) === null || _a === void 0 ? void 0 : _a.href, | 
					
						
							|  |  |  |  |                       }); | 
					
						
							|  |  |  |  |                   }, | 
					
						
							|  |  |  |  |               }), | 
					
						
							|  |  |  |  |           ]; | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       addProseMirrorPlugins() { | 
					
						
							|  |  |  |  |           const plugins = []; | 
					
						
							|  |  |  |  |           if (this.options.autolink) { | 
					
						
							|  |  |  |  |               plugins.push(autolink({ | 
					
						
							|  |  |  |  |                   type: this.type, | 
					
						
							|  |  |  |  |                   validate: this.options.validate, | 
					
						
							|  |  |  |  |               })); | 
					
						
							|  |  |  |  |           } | 
					
						
							|  |  |  |  |           if (this.options.openOnClick) { | 
					
						
							|  |  |  |  |               plugins.push(clickHandler({ | 
					
						
							|  |  |  |  |                   type: this.type, | 
					
						
							|  |  |  |  |               })); | 
					
						
							|  |  |  |  |           } | 
					
						
							|  |  |  |  |           if (this.options.linkOnPaste) { | 
					
						
							|  |  |  |  |               plugins.push(pasteHandler({ | 
					
						
							|  |  |  |  |                   editor: this.editor, | 
					
						
							|  |  |  |  |                   type: this.type, | 
					
						
							|  |  |  |  |               })); | 
					
						
							|  |  |  |  |           } | 
					
						
							|  |  |  |  |           return plugins; | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |   }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   exports.Link = Link; | 
					
						
							|  |  |  |  |   exports["default"] = Link; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Object.defineProperty(exports, '__esModule', { value: true }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | })); | 
					
						
							|  |  |  |  | //# sourceMappingURL=tiptap-extension-link.umd.js.map
 |