CC98 Tools - Math Editor

为CC98网页版添加数学公式支持

// ==UserScript==
// @name         CC98 Tools - Math Editor
// @namespace    https://www.cc98.org/
// @version      0.0.1
// @description  为CC98网页版添加数学公式支持
// @author       ml98
// @match        https://www.cc98.org/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @require      https://gf.qytechs.cn/scripts/2199-waitforkeyelements/code/waitForKeyElements.js?version=6349
// @grant        GM_addStyle
// ==/UserScript==

// ref
// https://latex.codecogs.com/svg.latex?\log\prod^N_{i}x_{i}=\sum^N_i\log{x_i}
// https://math.now.sh/?from=\\log\\prod^N_{i}x_{i}=\\sum^N_i\\log{x_i}
// https://www.zhihu.com/equation?tex=~

// test https://www.cc98.org/topic/2803718/695#4

console.log("%cCC98 Tools Math Editor", "font-size: large");


function addMathEditor(){
    'use strict';
    console.log("addMathEditor");
    // add Math Editor modal
    console.log("add Math Editor modal");
    var myModal = document.createElement('div');
    myModal.id = "myModal";
    myModal.classList = "modal";
    if(1){myModal.innerHTML = String.raw`
        <!-- Modal content -->
        <div class="modal-content">
            <span class="close">&times;</span>
            <h3 id="header">Math Editor for CC98</h3>
            <div id="main">
                <div id="io">
                    <div id="input">
                        <p>Input</p>
                        <textarea id="inputText" spellcheck="false">\LaTeX</textarea>
                        <button id="copyInput" onclick="copy('inputText')">Copy</button>
                    </div>

                    <div id="output">
                        <p>Output</p>
                        <textarea type="text" id="outputText" spellcheck="false" value=''></textarea>
                        <button id="copyOutput" onclick="copy('outputText')">Copy</button>
                    </div>
                </div>
                <br>
                <label style="display: inline-block;">Engine
                    <select name="select" id="engineSelect">
                        <option value="zhihu" selected>zhihu</option>
                        <option value="codecogs">codecogs</option>
                        <option value="math.now.sh">math.now.sh</option>
                    </select>
                </label>
                <label style="display: inline-block;">Format
                    <select name="select" id="formatSelect">
                        <option value="Ubb" selected>Ubb</option>
                        <option value="Markdown">Markdown</option>
                        <option value="HTML">HTML</option>
                        <option value="URL">URL</option>
                    </select>
                </label>

                <div id="preview">
                    <p>Preview</p>
                    <div id="imagebox">
                        <img id="previewImage" src="" />
                    </div>
                </div>
            </div>
            <div id="footer">
                <p>86ɔɔ ɹoɟ ɹoʇıpǝ ɥʇɐɯ</p>
            </div>
        </div>
`;}
    document.body.appendChild(myModal);

    // add style
    console.log("add Math Editor style");
    if(1){GM_addStyle(String.raw`
        /* The Modal (background) */
        .modal {
            display: none;
            /* Hidden by default */
            position: fixed;
            /* Stay in place */
            z-index: 1;
            /* Sit on top */
            padding-top: 50px;
            /* Location of the box */
            left: 0;
            top: 0;
            width: 100%;
            /* Full width */
            height: 100%;
            /* Full height */
            overflow: auto;
            /* Enable scroll if needed */
            background-color: rgb(0, 0, 0);
            /* Fallback color */
            background-color: rgba(0, 0, 0, 0.4);
            /* Black w/ opacity */
        }

        /* Modal Content */
        .modal-content {
            background-color: #fefefe;
            margin: auto;
            padding: 20px;
            border: 1px solid #888;
            border-radius: 6px;
            width: 55%;
            height: 75%;
            position: relative;
            -webkit-animation-name: animatetop;
            -webkit-animation-duration: 0.4s;
            animation-name: animatetop;
            animation-duration: 0.4s
        }

        /* Add Animation */
        @-webkit-keyframes animatetop {
            from {
                top: -300px;
                opacity: 0
            }

            to {
                top: 0;
                opacity: 1
            }
        }

        @keyframes animatetop {
            from {
                top: -300px;
                opacity: 0
            }

            to {
                top: 0;
                opacity: 1
            }
        }

        /* The Close Button */
        .close {
            color: #aaaaaa;
            float: right;
            font-size: 28px;
            font-weight: bold;
        }

        .close:hover,
        .close:focus {
            color: #000;
            text-decoration: none;
            cursor: pointer;
        }

        /* main style */
        #header {
            border-bottom: 1px solid #ccc;
            font-size: 2em;
        }

        #main {
            max-height: 80%;
            overflow-y: auto;
        }

        #input,
        #output {
            display: inline-block;
            vertical-align: top;
        }

        #inputText,
        #outputText {
            width: 360px;
            height: 160px;
            font-size: medium;
            resize: both;
            padding-left: 3px;
        }

        #copyInput,
        #copyOutput {
            display: block;
        }

        #footer {
            position: absolute;
            bottom: 0;
        }
`);}

    // add Math Editor script
    console.log("add Math Editor script");
    var script = document.createElement('script');
    if(1){script.innerHTML = String.raw`
        // Get the modal
        var modal = document.getElementById("myModal");

        // Get the button that opens the modal
        var btn = document.querySelector(".fa-math-editor");

        // Get the <span> element that closes the modal
        var span = document.getElementsByClassName("close")[0];

        // When the user clicks the button, open the modal
//         btn.onclick = function () {
//             update();
//             modal.style.display = "block";
//         }

        // When the user clicks on <span> (x), close the modal
        span.onclick = function () {
            modal.style.display = "none";
        }

        // When the user clicks anywhere outside of the modal, close it
        window.onclick = function (event) {
            if (event.target == modal) {
                modal.style.display = "none";
            }
        }

        // main script
        const inputText = document.querySelector("#inputText");
        const previewImage = document.querySelector("#previewImage");
        const outputText = document.querySelector("#outputText");
        const engineSelect = document.querySelector("#engineSelect");
        const formatSelect = document.querySelector("#formatSelect");

        inputText.addEventListener("input", delay(update, 1200));
        engineSelect.addEventListener("change", update);
        formatSelect.addEventListener("change", update);
        outputText.addEventListener("input", delay(analyse, 1200));
        // update();

        function delay(callback, ms) {
            var timer = 0;
            return function () {
                clearTimeout(timer);
                timer = setTimeout(callback, ms);
            };
        }

        // 编码 input -> url -> output
        function update() {
            const input = inputText.value;
            const engine = engineSelect.value;
            const format = formatSelect.value;

            if (input === "") return;

            console.log("update", input);
            const purifiedURL = input2Url(input, engine);
            previewImage.alt = input;
            if (previewImage.src !== purifiedURL) previewImage.src = purifiedURL;
            outputText.value = Url2Output(purifiedURL, format);
        }

        function input2Url(input, engine) {
            switch (engine) {
                case "math.now.sh":
                    return "https://math.now.sh?from=" + encode(input);
                case "zhihu":
                    return (
                        "https://www.zhihu.com/equation?tex=" +
                         // encode(input)
                         encode("\\bbox[white]{" + input + "}")
                    );
                case "codecogs":
                    return (
                        "https://latex.codecogs.com/svg.latex?" +
                        encode(input.replace(/^\s+|\s+$/g, "").replace(/\s+/g, " "))
                    );
                default:
                    break;
            }
        }

        function encode(s) {
            return encodeURIComponent(s).replace(/[\-\_\.\!\~\*\'\(\)]/g, function (c) {
                return "%" + c.charCodeAt(0).toString(16).toUpperCase();
            });
        }

        function Url2Output(url, format) {
            switch (format) {
                case "Ubb":
                    return "[img]" + url + "[/img]";
                case "Markdown":
                    return "![](" + url + ")";
                case "HTML":
                    return '<img src="' + url + '"/>';
                case "URL":
                    return url;
                default:
                    break;
            }
        }

        // 简单的反向解析 output -> url -> input
        function analyse() {
            const output = outputText.value;
            if (output === "") return;

            console.log("analyse", output);
            const [format, url] = output2Url(output);
            const [engine, input] = url2Input(url);
            console.log(engine, format, input);
            previewImage.alt = input;
            if (previewImage.src !== url) previewImage.src = url;
            inputText.value = input;
        }

        function output2Url(output) {
            if (output.match(/\[img\]/))
                return ["Ubb", output.replace(/\[img\]/, "").replace(/\[\/img\]/, "")];
            if (output.match(/\!\[/))
                return ["Markdown", output.replace(/\!\[.*?\]\(/, "").replace(/\)/, "")];
            if (output.match(/<img src=\"/))
                return ["HTML", output.replace(/<img src=\"/, "").replace(/\"\/>/, "")];
            if (output.match(/https/)) return ["URL", output];
            return ["", ""];
        }

        function url2Input(url) {
            if (url.match(/math\.now\.sh/))
                return [
                    "math.now.sh",
                    decodeURIComponent(url.replace("https://math.now.sh?from=", "")),
                ];
            if (url.match(/www\.zhihu\.com/))
                return [
                    "zhihu",
                    decodeURIComponent(url.replace("https://www.zhihu.com/equation?tex=", ""))
                       .replace("\\bbox[white]{", "")
                       .slice(0, -1),
                ];
            if (url.match(/latex\.codecogs\.com/))
                return [
                    "codecogs",
                    decodeURIComponent(
                        url.replace("https://latex.codecogs.com/svg.latex?", "")
                    ),
                ];
            return ["", ""];
        }

        function copy(e) {
            var copyText = document.getElementById(e);
            copyText.select();
            copyText.setSelectionRange(0, 99999); /* For mobile devices */
            document.execCommand("copy");
        }
`;}
    document.body.appendChild(script);
}

