LaTeX Unicode Shortcuts

Highlight text then press [ALT+X] to convert LaTeX commands to their unicode equivalent (ex. \pi → π)

目前為 2020-07-21 提交的版本,檢視 最新版本

// ==UserScript==
// @name         LaTeX Unicode Shortcuts
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Highlight text then press [ALT+X] to convert LaTeX commands to their unicode equivalent (ex. \pi → π)
// @author       eyl327
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    var convert;

    var dictLoaded = false;

    /* source url for shortcut file */
    var dictionarySource = "https://raw.githubusercontent.com/eyl327/LaTeX-Gboard-Dictionary/master/dictionary.txt";

    /* fetch text file when requested */
    function loadAsset(url, callback) {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", url, false);
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200 || xhr.status === 0) {
                    callback(xhr.responseText);
                }
            }
        }
        xhr.send();
    }

    /* on dictionary loaded callback */
    function loaded(response) {
        console.log("LaTeX Unicode Shortcuts has been loaded.");
        /* generate dictionary from text file */
        var dictArr = response.split("\n").slice(1);
        var dictionary = {};
        for (var i = 0, len = dictArr.length; i < len; ++i) {
            var kvp = dictArr[i].split("\t");
            dictionary[kvp[0]] = kvp[1];
        }
        /* conversion function */
        convert = function (text) {
            var result = text.replace(/{([A-Za-z0-9])}/g, '$1'); // {R} => R
            for (var key in dictionary) {
                var pattern = new RegExp(key.replace(/([[^$.|\\?*+(){}])/g, '\\$1') + "\\b", 'g'); // clean and escape key
                var replaced = result.replace(pattern, dictionary[key]);
                if (replaced.length < result.length) {
                    result = replaced;
                }
            }
            return result;
        };
        dictLoaded = true;
    }

    /* get caret position within input box */
    function getCaretPosition(el) {
        if ("selectionStart" in el && document.activeElement == el) {
            return {
                start: el.selectionStart,
                end: el.selectionEnd
            };
        }
        else if (el.createTextRange) {
            var sel = document.selection.createRange();
            if (sel.parentElement() === el) {
                var range = el.createTextRange();
                range.moveToBookmark(sel.getBookmark());
                for (var len = 0;
                    range.compareEndPoints("EndToStart", range) > 0;
                    range.moveEnd("character", -1)) {
                    len++;
                }
                range.setEndPoint("StartToStart", el.createTextRange());
                for (var pos = { start: 0, end: len };
                    range.compareEndPoints("EndToStart", range) > 0;
                    range.moveEnd("character", -1)) {
                    pos.start++;
                    pos.end++;
                }
                return pos;
            }
        }
        return -1;
    }

    /* set caret position within input box */
    function setCaretPosition(el, pos) {
        if (el.setSelectionRange) {
            el.focus();
            el.setSelectionRange(pos, pos);
        }
        else if (el.createTextRange) {
            var range = el.createTextRange();
            range.collapse(true);
            range.moveEnd('character', pos);
            range.moveStart('character', pos);
            range.select();
        }
    }

    function replaceConversionInElement(activeEl, start, end) {
        var fullText = activeEl.value;
        var textToConvert = fullText.substring(start, end);
        var before = fullText.substring(0, start);
        var after = fullText.substring(end, fullText.length);
        // convert selection
        var convertedText = convert(textToConvert);
        // overwrite text
        activeEl.value = before + convertedText + after
        // set cursor to be at end of selection
        setCaretPosition(activeEl, before.length + convertedText.length);
    }

    /* convert hilighted text in active element */
    function convertSelection(activeEl) {
        var caretRange = getCaretPosition(activeEl);
        var selStart = caretRange.start;
        var selEnd = caretRange.end;
        /* if selection is empty, find word at caret */
        if (selStart == selEnd) {
            var fullText = activeEl.value;
            // Find beginning and end of word
            var left = fullText.slice(0, selStart + 1).search(/\S+$/);
            var right = fullText.slice(selStart).search(/(\s|$)/);
            /* convert the word at the caret selection */
            replaceConversionInElement(activeEl, left, right + selStart)
        }
        /* else convert the selection */
        else {
            replaceConversionInElement(activeEl, selStart, selEnd);
        }
    }

    /* detect ALT+X keyboard shortcut */
    async function enableLaTeXShortcuts(event) {
        if (event.altKey && event.keyCode == 88) { // ALT+X
            // load dictionary when first pressed
            if (!dictLoaded) {
                await loadAsset(dictionarySource, loaded);
            }
            // convert selection
            var activeEl = document.activeElement;
            var activeElTag = activeEl.tagName.toLowerCase();
            if (activeElTag == "textarea" || activeElTag == "input") {
                convertSelection(activeEl);
            }
        }
    }

    document.addEventListener('keydown', enableLaTeXShortcuts, false);

})();

QingJ © 2025

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