HMarzban / extension-hyperlink

A powerful and customizable hyperlink extension for Tiptap Editor, offering enhanced functionality similar to Google Docs link plugin.
MIT License
26 stars 2 forks source link

Mismatched Transaction #1

Open AaronAnz opened 7 months ago

AaronAnz commented 7 months ago

Was interested in trying this plugin because the default one is lacking the ability to easily set the text for a link and I didnt want to bake my own solution but when I run :

this.tiptap
    .chain()
    .focus()
    .extendMarkRange('hyperlink')
    .editHyperlink({
            newURL: "https://google.com", 
            newText: "Testing" })
    .run();

results in "HResult=0x80131500 Message=Applying a mismatched transaction".

and so does this:

this.tiptap
    .commands
    .editHyperlink({
        newURL: url,
        newText: text
    });
this.tiptap = new Editor({
  element: tipTapElement,
  extensions: [
      Hyperlink.configure({
        autoHyperlink: true,
        hyperlinkOnPaste: true,
        openOnClick: false,
        HTMLAttributes: {
            class: "mud-typography mud-link mud-primary-text mud-link-underline-hover mud-typography-body1"
        }
    })
  ]
});
"dependencies": {
  "@tiptap/core": "^2.1.11",
  "@tiptap/pm": "^2.1.11",
  "@tiptap/starter-kit": "^2.1.11",
  "@tiptap/extension-bubble-menu": "^2.1.11",
  "@tiptap/extension-character-count": "^2.1.11",
  "@tiptap/extension-color": "^2.1.11",
  "@tiptap/extension-font-family": "^2.1.11",
  "@tiptap/extension-highlight": "^2.1.11",
  "@tiptap/extension-image": "^2.1.11",
  "@tiptap/extension-placeholder": "^2.1.11",
  "@tiptap/extension-subscript": "^2.1.11",
  "@tiptap/extension-superscript": "^2.1.11",
  "@tiptap/extension-table": "^2.1.11",
  "@tiptap/extension-table-cell": "^2.1.11",
  "@tiptap/extension-table-header": "^2.1.11",
  "@tiptap/extension-table-row": "^2.1.11",
  "@tiptap/extension-text-align": "^2.1.11",
  "@tiptap/extension-typography": "^2.1.11",
  "@tiptap/extension-underline": "^2.1.11",
  "@docs.plus/extension-hyperlink": "1.5.2"
}
HMarzban commented 7 months ago

Hi, as demonstrated in the example here, it works, and I have tested a bunch of other methods. However, I did not encounter that error! It would be great to see it in action or to review the main code.

AaronAnz commented 7 months ago

Strange. I am using Blazor which is a pretty unique frontend but every single plugin for tiptap works fine but yours. Unable to get a dumbed down example at the moment, I ended up just writing my own function to handle setting it.

SENNQQ commented 2 weeks ago

Strange. I am using Blazor which is a pretty unique frontend but every single plugin for tiptap works fine but yours. Unable to get a dumbed down example at the moment, I ended up just writing my own function to handle setting it.

Hi, could you please share your implementation. I am also facing mismatched transaction and can't figure out how to fix it.

AaronAnz commented 2 weeks ago

Strange. I am using Blazor which is a pretty unique frontend but every single plugin for tiptap works fine but yours. Unable to get a dumbed down example at the moment, I ended up just writing my own function to handle setting it.

Hi, could you please share your implementation. I am also facing mismatched transaction and can't figure out how to fix it.

I got busy and kind of abandoned working on the project for a while and hadn't fully finished everything but here is some probably broken ass code which can point you in the direction I was heading

import Link from '@tiptap/extension-link'                   // https://tiptap.dev/api/marks/link
Link.extend({ inclusive: false }).configure({
                    autolink: true,
                    HTMLAttributes: {
                        class: "mud-typography mud-link mud-primary-text mud-link-underline-hover mud-typography-body1"
                    },
                    linkOnPaste: true,
                    openOnClick: false,
                }),
    public editLink = (url, text, target) => {
        var link = this.getFocusedAnchorTag();

        const nodePos = this.tiptap.view.posAtDOM(link, 0);

        var transaction = this.tiptap.view.state.tr;

        transaction.deleteRange(nodePos, nodePos + (link?.innerText || "")?.length).replaceWith(
            nodePos,
            nodePos,
            this.tiptap.schema.text(text, [
                this.tiptap.schema.marks.link.create({
                    href: url,
                }),
            ])
        );

        this.tiptap.view.dispatch(transaction);
    }

    public getFocusedAnchorTag = () => {
        if (this.tiptap.isActive('link')) {
            const { state, dispatch } = this.tiptap.view;
            const { from, to } = state.selection;

            let link: HTMLAnchorElement | null = null;

            var test = (to - 1 <= from) ? from : to - 1; 
            const selectedNode = this.tiptap.view.domAtPos(test).node as HTMLElement;
            const nodeName = selectedNode?.nodeName;

            if (nodeName === "#text") {
                return (selectedNode.parentNode as HTMLElement)?.closest("a");
            } else {
                return selectedNode?.closest("a");
            }
        }

        return null;
    }

    public setLink = (url, text, target) => {
        if (this.tiptap.isActive('link')) {
            // get the focused anchor tag element
            var link = this.getFocusedAnchorTag();

            // get bounds of anchor tag text
            const nodePos = this.tiptap.view.posAtDOM(link, 0);
            var startPos = nodePos;
            var endPos = nodePos + (link?.innerText ?? "").length;
        } else {
            // get current selection bounds
            var selection = this.tiptap.state.selection;
            var startPos = selection.$from.pos;
            var endPos = selection.$to.pos;
        }

        // create a new transaction
        var transaction = this.tiptap.view.state.tr;

        // set transaction to replace range
        transaction.replaceWith(
            startPos,
            endPos,
            // set text
            this.tiptap.schema.text(text, [
                // set link mark
                this.tiptap.schema.marks.link.create({
                    href: url,
                }),
            ])
        );

        // dispatch the transaction to the editor.
        this.tiptap.view.dispatch(transaction);
    }