File size: 3,614 Bytes
e2f726f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**

 * Markdown渲染器库(支持HTML标签)

 * 依赖:

 * - markdown-it

 * - highlight.js

 * - clipboard.js

 */

const MarkdownRenderer = (function () {
    // 初始化 markdown-it 实例,启用 HTML 支持
    hljs.configure({
        ignoreUnescapedHTML: true
    });
    const md = window.markdownit({
        html: true,          // 启用HTML标签支持
        breaks: true,
        xhtmlOut: true,
        typographer: true,   // 启用智能标点转换
        highlight: function (str, lang) {
            if (lang && hljs.getLanguage(lang)) {
                try {
                    return hljs.highlight(str, { language: lang }).value;
                } catch (__) { }
            }
            return hljs.highlight(str, { language: 'plaintext' }).value;
        }
    });

    /**

     * 渲染Markdown内容为HTML

     * @param {string} content - Markdown格式的内容

     * @returns {string} 渲染后的HTML字符串

     */
    function renderMessage(content) {
        // 处理有序列表
        content = content.replace(/(\d+)\.\s/g, ' $1\\. ');

        // 渲染markdown内容
        let renderedContent = md.render(content);

        // 创建临时容器
        const container = document.createElement('div');
        container.innerHTML = renderedContent;

        // 处理代码块
        container.querySelectorAll('pre code').forEach((block) => {
            const pre = block.parentNode;
            const lang = block.className.split('-')[1] || 'plaintext';

            // 生成唯一ID
            pre.id = 'code-' + Math.random().toString(36).substr(2, 9);

            // 创建代码头部
            const header = document.createElement('div');
            header.className = 'code-header bg-gradient-to-b from-gray-900 via-gray-800 to-gray-700 text-white rounded-lg rounded-br-none rounded-bl-none';
            header.innerHTML = `

                <div style="margin-left: 8px;">

                <span class="code-language">${lang}</span>



                <button class="copy-button" data-clipboard-target="#${pre.id}">✄</button>

                </div>

            `;

            // 添加样式类
            pre.classList.add('code-block', 'rounded-tr-none', 'rounded-tl-none');

            pre.parentNode.insertBefore(header, pre);

            // 代码高亮
            hljs.highlightElement(block);

            // 初始化复制功能
            setTimeout(() => {
                const clipboard = new ClipboardJS('.copy-button');

                clipboard.on('success', function (e) {
                    e.trigger.textContent = '♫';

                    setTimeout(() => {
                        e.trigger.textContent = '✄';
                    }, 1000);

                    e.clearSelection();
                });

                clipboard.on('error', function (e) {
                    console.error('Copy failed!');
                });
            }, 0);
        });

        // 不再需要转换HTML实体,因为我们现在允许HTML标签

        return container.innerHTML;
    }

    // 只暴露需要的方法
    return {
        render: renderMessage
    };
})();

// 支持 CommonJS
if (typeof module !== 'undefined' && module.exports) {
    module.exports = MarkdownRenderer;
}

// 支持 ES6 模块
if (typeof exports !== 'undefined') {
    exports.default = MarkdownRenderer;
}

// 支持全局变量
if (typeof window !== 'undefined') {
    window.MarkdownRenderer = MarkdownRenderer;
}