Pasting text from Google Doc always pastes as <strong> text

1 Answer 25 Views
Editor
Vincent
Top achievements
Rank 3
Iron
Iron
Iron
Vincent asked on 23 Feb 2024, 02:06 PM

Hello,


I'm trying to get the Kendo Vue Editor to be able to accept pasted content from a Google Doc. 
However when trying to copy paste from there the text in the clipboard is wrapped in a <b style="font-weight: normal"> tag.

This is a known issue for the ProseMirror devs and they have a fix for it. 
Simple Copy Paste from google docs yields bold text · Issue #459 · ProseMirror/prosemirror (github.com)

If you try the editor example on ProseMirror.com you can safely paste text from Google Doc and it won't be converted to <strong>:
ProseMirror basic example

It seems it's able to do so correctly because of this ProseMirror schema change:
Don't treat <b style=font-weight: normal> as strong · ProseMirror/prosemirror-schema-basic@cbbdc1a (github.com)

prosemirror-schema-basic/src/schema-basic.ts at master · ProseMirror/prosemirror-schema-basic (github.com)


However when I try to load this schema-basic schema it doesn't work as intended and Google Doc text is still converted to <strong> text

Here is my attempt so far:
Yrawzh (forked) - StackBlitz

 

What's the best way to fix this issue?

1 Answer, 1 is accepted

Sort by
0
Vessy
Telerik team
answered on 28 Feb 2024, 02:12 PM

Hi, Vincent,

The faced strong/b tag is coming with each copied content from Google Docs, therefore the Editor also render it after pasting. A possible approach you can use to fix it is to handle the Editor's onPasteHtml event and remove the <b> nodes that have "font-weight:normal" style (persistd in each of the undesired b tags). For example, you can have a similar setup:

    htmlToFragment(html) {
      const template = document.createElement('template');
      template.innerHTML = html;
      return template.content;
    },
    fragmentToHtml(fragment){
      return Array.from(fragment.childNodes).reduce(
        (acc, cur) => acc + ((cur as Element).outerHTML || cur.textContent || ''),
        ''
      );
    },
    removeNode(node){
      const parentNode = node.parentNode;
      if (parentNode) {
        while (node.firstChild) {
          parentNode.insertBefore(node.firstChild, node);
        }
        parentNode.removeChild(node);
      }
    },
    onPasteHtml(event) {
      let html = pasteCleanup(sanitize(event.pastedHtml), pasteSettings);
        const fragment = this.htmlToFragment(html);
        fragment
          .querySelectorAll('b[style="font-weight: normal;"]')
          .forEach(this.removeNode);

        html = this.fragmentToHtml(fragment);

        return html;
    },

I hope the provided solution will be helpful for you but do let me know if I can assist you any further on this.

Regards,
Vessy
Progress Telerik

Stay tuned by visiting our public roadmap and feedback portal pages! Or perhaps, if you are new to our Kendo family, check out our getting started resources

Vincent
Top achievements
Rank 3
Iron
Iron
Iron
commented on 01 Mar 2024, 09:59 AM

Hello Vessy,

 

Thanks for the solution you posted, there was one issue with your solution, it doesnt completely clear all the styles from the pasted google doc text. As a result some text would be in font-family Calibri and a different font-size.

To fix this I added a second sanitize call to process the html returned from fragmentToHtml, in this call I remove all the styles and classes added by google docs.

The drawback is that this solution is very intensive and hard to read.

Is there really no chance to simply extend the prosemirror schema to handle the google docs case? 

Vessy
Telerik team
commented on 06 Mar 2024, 09:29 AM

Hi, Vincent,

Thank you for sharing your solution - I am glad that you have managed to find an approach that strips all undesired google docs content at your side. Unfortunately, this is the optimal solution at the moment and there is no way to customize the schema for this specific scenario at the moment.

Tags
Editor
Asked by
Vincent
Top achievements
Rank 3
Iron
Iron
Iron
Answers by
Vessy
Telerik team
Share this question
or