Skip to content

Copy / paste mathtype formul on ckeditor #1101

@fauguste

Description

@fauguste

Description

When you copy/paste a mathtype formula into ckeditor (without opening the mathtype editor), you end up with two elements in ckeditor: the image of the formula and the formula;

Reproductible on https://ckeditor.com/mathtype/

Environment

  • ckdeditor : 45.1.0
  • mathtype-ckeditor5 : ^8.13.1

What is the relevant software and their versions?

  • _Editor : CKEditor
  • _Browser : Chrome
  • _Operating System : Windows

Steps to reproduce

  1. copy a mathtype formula in ckeditor
  2. past the mathtype formula in ckeditor

Expected result

only mathtype formula should be display

Actual result

two mathtype formula is display : An image and a formula

Other details

my working patch 👍

function normalizeSpecialCharacters(inputText) {
  if (typeof inputText !== 'string') {
    // If the input is not a string (e.g., null, undefined, number),
    // return it as is or an empty string, depending on desired behavior.
    // Here, returning it as is or an empty string if null/undefined.
    return inputText === null || inputText === undefined ? '' : String(inputText);
  }

  let result = inputText;
  result = result.replace(/«/g, '<'); // Replace « (U+00AB) with < (U+003C)
  result = result.replace(/»/g, '>'); // Replace » (U+00BB) with > (U+003E)
  result = result.replace(/§/g, '&'); // Replace § (U+00A7) with & (U+0026)
  result = result.replace(/¨/g, '"'); // Replace ¨ (U+00A8) with " (U+0022)
  result = result.replace(/`/g, "'"); // Replace ` (U+0060) with ' (U+0027)

  return result;
}

editor.plugins.get( 'ClipboardPipeline' ).on( 'inputTransformation', ( evt, data ) => {
    const htmlContent = data.dataTransfer.getData( 'text/html' );

    if ( !htmlContent ) {
        return; // No HTML content to process
    }

    let mathml = null;
    let isMathTypeContent = false;

    // 1. Try to detect an image with the data-mathml attribute
    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = htmlContent;

    const mathTypeImage = tempDiv.querySelector('img[data-mathml]');

    if ( mathTypeImage ) {
        const rawMathml = mathTypeImage.getAttribute('data-mathml');
        if (rawMathml) {
            const textPara = document.createElement('p');
            textPara.innerHTML = rawMathml; // The browser decodes HTML entities here
            mathml = textPara.textContent || textPara.innerText || "";
            isMathTypeContent = true;
            console.log('MathType Image with data-mathml detected. Extracted MathML:', mathml);
        }
    }

    // 2. If no image, look for raw MathML (math tag)
    if ( !isMathTypeContent ) {
        // Basic regex to find the first <math>...</math> tag
        const mathmlRegex = /(<math[\s\S]*?<\/math>)/i;
        const match = htmlContent.match(mathmlRegex);
        if (match && match[1]) {
            mathml = match[1];
            isMathTypeContent = true;
            console.log('Raw MathML detected:', mathml);
        }
    }

    // 3. If MathType content was found, transform data.content
    if ( isMathTypeContent && mathml ) {
        try {
            // Use editor.data.processor.toView() to convert the MathML string
            // into a ViewDocumentFragment. This is the idiomatic and correct way.
            const mathmlViewFragment = editor.data.processor.toView(normalizeSpecialCharacters(mathml));

            // Replace the existing content of data.content with the new fragment.
            // data.content is a ViewDocumentFragment.
            data.content = mathmlViewFragment;

            console.log('Replaced data.content with MathML ViewDocumentFragment for MathType plugin to process.');
            // evt.stop(); // Uncomment if you want to explicitly stop further processing of this data.

        } catch (e) {
            console.error("Error parsing MathML with editor.data.processor.toView:", e);
            // In case of an error (e.g., malformed MathML), do not modify data.content
            // to let CKEditor handle the original content (which will likely be the image).
        }
    }
});

Is there anything else to consider?

Metadata

Metadata

Assignees

No one assigned

    Labels

    type:bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions