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 3 forks source link

Mismatched Transaction #1

Open AaronAnz opened 10 months ago

AaronAnz commented 10 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 10 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 10 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 3 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.

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

AaronAnz commented 3 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.

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);
    }