Mathcord

Typeset equations in Discord messages.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

You will need to install an extension such as Tampermonkey to install this script.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Mathcord
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  Typeset equations in Discord messages.
// @author       Till Hoffmann
// @match        https://discordapp.com/*
// @resource     katexCSS https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js
// @grant        GM_addStyle
// @grant        GM_getResourceText
// ==/UserScript==

/**
 * Evaluate whether an element has a certain class prefix.
 */
function hasClassPrefix(element, prefix) {
    var classes = (element.getAttribute("class") || "").split();
    return classes.some(x => x.startsWith(prefix));
}

(function() {
    'use strict';
    // Declare rendering options (see https://katex.org/docs/autorender.html#api for details)
    const options = {
        delimiters: [
            {left: "$$", right: "$$", display: true},
            {left: "\\(", right: "\\)", display: false},
            {left: "\\[", right: "\\]", display: true},
            // Needs to come last to prevent over-eager matching of delimiters
            {left: "$", right: "$", display: false},
        ],
    };

    // We need to download the CSS, modify any relative urls to be absolute, and inject the CSS
    var katexCSS = GM_getResourceText("katexCSS");
    var pattern = /url\((.*?)\)/gi;
    katexCSS = katexCSS.replace(pattern, 'url(https://cdn.jsdelivr.net/npm/[email protected]/dist/$1)');
    GM_addStyle(katexCSS);

    // Monitor the document for changes and render math as necessary
    var config = { childList: true, subtree: true };
    var observer = new MutationObserver(function(mutations, observer) {
        for (let mutation of mutations) {
            var target = mutation.target;
            // Iterate over all messages added to the scroller and typeset them
            if (target.tagName == "DIV" && hasClassPrefix(target, "scroller")) {
                for (let added of mutation.addedNodes) {
                    if (added.tagName == "DIV" && hasClassPrefix(added, "message")) {
                        renderMathInElement(added, options);
                    }
                }
            }
            // Respond to edited messages
            else if (target.tagName == "DIV" && hasClassPrefix(target, "container") &&
                       hasClassPrefix(target.parentNode, "message")) {
                for (let added of mutation.addedNodes) {
                    // Do not typeset the interactive edit container
                    if (added.tagName == "DIV" && !added.getAttribute("class")) {
                        continue;
                    }
                    setTimeout(_ => renderMathInElement(added, options), 1000);
                }
            }
        }
    });
    observer.observe(document.body, config);
})();