Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help with pasting markdown into editor #2874

Closed
1 task
sebpowell opened this issue Jun 12, 2022 · 1 comment
Closed
1 task

Help with pasting markdown into editor #2874

sebpowell opened this issue Jun 12, 2022 · 1 comment
Labels
Type: Feature The issue or pullrequest is a new feature

Comments

@sebpowell
Copy link

sebpowell commented Jun 12, 2022

What problem are you facing?

We're currently using Tiptap as the text editor for a new app we're building, and need it to support the ability for a user to either paste or enter some markdown.

Typing works (for instance, I can do ## Some text, and that will convert to a heading – ditto bold marks etc).

However, I can't seem to get pasting to work – e.g. if user pastes in some content from another editor – Notion for instance.

I had a look around, and found a couple of threads – namely this one: #337.

I couldn't get the example to work, but in any case, I'm not sure it's the right path to go down as I want to support this behaviour for different marks / nodes (images being another).

So, I eventually came across this example (not TipTap), where they've written their own ProseMirror plugin, and it would appear, something similar could be done in TipTap using the addProseMirrorPlugin property: https://github.com/outline/rich-markdown-editor/blob/main/src/plugins/PasteHandler.ts

And I've had some success with this approach – my code looks something like this:

export const EventHandler = Extension.create({
  name: "eventHandler",

  addProseMirrorPlugins() {
    return [
      new Plugin({
        key: new PluginKey("eventHandler"),
        props: {
          handlePaste(this, view, event, slice) {
            const regexMdLinks = /\[([^\[]+)\](\(.*\))/gm;

            const mdContents = `
  Lorem ipsum dolor sit amet, consectetur adipiscing elit..
  
  [hello link](/admin/table_edit/table_edit.cfm?action=edit&table_name=organizationsXcategories)
  
  Lorem ipsum dolor sit amet, consectetur adipiscing elit..
  
  [otherLink](https://google.com)
  
  Lorem ipsum dolor sit amet, consectetur adipiscing elit..
  
  [third link](https://google.com)
                `;

            const text = mdContents;

            const { state, dispatch } = view;

            const matches = mdContents.match(regexMdLinks);

            const singleMatch = /\[([^\[]+)\]\((.*)\)/;

            let updated = text;

            // Remove all markdown syntax
            for (var i = 0; i < matches.length; i++) {
              let text = singleMatch.exec(matches[i]);
              updated =
                updated.substring(0, updated.indexOf(matches[i])) +
                text[1] +
                updated.substring(
                  updated.indexOf(matches[i]) + matches[i].length
                );
            }

            const transaction = view.state.tr.insertText(
                updated,
                state.selection.from,
                state.selection.to
            );

            // Apply the link mark
            for (var i = 0; i < matches.length; i++) {
              let text = singleMatch.exec(matches[i]);

              transaction.addMark(
                state.selection.from + updated.indexOf(matches[i]),
                state.selection.to +
                  (updated.indexOf(matches[i]) + text[i].length),
                state.schema.marks.link.create({ href: text })
              );
            }

            view.dispatch(transaction);

            return true;
          },
        },
      }),
    ];
  },
});

The issue I'm now running into is the line breaks in the example markdown aren't preserved. So I assume I would need to do something like the above to convert paragraphs into nodes.

But I'm also wondering if I'm going about this the right way, and whether there's perhaps, a simpler way?

I also tried using MarkdownIt to convert the input into HTML, and then converting that HTML into JSON using the generateJSON helper, but that didn't seem to work either.

Any guidance would be greatly appreciated!

What’s the solution you would like to see?

I imagine there's a reason why the above hasn't been implemented as default, so not sure what to suggest here – I guess if the above is already doable, then updating the documentation to make this clearer would help.

What alternatives did you consider?

Nothing to add here.

Anything to add? (optional)

No response

Are you sponsoring us?

  • Yes, I’m a sponsor. 💖
@sebpowell sebpowell added the Type: Feature The issue or pullrequest is a new feature label Jun 12, 2022
@sebpowell sebpowell changed the title Paste markdown Help with pasting markdown into editor Jun 12, 2022
@sebpowell
Copy link
Author

sebpowell commented Jun 13, 2022

Turns out the solution for this was remarkably simple – the editor instance is available within the plugin, here's what my code looks like (and it works perfectly). Closing, but sharing this here in case it helps anyone.

export const EventHandler = Extension.create({
  name: "eventHandler",

  addProseMirrorPlugins() {
    const { editor } = this;

    return [
      new Plugin({
        key: new PluginKey("eventHandler"),
        props: {
          handlePaste() {
            const md = new MarkdownIt();

            const mdContents = `
Lorem ipsum dolor sit amet, consectetur adipiscing elit..

[hello link](/admin/table_edit/table_edit.cfm?action=edit&table_name=organizationsXcategories)

Lorem ipsum dolor sit amet, consectetur adipiscing elit..

[otherLink](https://google.com)

Lorem ipsum dolor sit amet, consectetur adipiscing elit..

[third link](https://google.com)
              `;

            editor.commands.insertContent(
              generateJSON(md.render(mdContents), [
                EventHandler,
                StarterKit,
                Link.configure({
                  openOnClick: false,
                }),
              ]),
              {
                parseOptions: {
                  preserveWhitespace: false,
                },
              }
            );

            return true;
          },
        },
      }),
    ];
  },
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature The issue or pullrequest is a new feature
Projects
None yet
Development

No branches or pull requests

1 participant