dimakorotkov / tinymce-mathjax

Tinymce plugin for MathJax
40 stars 19 forks source link

Uncaught TypeError: Cannot read property 'getComponents' of undefined #2

Open rsp4jack opened 4 years ago

rsp4jack commented 4 years ago

(Sorry, English isn't my mother language) (This Error is trigger on open the Mathjax panel)

Uncaught TypeError: Cannot read property 'getComponents' of undefined
    at xN.<anonymous> (plugin.min.js:formatted:71)
    at FS.fire (tinymce.min.js:9)
    at xN.fire (tinymce.min.js:9)
    at rm (tinymce.min.js:9)
    at Object.insertContent (tinymce.min.js:9)
    at yS (tinymce.min.js:9)
    at mceInsertContent (tinymce.min.js:9)
    at LS.execCommand (tinymce.min.js:9)
    at xN.execCommand (tinymce.min.js:9)
    at xN.insertContent (tinymce.min.js:9)
    at Object.c [as onSubmit] (plugin.min.js:formatted:130)
    at theme.min.js:9
    at theme.min.js:9
    at theme.min.js:9
    at Object.each (theme.min.js:9)
    at u (theme.min.js:9)
    at theme.min.js:9
    at theme.min.js:9
    at theme.min.js:9
    at theme.min.js:9
    at Object.fold (theme.min.js:9)
    at Mb (theme.min.js:9)
    at Ab (theme.min.js:9)
    at Ib (theme.min.js:9)
    at theme.min.js:9
    at Nu (theme.min.js:9)
    at ju (theme.min.js:9)
    at Object.triggerEvent (theme.min.js:9)
    at Go (theme.min.js:9)
    at Lo (theme.min.js:9)
    at theme.min.js:9
    at theme.min.js:9
    at theme.min.js:9
    at it (theme.min.js:9)
    at run (theme.min.js:9)
    at theme.min.js:9
    at theme.min.js:9
    at theme.min.js:9
    at Object.fold (theme.min.js:9)
    at Mb (theme.min.js:9)
    at Ab (theme.min.js:9)
    at Ib (theme.min.js:9)
    at theme.min.js:9
    at Nu (theme.min.js:9)
    at ju (theme.min.js:9)
    at Object.triggerEvent (theme.min.js:9)
    at Go (theme.min.js:9)
    at Lo (theme.min.js:9)
    at Uo (theme.min.js:9)
    at t (theme.min.js:9)
    at theme.min.js:9
    at it (theme.min.js:9)
    at run (theme.min.js:9)
    at theme.min.js:9
    at theme.min.js:9
    at theme.min.js:9
    at Object.fold (theme.min.js:9)
    at Mb (theme.min.js:9)
    at Ab (theme.min.js:9)
    at Ib (theme.min.js:9)
    at theme.min.js:9
    at Nu (theme.min.js:9)
    at ju (theme.min.js:9)
    at Object.triggerEvent (theme.min.js:9)
    at theme.min.js:9
    at HTMLDivElement.a (theme.min.js:9)
b.on("SetContent", function(c) {
        if (b.getDoc().defaultView.MathJax) {
>>       b.getDoc().defaultView.MathJax.startup.getComponents();
            b.getDoc().defaultView.MathJax.typeset()
        }
    });

Using CodePen: TinyMCE:https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.3.2/tinymce.min.js Mathjax:https://cdn.jsdelivr.net/npm/mathjax@3.0.5/es5/tex-mml-chtml.js tinymce-mathjax:https://cdn.jsdelivr.net/npm/@dimakorotkov/tinymce-mathjax@1.0.4/config.js Tinymce Init Config:

tinymce.init({
  "selector": "div#tinymcew",
  "plugins": [
    "print",
    "preview",
    "fullpage",
    "powerpaste",
    "noneditable",
    "searchreplace",
    "autolink",
    "directionality",
    "advcode",
    "visualblocks",
    "visualchars",
    "fullscreen",
    "image",
    "link",
    "media",
    "mediaembed",
    "template",
    "codesample",
    "table",
    "advtable",
    "charmap",
    "hr",
    "pagebreak",
    "nonbreaking",
    "anchor",
    "toc",
    "insertdatetime",
    "advlist",
    "lists",
    "checklist",
    "wordcount",
    "tinymcespellchecker",
    "a11ychecker",
    "imagetools",
    "textpattern",
    "help",
    "formatpainter",
    "permanentpen",
    "pageembed",
    "tinycomments",
    "mentions",
    "linkchecker",
    "casechange",
  ], 
  browser_spellcheck: true,
  external_plugins: {'mathjax': 'https://cdn.jsdelivr.net/npm/@dimakorotkov/tinymce-mathjax@1.0.4/plugin.min.js'},
  contextmenu: false,
  mathjax: {
    lib: 'https://cdn.jsdelivr.net/npm/mathjax@3.0.5/es5/tex-mml-chtml.js', //required path to mathjax
    className: "math-tex", //optional: mathjax element class
   configUrl: "https://cdn.jsdelivr.net/npm/@dimakorotkov/tinymce-mathjax@1.0.4/config.js",
  },
  "toolbar": "formatselect | fontselect | bold italic strikethrough forecolor backcolor formatpainter | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | link insertfile image mathjax | removeformat | code | addcomment | checklist | casechange",
  "toolbar_mode": "floating",
  "menubar": "file edit insert view format table tools help",
  "menu": {
    "edit": {
      "title": "Edit",
      "items": "undo redo | cut copy paste pastetext | selectall | searchreplace"
    }
  },
  "tinycomments_mode": "embedded",
  "noneditable_noneditable_class": "mceNonEditable",
  "image_advtab": true,
  "resize": "both",
  height: 340,
  width: 960,
})

In the preview it worked, but it can't display in tinymce text box, it's displayed:\( f\left( \left[ \frac{ 1+\left\{x,y\right\} }{ \left( \frac{x}{y}+\frac{y}{x} \right) \left(u+1\right) }+a \right]^{3/2} \right) \) After waiting a while to type or refresh a few times, it will display normally. What causes this? How can I solve this problem? Maybe because the Network Delay? (I lived in China)

folkevil commented 4 years ago

I got the same problem, debugged 1 day and still don't know why :(

rsp4jack commented 4 years ago

When I use the cdnjs, this error isn't happens.(But it still happens sometimes)(TinyMCE use the cdnjs not this plugins)

daakbahok commented 3 years ago

Is it around line 166? I think 2 lines need to be wrapped with an if statement.

if(editor.getDoc().defaultView.MathJax){ editor.getDoc().defaultView.MathJax.startup.getComponents(); editor.getDoc().defaultView.MathJax.typeset(); }

mqingqing123 commented 3 years ago

here is code: .html: `

tinymce.init({ selector: ".editor", external_plugins: { 'mathjax': 'plugin.js' }, mathjax: { lib: 'tex-mml-chtml.js' } }, ` The key point is: html use tex-chtml-full.js but addin use tex-mml-chtml.js

rsp4jack commented 3 years ago

Maybe it can fix this issue, but I think it isn't a beautiful means.

BeLi4L commented 2 years ago

Isn't it because you defined your MathJax config after loading mathjax?

That would explain why MathJax.startup is undefined ;)