//window.addEventListener('load', addMathEditor, false); // not work?
addMathEditor();

// ubb-editor 添加Math Editor按钮
function addUbbMathEditorButton(){
    'use strict';
    console.log("addMathEditorButton");
    let mathEditorButton = document.querySelector(".fa-math-editor");
    if(!mathEditorButton) mathEditorButton = createUbbMathEditorButton();
    let referenceNode = document.querySelector(".fa.fa-file.ubb-button.ubb-button-icon");
    referenceNode.parentNode.insertBefore(mathEditorButton, referenceNode.nextSibling);
}

function createUbbMathEditorButton(){
    'use strict';
    console.log("createMathEditorButton");
    let mathEditorButton = document.createElement("button");
    mathEditorButton.className = "fa fa-math-editor ubb-button";
    mathEditorButton.type = "button";
    mathEditorButton.title = "Math Editor";
    mathEditorButton.innerText = "Σ";
    mathEditorButton.style = "font-size: larger;";
    mathEditorButton.onclick = function(){
        update();
        var modal = document.getElementById("myModal");
        modal.style.display = "block";
    }
    return mathEditorButton;
}

function removeUbbMathEditorButton(){
    console.log("removeButton");
    let mathEditorButton = document.querySelector(".fa-math-editor");
    if(mathEditorButton) mathEditorButton.remove();
}

