Greasy Fork is available in English.
为中文文本中的公式添加 $$ 符号,以适应 Markdown 或 Latex 格式的需求。并修复常见的图片识别结果中的错误
当前为
// ==UserScript==
// @name Latexlive公式编辑器输出增强:转 Markdown 格式,适用于 Logseq 等
// @namespace http://tampermonkey.net/
// @version 1.2
// @description 为中文文本中的公式添加 $$ 符号,以适应 Markdown 或 Latex 格式的需求。并修复常见的图片识别结果中的错误
// @author Another_Ghost
// @match https://*.latexlive.com/*
// @icon https://img.icons8.com/?size=50&id=1759&format=png
// @grant GM_registerMenuCommand
// @license MIT
// ==/UserScript==
(function () {
createButton('复制', copyOriginalText, '');
createButton('转换后复制', convertFormulasToLaTeX, /\\boldsymbol/g);
/**
* 创建按钮并添加到指定容器中
* @param {number} buttonName - 按钮的名字
* @param {function} convert - 转换函数
* @param {string} wordsToRemove - 需要移除的字符串
*/
function createButton(buttonName, convert, wordsToRemove) {
// 创建一个新按钮
let button = document.createElement('button');
button.innerHTML = `${buttonName}`;
button.className = 'btn btn-light btn-outline-dark';
//button.id = `copy-btn${buttonId}`;
// add click handler
button.onclick = function () {
//选中输入文本框的所有文本
var selected = document.querySelector('#txta_input');
//先通过 convert 函数转换文本,再复制
navigator.clipboard.writeText(convert(selected.value, wordsToRemove));
displayAlertBox('已复制');
};
//输入框上方的容器
var CONTAINER = "#wrap_immediate > row > div.col-5.col-sm-5.col-md-5.col-lg-5.col-xl-5";
//等待容器出现并添加按钮
var interval = setInterval(function () {
var wrap = document.querySelector(CONTAINER);
if (wrap) {
wrap.appendChild(button);
clearInterval(interval);
}
}, 200);
}
function displayAlertBox(text) {
var alertBox = document.createElement('div');
alertBox.innerHTML = text;
//alertBox.style.display = none;
alertBox.style.position = 'fixed';
alertBox.style.bottom = `20px`;
alertBox.style.left = `50%`;
alertBox.style.transform = `translateX(-50%)`;
alertBox.style.backgroundColor = `#4CAF50`;
alertBox.style.color = `white`;
alertBox.style.padding = `12px`;
alertBox.style.borderRadius = `5px`;
alertBox.style.zIndex = `1000`;
alertBox.style.boxShadow = `0px 0px 10px rgba(0,0,0,0.5)`;
alertBox.style.opacity = '0';
alertBox.style.transition = 'opacity 0.3s';
document.body.appendChild(alertBox);
setTimeout(function () {
alertBox.style.opacity = '1';
}, 100);
setTimeout(function () {
alertBox.style.opacity = '0';
}, 1100);
setTimeout(function () {
alertBox.remove();
}, 1500);
}
function copyOriginalText(inStr, wordsToRemove = '') {
return inStr;
}
let bRadical = true; //是否是更激进的转换方式
let shortcutKey = null;
GM_registerMenuCommand('切换激进转换', function (){
bRadical = !bRadical;
if(bRadical)
{
displayAlertBox("开启激进转换");
}
else
{
displayAlertBox("关闭激进转换");
}
}, shortcutKey);
/**
* 将字符串中的公式转换为LaTeX格式,用"$$"包围起来。
*/
function convertFormulasToLaTeX(inStr, wordsToRemove = '') {
// const menu_command_id_1 = GM_registerMenuCommand("Show Alert", function(event: MouseEvent | KeyboardEvent) {
// alert("Menu item selected");
// }, {
// accessKey: "a",
// autoClose: true
// });
// 输入的预处理
inStr = inStr.trim(); //删除字符串两端的空白字符
if(bRadical)
{
inStr = inStr.replace(/\\begin{array}{[^{}]*}/g, '\\begin{aligned}');
inStr = inStr.replace(/\\end{array}/g, '\\end{aligned}');
}
inStr = inStr.replace(wordsToRemove, '');
inStr = inStr.replace(/ +/g, ' '); //将多个空格替换为一个空格
inStr = inStr.replace(/\n+/g, '\n'); //去除重复换行符
inStr = inStr.replace('输人', '输入');
//inStr = inStr.replace(/\\text *{([^{}]*)}/g, '$1');
let str = inStr.trim();
let outStr = ""; //最终输出的字符串
let equation = ""; //存储一个公式
let bEquation = false; //是否在处理一个公式
//处理并存储一个潜在公式
let PushEquationToOutStr = (nextChar) => {
if(/[\-<=>\\\^_{\|}\/\*\+\(]/.test(equation) || /^[a-zA-Z0-9]$/.test(equation.trim())){ //判断是否是真的公式
outStr += ToMarkdownLatex(equation, nextChar);
}
else
{
outStr+=equation;
}
bEquation = false;
equation = "";
}
//实际转换格式的函数
function ToMarkdownLatex(equation, nextChar)
{
equationSymbol = "$";
let prevChar = outStr[outStr.length-1];
if((!nextChar || nextChar.match(/[\n\r]/)) && (!prevChar || prevChar.match(/[\n\r]/))) //判断是否为单行居中显示的公式
{
equationSymbol = "$$";
}
if(equation[equation.length-1] != '$' || equation[0] != '$$')
{
equation = insertCharAt(equation, equationSymbol, findLastNonWhitespaceChar(equation)+1); //在公式字符串的最后一个非空格字符的位置的后一个位置插入"$$")
}
if(equation[0] != '$' || equation[0] != '$$')
{
equation = equationSymbol + equation;
}
return equation;
}
//遍历字符串的主循环
for(let i = 0; i < str.length; i++) {
let c = str[i];
//let nextChar = i < str.length - 1 ? str[i + 1] : '';
if(!bEquation){
if(c.match(/[!-~]/)) { //判断是否是非空格ASCII字符
if(!bEquation && !c.match(/[:,.]/)) //把开头的 ":" 排除在 $$ 外;因为之后一般会跟着换行符,所以没有写在 ToLatex 函数里
{
bEquation = true;
}
}
}
else{ //判断一个公式是否结束
if((c.match(/[\n\r]/) && (!/\\begin/.test(equation) || /\\end/.test(equation))) //换行符且是不是在\begin{array}和\end{array}之间,则算作一个潜在公式
|| (!c.match(/[ -~]/) && !(/\\text *{([^}])*$/.test(equation)) && !c.match(/[\n\r]/)) //判断如果是非换行符的ASCII字符,且不在 \text{} 中,则算作一个潜在公式进行后续处理
)
{
PushEquationToOutStr(c);
}
}
//循环中,只有此处存储字符
if(bEquation){
equation += c;
}
else{
outStr += c;
}
}
if(equation.length > 0) {
PushEquationToOutStr('');
}
console.log(outStr);
return outStr;
/**
* Insert a character at a specified index in the original string.
* @param {string} originalString - The original string.
* @param {string} charToInsert - The character to insert.
* @param {number} index - The index to insert at.
* @returns {string} - The new string with the inserted character.
*/
function insertCharAt(originalString, charToInsert, index) {
let firstPart = originalString.slice(0, index);
let secondPart = originalString.slice(index);
return `${firstPart}${charToInsert}${secondPart}`;
}
function findLastNonWhitespaceChar(str) {
const match = str.match(/(\S)\s*$/);
return match ? str.lastIndexOf(match[1]) : -1;
}
}
})();