FNugrohoSr commented 2 years ago

Is it around line 166? I think 2 lines need to be wrapped with an if statement.

if(editor.getDoc().defaultView.MathJax){ editor.getDoc().defaultView.MathJax.startup.getComponents(); editor.getDoc().defaultView.MathJax.typeset(); }

I get it working by doing it like this:

if(editor.getDoc().defaultView.MathJax && editor.getDoc().defaultView.MathJax.startup){ editor.getDoc().defaultView.MathJax.startup.getComponents(); editor.getDoc().defaultView.MathJax.typeset(); }

Edit: Still doesn't work. It doesn't typeset (obviously)

ajuszczyk commented 2 years ago

We fixed this issue by not including the tex-mml-chtml.js on every page but just where it is required to display the math notation. The tinyMCE plugin doesn't like it when it is twice there, once as a script included on the page and again when it was loaded with this plugin. Hope this makes sense :)

FNugrohoSr commented 2 years ago

We fixed this issue by not including the tex-mml-chtml.js on every page but just where it is required to display the math notation. The tinyMCE plugin doesn't like it when it is twice there, once as a script included on the page and again when it was loaded with this plugin. Hope this makes sense :)

So what if I want to display math on the same page as the TinyMCE editor?

ajuszczyk commented 2 years ago

That's a good point. We only needed it to display the math notations inside the tinyMCE. The issue could be replicated in Chrome browser and only with DevTools closed. With the DevTools opened all worked fine so I suspect some issue with the Chrome itself.

FNugrohoSr commented 2 years ago

That's a good point. We only needed it to display the math notations inside the tinyMCE. The issue could be replicated in Chrome browser and only with DevTools closed. With the DevTools opened all worked fine so I suspect some issue with the Chrome itself.

I suppose we could do without math inside tinyMCE if it means the math outside will display fine. About replicating the issue, it's not the DevTools, it's the "Disable cache" settings. If you uncheck the "Disable cache" settings it will throw the error just like when the DevTools is closed.

jsmithangular commented 1 year ago

@Creepercdn , did you resolved this? I have same issue

mqingqing123 commented 1 year ago

here is for tinymce6 config.js