// markdown-editor 添加Math Editor按钮
function addMdMathEditorButton(){
    'use strict';
    console.log("addMathEditorButton");
    let mathEditorButton = document.querySelector(".mde-header > ul:nth-child(3) > li:nth-child(4)");
    if(!mathEditorButton) mathEditorButton = createMdMathEditorButton();
    let referenceNode = document.querySelector(".mde-header > ul:nth-child(3) > li:nth-child(3)");
    referenceNode.parentNode.insertBefore(mathEditorButton, referenceNode.nextSibling);
}

function createMdMathEditorButton(){
    'use strict';
    console.log("createMathEditorButton");
    let mathEditorButton = document.createElement("li");
    mathEditorButton.className = "mde-header-item md-math-editor-btn";
    let btn = document.createElement("button");
    btn.innerText = "Σ";
    btn.onclick = function(){
        update();
        var modal = document.getElementById("myModal");
        modal.style.display = "block";
    }
    mathEditorButton.appendChild(btn);
    return mathEditorButton;
}

function removeMdMathEditorButton(){
    console.log("removeButton");
    let mathEditorButton = document.querySelector(".mde-header > ul:nth-child(3) > li:nth-child(4)");
    if(mathEditorButton) mathEditorButton.remove();
}

waitForKeyElements(".fa-smile-o", addUbbMathEditorButton);
waitForKeyElements(".ubb-preview", removeUbbMathEditorButton);
waitForKeyElements(".mde-header", addMdMathEditorButton);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址