在 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.