let className = 'math-tex'; if (document.currentScript) { let urlParts = document.currentScript.getAttribute('src').split('?'); if (urlParts[1]) { let queryParams = urlParts[1].split('&'); for (let i = 0; i < queryParams.length; i++) { let param = queryParams[i].split('='); if (param[0] == 'class') { className = param[1]; break; } } } } MathJax = { options: { processHtmlClass: className, ignoreHtmlClass: '.*', M:window.MathJax } };

plugin.js

tinymce.PluginManager.add('mathjax', function (editor, url) {

// plugin configuration options
let settings = editor.getParam('mathjax');
let mathjaxClassName = settings.className || "math-tex";
let mathjaxTempClassName = mathjaxClassName + '-original';
let mathjaxSymbols = settings.symbols || { start: '\\(', end: '\\)' };
let mathjaxUrl = settings.lib || null;
let mathjaxConfigUrl = (settings.configUrl || url + '/config.js') + '?class=' + mathjaxTempClassName;
let mathjaxScripts = [mathjaxConfigUrl];
if (mathjaxUrl) {
    mathjaxScripts.push(mathjaxUrl);
}

// load mathjax and its config on editor init
editor.on('init', function () {
    console.log("GetContent");
    let scripts = editor.getDoc().getElementsByTagName('script');
    for (let i = 0; i < mathjaxScripts.length; i++) {
        // check if script have already loaded
        let id = editor.dom.uniqueId();
        let script = editor.dom.create('script', { id: id, type: 'text/javascript', src: mathjaxScripts[i] });
        let found = false;
        for (let j = 0; j < scripts.length; j++) {
            if (scripts[j].src == script.src) {
                found = true;
                break;
            }
        }
        // load script
        if (!found) {
            editor.getDoc().getElementsByTagName('head')[0].appendChild(script);
        }
    }
});

// remove extra tags on get content
editor.on('GetContent', function (e) {
    console.log("GetContent");
    let div = editor.dom.create('div');
    div.innerHTML = e.content;
    let elements = div.querySelectorAll('.' + mathjaxClassName);
    for (let i = 0; i < elements.length; i++) {
        let children = elements[i].querySelectorAll('span');
        for (let j = 0; j < children.length; j++) {
            children[j].remove();
        }
        let latex = elements[i].getAttribute('data-latex');
        elements[i].removeAttribute('contenteditable');
        elements[i].removeAttribute('style');
        elements[i].removeAttribute('data-latex');
        elements[i].innerHTML = latex;
    }
    e.content = div.innerHTML;
});

let checkElement = function (element) {
    if (element.childNodes.length != 2) {
        element.setAttribute('contenteditable', false);
        element.style.cursor = 'pointer';
        let latex = element.getAttribute('data-latex') || element.innerHTML;
        element.setAttribute('data-latex', latex);
        element.innerHTML = '';

        let math = editor.dom.create('span');
        math.innerHTML = latex;
        math.classList.add(mathjaxTempClassName);
        element.appendChild(math);

        let dummy = editor.dom.create('span');
        dummy.classList.add('dummy');
        dummy.innerHTML = 'dummy';
        dummy.setAttribute('hidden', 'hidden');
        element.appendChild(dummy);
    }
};

// add dummy tag on set content
editor.on('BeforeSetContent', function (e) {
    console.log("BeforeSetContent");
    let div = editor.dom.create('div');
    div.innerHTML = e.content;
    let elements = div.querySelectorAll('.' + mathjaxClassName);
    for (let i = 0; i < elements.length; i++) {
        checkElement(elements[i]);
    }
    e.content = div.innerHTML;
});

// refresh mathjax on set content
editor.on('SetContent', function (e) {
    console.log("SetContent");
    if (editor.getDoc().defaultView.MathJax) {
        if (editor.getDoc().defaultView.MathJax.options.M) {
            editor.getDoc().defaultView.MathJax.options.M.typesetPromise();
        }
    }
});

// refresh mathjax on any content change
editor.on('Change', function (data) {
    console.log("Change");
    elements = editor.dom.getRoot().querySelectorAll('.' + mathjaxClassName);
    if (elements.length) {
        for (let i = 0; i < elements.length; i++) {
            checkElement(elements[i]);
        }

        if (editor.getDoc().defaultView.MathJax) {
            editor.getDoc().defaultView.MathJax.options.M.typesetPromise();
        }

    }
});

// add button to tinimce
editor.ui.registry.addToggleButton('mathjax', {
    text: '数学公式',
    tooltip: 'Mathjax',
    onAction: function () {
        let selected = editor.selection.getNode();
        let target = undefined;
        if (selected.classList.contains(mathjaxClassName)) {
            target = selected;
        }
        openMathjaxEditor(target);
    },
    onSetup: function (buttonApi) {
        return editor.selection.selectorChangedWithUnbind('.' + mathjaxClassName, buttonApi.setActive).unbind;
    }
});

// handle click on existing
editor.on("click", function (e) {
    let closest = e.target.closest('.' + mathjaxClassName);
    if (closest) {
        openMathjaxEditor(closest);
    }
});

// open window with editor
let openMathjaxEditor = function (target) {
    console.log(target);
    let mathjaxId = editor.id + '_' + editor.dom.uniqueId();

    let latex = '';
    if (target) {
        latex_attribute = target.getAttribute('data-latex');

      //  console.log("latex_attribute is" + latex_attribute);

        if (latex_attribute.length >= (mathjaxSymbols.start + mathjaxSymbols.end).length) {
            latex = latex_attribute.substr(mathjaxSymbols.start.length, latex_attribute.length - 1-(mathjaxSymbols.start + mathjaxSymbols.end).length);
        }
    }

    // show new window
    editor.windowManager.open({
        title: 'Mathjax',
        width: 600,
        height: 330,
        body: {
            type: 'panel',
            items: [

                {
                    type: 'htmlpanel',
                    html: '<div style="font-size:12px"> <input onclick=changesybol() type=checkbox id=cb_br name=cb_br>换行                 <a href="https://www.cnblogs.com/mqingqing123/p/12063096.html" target="blank" >LaTex说明</a>   <a href="http://www.dotnetcms.org" target="blank" >启明星官网</a>  </div>'
                },
                {
                    type: 'textarea',
                    name: 'title'
                }, {
                    type: 'htmlpanel',
                    html: '<iframe id="' + mathjaxId + '" style="width: 100%; min-height: 50px;"></iframe>'
                }]
        },
        buttons: [{ type: 'submit', text: 'OK' }],
        onSubmit: function onsubmit(api) {
            let value = api.getData().title.trim();
            if (target) {
                target.innerHTML = '';
                target.setAttribute('data-latex', getMathText(value));
                checkElement(target);
            } else {
                let newElement = editor.getDoc().createElement('span');
                newElement.innerHTML = getMathText(value);
                newElement.classList.add(mathjaxClassName);
                checkElement(newElement);
                editor.insertContent(newElement.outerHTML);
            }

            //fix
            //  editor.getDoc().defaultView.MathJax.startup.getComponents();
            // editor.getDoc().defaultView.MathJax.typeset();

            if (editor.getDoc().defaultView.MathJax) {
                editor.getDoc().defaultView.MathJax.options.M.typesetPromise();
            }

            api.close();
        },
        onChange: function (api) {
            var value = api.getData().title.trim();
            if (value != latex) {
                refreshDialogMathjax(value, document.getElementById(mathjaxId));
                latex = value;
            }
        },
        initialData: { title: latex }
    });

    if (mathjaxSymbols.start == "\\(") {
        document.getElementById("cb_br").checked = false;
    }
    else {
        document.getElementById("cb_br").checked = true;
    }

    // console.log(mathjaxSymbols);

    // add scripts to iframe
    let iframe = document.getElementById(mathjaxId);

    let iframeWindow = iframe.contentWindow || iframe.contentDocument.document || iframe.contentDocument;
    let iframeDocument = iframeWindow.document;
    let iframeHead = iframeDocument.getElementsByTagName('head')[0];
    let iframeBody = iframeDocument.getElementsByTagName('body')[0];

    // get latex for mathjax from simple text
    let getMathText = function (value, symbols) {
        if (!symbols) {
            symbols = mathjaxSymbols;
        }

        if (document.getElementById("cb_br").checked) {
            symbols = { start: '\\[', end: '\\] ' };
        }
        else {
            symbols = { start: '\\(', end: '\\) ' };
        }

        return symbols.start + ' ' + value + ' ' + symbols.end;
    };

    // refresh latex in mathjax iframe
    let refreshDialogMathjax = function (latex) {
        let MathJax = iframeWindow.MathJax;
        let div = iframeBody.querySelector('div');
        if (!div) {
            div = iframeDocument.createElement('div');
            div.classList.add(mathjaxTempClassName);
            iframeBody.appendChild(div);
        }
        div.innerHTML = getMathText(latex, { start: '$$', end: '$$' });

        if (MathJax && MathJax.startup) {
            console.log(MathJax);
            //MathJax.startup.getComponents();
            MathJax.typesetPromise();

        }

    };
    refreshDialogMathjax(latex);

    // add scripts for dialog iframe
    for (let i = 0; i < mathjaxScripts.length; i++) {
        let node = iframeWindow.document.createElement('script');
        node.src = mathjaxScripts[i];
        node.type = 'text/javascript';
        node.async = false;
        node.charset = 'utf-8';
        iframeHead.appendChild(node);
    }

};

});

function changesybol() { if (document.getElementById("cb_br").checked) { mathjaxSymbols = { start: '\[', end: '\] ' }; } else { mathjaxSymbols = { start: '\(', end: '\) ' }; }

}