在 EasyMDE 里添加数学表达式支持和表格快速对齐

语言: CN / TW / HK

最近试用了一些 markdown 编辑器,之前最有名的是 simplemde , 2017 年之后未更新,有人在此基础上做了个 easymde ,现在还有一些更新。

这个东西的一个问题是不支持数学公式。幸好它的自定义能力比较强,我用 Katex 给它加了数学表达式的支持。

首先添加一大堆依赖:

<script src="http://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>

<link rel="stylesheet" href="http://cdn.jsdelivr.net/highlight.js/latest/styles/tomorrow.min.css">
<script src="http://cdn.jsdelivr.net/highlight.js/latest/highlight.min.js"></script>

<link href="http://cdn.bootcss.com/KaTeX/0.11.1/katex.min.css" rel="stylesheet">
<script src="http://cdn.bootcss.com/KaTeX/0.11.1/katex.min.js" ></script>

<link rel="stylesheet" href="http://unpkg.com/easymde/dist/easymde.min.css">
<script src="http://unpkg.com/easymde/dist/easymde.min.js"></script>

然后引入下面函数:

<script>
function easymdn_katex_wrap(ele, config, markedOptions) {
    markedOptions = {
        renderer: new marked.Renderer(),
        highlight: function(code, language) {
            const validLanguage = hljs.getLanguage(language) ? language : 'cpp';
            return hljs.highlight(validLanguage, code).value;
        },
        pedantic: false,
        gfm: true,
        breaks: true,
        sanitize: false,
        smartLists: true,
        smartypants: false,
        xhtml: false,
        ...(markedOptions || {}),
    };

    marked.setOptions(markedOptions);

    let customMarkdownParser = function(plainText) {
        plainText = plainText.replace(/\$\$(.*?)\$\$/g, function (match, p1) {
            return "<p class='text-center'>" 
                + katex.renderToString(p1, {displayMode: true}) + "</p>";
        }).replace(/\$(.*?[^\\])\$/g, function (match, p1) {
            return katex.renderToString(p1, {displayMode: false});
        });

        return marked(plainText);
    };

    /// align table in markdown
    let formatTable = function (table) {
        function strWidth(str) {
            var len = 0;
            for (var i = 0; i < str.length; ++i) {
                len += (str.charCodeAt(i) < 256) ? 1 : 2;
            }

            return len;
        }

        table = table.trim();
        if (!table) {
            return "";
        }

        var rows = table.split("\n").map(function (row) {
            row = row.split("|");
            row = row.map(function (col) {
                return col.trim();
            });

            return row;
        });

        var widths = Array(rows[0].length).fill(0);
        rows.forEach(function (row) {
            row.forEach(function (item, col) {
                widths[col] = Math.max(widths[col], strWidth(item));
            });
        });

        console.log(widths);

        rows = rows.map(function (row) {
            row = row.map(function (item, col) {
                if (widths[col] > 0) {
                    item = " " + item + " ".repeat(widths[col] - strWidth(item) + 1);
                }

                return item;
            }).join("|");

            return row;
        });

        return rows.join("\n");
    };

    config = {
        spellChecker: false,
        autosave: {
            enabled: false,
        },
        toolbar: [
            'bold', 'italic', 'strikethrough', 'heading-3', 'code', 'quote',
            'unordered-list', 'ordered-list', 'clean-block', 'link', 'image', '|', 'table',
        {
            name: "format_table",
            action: function (editor){
                console.log(editor);
                var selection = editor.codemirror.doc.getSelection();
                editor.codemirror.doc.replaceSelection(formatTable(selection));
            },
            className: "fa fa-align-justify",
            title: "格式化表格",
        }, 'preview', 'side-by-side', 'fullscreen', '|', 'guide',  ],


        placeholder: 'Type here...',
        tabSize: 4,
        previewRender: function(plainText, preview) { // Async method
            setTimeout(function(){
                preview.innerHTML = customMarkdownParser(plainText);
            }, 250);
        },
        ...(config || {})
    };

    return new EasyMDE(config);
}   
</script>

最后要用的时候直接调用:

<script>
var mde = easymde_katex_wrap($("#textarea"));
</script>

几点说明:

上面还增加了一个按钮,可以对选中的 markdown 表格代码快速对齐。简单举个例子,如果我们选中下面的表格:

| aaaa | bbb | c
|---|-|-
|x|xxxx|xx

点击快速对齐的按钮之后,将会格式化成下面的代码:

| aaaa | bbb  | c  
| ---  | -    | -  
| x    | xxxx | xx

Q. E. D.