Ionaru / easy-markdown-editor

EasyMDE: A simple, beautiful, and embeddable JavaScript Markdown editor. Delightful editing for beginners and experts alike. Features built-in autosaving and spell checking.
https://stackblitz.com/edit/easymde
MIT License
2.45k stars 319 forks source link

TOC feature via markedOptions: Uncaught ReferenceError: marked is not defined #295

Closed Offerel closed 3 years ago

Offerel commented 3 years ago

If im right EasyMDE uses marked to preview the Markdown. I have found at https://github.com/markedjs/marked/issues/545 a nice solution to generate a TOC from the markdownfile. If i understand https://github.com/Ionaru/easy-markdown-editor/issues/2 right, this is exactly, where i could insert the TOC feature. But if i try it, i get the error message:

Uncaught ReferenceError: marked is not defined

I have the following code now:

var renderer = new marked.Renderer();
var toc = [];

renderer.heading = function(text, level, raw) {
var anchor = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w]+/g, '-');
toc.push({
    anchor: anchor,
    level: level,
    text: text
});
return '<h'
    + level
    + ' id="'
    + anchor
    + '">'
    + text
    + '</h'
    + level
    + '>\n';
};

var mde = new EasyMDE({
        element: document.getElementById('myeditor'),
        autoDownloadFontAwesome: false,
        autofocus: true,
        spellChecker: false,
        autofocus: true,
        status: false,
        promptURLs: true,
        renderingConfig: {
            codeSyntaxHighlighting: true,
            markedOptions: {
                renderer: renderer,
            }
        },...

I'm sure that have understand it wrong, can you please point me to right direction? BTW: I'm using release 2.13.0

Offerel commented 3 years ago

I have created a small workaround to create a ToC, maybe that's helpful for others. This will create a button and appends this to a already existing div, to toggle the ToC menu. For toggling, I'm using a class, what disables/enables the ToC div. The button and the div will only appended, if the script finds some headings from the render preview. If you click on of the links, it will jump to the heading. Sure, you must fine-tune it a little bit, but basically it should work.

var headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
    if(headings.length > 0) {
        let tbutton = document.createElement('button');
        tbutton.id = 'tbutton';
        tbutton.innerText = 'ToC';
        document.getElementById('main_header').appendChild(tbutton);

        let tocdiv = document.createElement('div');
        tocdiv.id = 'tocdiv';
        let o = 0;
        let a = 0;
        let list = 'c%';
        headings.forEach(function(element){
            a = element.tagName.substr(1,1);
            if(o < a) {
                list = list.replace('c%','<li><ul><li><a title="'+element.innerText+'" href="#' + element.id + '">' + element.innerText + '</a></li>c%</ul></li>');
            } else if(o > a) {
                list = list.replace('c%','</ul><li><a title="'+element.innerText+'" href="#' + element.id + '">' + element.innerText + '</a></li>c%');
            } else {
                list = list.replace('c%','<li><a title="'+element.innerText+'" href="#' + element.id + '">' + element.innerText + '</a></li>c%');
            }
            o = a;
        });
        list = list.replace('c%</ul>','');
        tocdiv.innerHTML = list;

        tbutton.addEventListener('click', function(e) {
            e.preventDefault();
            tocdiv.classList.toggle('tdhidden');
        });

        document.querySelector('.EasyMDEContainer').appendChild(tocdiv);

        document.querySelectorAll('#tocdiv a').forEach(function(elem) {
            elem.addEventListener('click', function(){
                tocdiv.classList.toggle('tdhidden');
            });
        });
}