'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var core = require('@tiptap/core');
var linkifyjs = require('linkifyjs');
var prosemirrorState = require('prosemirror-state');

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;
//# sourceMappingURL=tiptap-extension-link.cjs.map
