diff --git a/.nvmrc b/.nvmrc index 25bf17f..19c7bdb 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18 \ No newline at end of file +16 \ No newline at end of file diff --git a/package.json b/package.json index 9a50fe3..283b5f5 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,10 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "roughjs": "^4.5.2", - "html2canvas": "^1.4.1", "@popperjs/core": "^2.11.8", "nanoid": "^4.0.2", - "lucide-react": "^0.263.1" + "lucide-react": "^0.263.1", + "mathjax-full": "^3.2.2" }, "devDependencies": { "lz-string": "^1.5.0", @@ -63,8 +63,7 @@ "rollup-plugin-web-worker-loader": "^1.6.1", "tslib": "^2.6.1", "ttypescript": "^1.5.15", - "typescript": "^5.2.2", - "mathjax-full": "3.2.1" + "typescript": "^5.2.2" }, "resolutions": { "@typescript-eslint/typescript-estree": "5.3.0" diff --git a/rollup.config.js b/rollup.config.js index 6dd943f..ecbb193 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -25,7 +25,6 @@ const reactdom_pkg = isLib ? "" : isProd ? fs.readFileSync("./node_modules/react-dom/umd/react-dom.production.min.js", "utf8") : fs.readFileSync("./node_modules/react-dom/umd/react-dom.development.js", "utf8"); const lzstring_pkg = isLib ? "" : fs.readFileSync("./node_modules/lz-string/libs/lz-string.min.js", "utf8"); -const mathjax_pkg = isLib ? "" : fs.readFileSync("./node_modules/mathjax-full/es5/tex-svg-full.js", "utf8"); const manifestStr = isLib ? "" : fs.readFileSync("manifest.json", "utf-8"); const manifest = isLib ? {} : JSON.parse(manifestStr); @@ -34,8 +33,6 @@ const manifest = isLib ? {} : JSON.parse(manifestStr); const packageString = isLib ? "" : ';' + lzstring_pkg + - 'const MATHJAX_SOURCE_LZCOMPRESSED = "' + - LZString.compressToBase64(btoa(unescape(encodeURIComponent(mathjax_pkg.replaceAll("MathJax","ExcalidrawMathJax"))))) + '";' + 'const EXCALIDRAW_PACKAGES = "' + LZString.compressToBase64(react_pkg + reactdom_pkg + excalidraw_pkg) + '";' + 'const {react, reactDOM, excalidrawLib} = window.eval.call(window, `(function() {' + '${LZString.decompressFromBase64(EXCALIDRAW_PACKAGES)};' + diff --git a/src/EmbeddedFileLoader.ts b/src/EmbeddedFileLoader.ts index c73b785..12adab5 100644 --- a/src/EmbeddedFileLoader.ts +++ b/src/EmbeddedFileLoader.ts @@ -586,7 +586,7 @@ export class EmbeddedFilesLoader { while (!this.terminate && !(equation = equations.next()).done) { if (!excalidrawData.getEquation(equation.value[0]).isLoaded) { const latex = equation.value[1].latex; - const data = await tex2dataURL(latex, this.plugin); + const data = await tex2dataURL(latex); if (data) { const fileData = { mimeType: data.mimeType, diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index b8da766..272b171 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -1377,7 +1377,7 @@ export class ExcalidrawAutomate { */ async addLaTex(topX: number, topY: number, tex: string): Promise { const id = nanoid(); - const image = await tex2dataURL(tex, this.plugin); + const image = await tex2dataURL(tex); if (!image) { return null; } diff --git a/src/LaTeX.ts b/src/LaTeX.ts index eed1ab8..10d0c2c 100644 --- a/src/LaTeX.ts +++ b/src/LaTeX.ts @@ -1,14 +1,19 @@ import { DataURL } from "@zsviczian/excalidraw/types/types"; +import {mathjax} from "mathjax-full/js/mathjax"; +import {TeX} from 'mathjax-full/js/input/tex.js'; +import {SVG} from 'mathjax-full/js/output/svg.js'; +import {LiteAdaptor, liteAdaptor} from 'mathjax-full/js/adaptors/liteAdaptor.js'; +import {RegisterHTMLHandler} from 'mathjax-full/js/handlers/html.js'; +import {AllPackages} from 'mathjax-full/js/input/tex/AllPackages.js'; + import ExcalidrawView from "./ExcalidrawView"; import ExcalidrawPlugin from "./main"; import { FileData, MimeType } from "./EmbeddedFileLoader"; import { FileId } from "@zsviczian/excalidraw/types/element/types"; -import { errorlog, getImageSize, log, sleep, svgToBase64 } from "./utils/Utils"; +import { getImageSize, svgToBase64 } from "./utils/Utils"; import { fileid } from "./constants/constants"; -import html2canvas from "html2canvas"; -import { Notice } from "obsidian"; - -declare let window: any; +import { TFile } from "obsidian"; +import { MathDocument } from "mathjax-full/js/core/MathDocument"; export const updateEquation = async ( equation: string, @@ -17,7 +22,7 @@ export const updateEquation = async ( addFiles: Function, plugin: ExcalidrawPlugin, ) => { - const data = await tex2dataURL(equation, plugin); + const data = await tex2dataURL(equation); if (data) { const files: FileData[] = []; files.push({ @@ -33,9 +38,23 @@ export const updateEquation = async ( } }; +let adaptor: LiteAdaptor; +let input: TeX; +let output: SVG; +let html: MathDocument; +let preamble: string; + +//https://github.com/xldenis/obsidian-latex/blob/master/main.ts +const loadPreamble = async () => { + const file = app.vault.getAbstractFileByPath("preamble.sty"); + preamble = file && file instanceof TFile + ? await app.vault.read(file) + : null; +}; + export async function tex2dataURL( tex: string, - plugin: ExcalidrawPlugin, + scale: number = 4 // Default scale value, adjust as needed ): Promise<{ mimeType: MimeType; fileId: FileId; @@ -43,102 +62,41 @@ export async function tex2dataURL( created: number; size: { height: number; width: number }; }> { - //if network is slow, or not available, or mathjax has not yet fully loaded - let counter = 0; - while (!plugin.mathjax && !plugin.mathjaxLoaderFinished && counter < 10) { - await sleep(100); - counter++; + if(!adaptor) { + await loadPreamble(); + adaptor = liteAdaptor(); + RegisterHTMLHandler(adaptor); + input = new TeX({ + packages: AllPackages, + ...Boolean(preamble) ? { + inlineMath: [['$', '$']], + displayMath: [['$$', '$$']] + } : {}, + }); + output = new SVG({ fontCache: "local" }); + html = mathjax.document("", { InputJax: input, OutputJax: output }); } - - if(!plugin.mathjaxLoaderFinished) { - errorlog({where: "text2dataURL", fn: tex2dataURL, message:"mathjaxLoader not ready, using fallback. Try reloading Obsidian or restarting the Excalidraw plugin"}); - } - - //it is not clear why this works, but it seems that after loading the plugin sometimes only the third attempt is successful. try { - return await mathjaxSVG(tex, plugin); - } catch (e) { - await sleep(100); - try { - return await mathjaxSVG(tex, plugin); - } catch (e) { - await sleep(100); - try { - return await mathjaxSVG(tex, plugin); - } catch (e) { - if (plugin.mathjax) { - new Notice( - "Unknown error loading LaTeX. Using fallback solution. Try closing and reopening this drawing.", - ); - } else { - new Notice( - "LaTeX support did not load. Using fallback solution. Try checking your network connection.", - ); - } - //fallback - return await mathjaxImage2html(tex); + const node = html.convert( + Boolean(preamble) ? `${preamble}${tex}` : tex, + { display: true, scale } + ); + const svg = new DOMParser().parseFromString(adaptor.innerHTML(node), "image/svg+xml").firstChild as SVGSVGElement; + if (svg) { + if(svg.width.baseVal.valueInSpecifiedUnits < 2) { + svg.width.baseVal.valueAsString = `${(svg.width.baseVal.valueInSpecifiedUnits+1).toFixed(3)}ex`; } + const dataURL = svgToBase64(svg.outerHTML); + return { + mimeType: "image/svg+xml", + fileId: fileid() as FileId, + dataURL: dataURL as DataURL, + created: Date.now(), + size: await getImageSize(dataURL), + }; } - } -} - -export async function mathjaxSVG( - tex: string, - plugin: ExcalidrawPlugin, -): Promise<{ - mimeType: MimeType; - fileId: FileId; - dataURL: DataURL; - created: number; - size: { height: number; width: number }; -}> { - const eq = plugin.mathjax.tex2svg(tex, { display: true, scale: 4 }); - const svg = eq.querySelector("svg"); - if (svg) { - if(svg.width.baseVal.valueInSpecifiedUnits < 2) { - svg.width.baseVal.valueAsString = `${(svg.width.baseVal.valueInSpecifiedUnits+1).toFixed(3)}ex`; - } - const dataURL = svgToBase64(svg.outerHTML); - return { - mimeType: "image/svg+xml", - fileId: fileid() as FileId, - dataURL: dataURL as DataURL, - created: Date.now(), - size: await getImageSize(dataURL), - }; + } catch (e) { + console.error(e); } return null; -} - -async function mathjaxImage2html(tex: string): Promise<{ - mimeType: MimeType; - fileId: FileId; - dataURL: DataURL; - created: number; - size: { height: number; width: number }; -}> { - const div = document.body.createDiv(); - div.style.display = "table"; //this will ensure div fits width of formula exactly - //@ts-ignore - - const eq = window.MathJax.tex2chtml(tex, { display: true, scale: 4 }); //scale to ensure good resolution - eq.style.margin = "3px"; - eq.style.color = "black"; - - //ipad support - removing mml as that was causing phantom double-image blur. - const el = eq.querySelector("mjx-assistive-mml"); - if (el) { - el.parentElement.removeChild(el); - } - div.appendChild(eq); - window.MathJax.typeset(); - const canvas = await html2canvas(div, { backgroundColor: null }); //transparent - document.body.removeChild(div); - return { - mimeType: "image/png", - fileId: fileid() as FileId, - dataURL: canvas.toDataURL() as DataURL, - created: Date.now(), - size: { height: canvas.height, width: canvas.width }, - }; -} +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index fd34d88..e4226b7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,7 +12,6 @@ import { TAbstractFile, ViewState, Notice, - loadMathJax, request, MetadataCache, FrontMatterCache, @@ -117,7 +116,6 @@ import { ExportDialog } from "./dialogs/ExportDialog"; import { UniversalInsertFileModal } from "./dialogs/UniversalInsertFileModal"; import { imageCache } from "./utils/ImageCache"; import { StylesManager } from "./utils/StylesManager"; -//import { MATHJAX_SOURCE_LZCOMPRESSED } from "./constants/constMathJaxSource"; import { PublishOutOfDateFilesDialog } from "./dialogs/PublishOutOfDateFiles"; import { EmbeddableSettings } from "./dialogs/EmbeddableSettings"; import { processLinkText } from "./utils/CustomEmbeddableUtils"; @@ -132,7 +130,6 @@ declare const react:any; declare const reactDOM:any; declare const excalidrawLib: any; declare const PLUGIN_VERSION:string; -declare const MATHJAX_SOURCE_LZCOMPRESSED:string; declare var LZString: any; export default class ExcalidrawPlugin extends Plugin { @@ -166,8 +163,6 @@ export default class ExcalidrawPlugin extends Plugin { null; //fileId, path public equationsMaster: Map = null; //fileId, formula public mermaidsMaster: Map = null; //fileId, mermaidText - public mathjax: any = null; - public mathjaxLoaderFinished: boolean = false; public scriptEngine: ScriptEngine; public fourthFontDef: string = VIRGIL_FONT; private packageMap: WeakMap = new WeakMap(); @@ -295,8 +290,6 @@ export default class ExcalidrawPlugin extends Plugin { this.switchToExcalidarwAfterLoad(); - this.loadMathJax(); - const self = this; this.app.workspace.onLayoutReady(() => { this.scriptEngine = new ScriptEngine(self); @@ -349,85 +342,6 @@ export default class ExcalidrawPlugin extends Plugin { return Array.from(visitedDocs); } - private removeMathJax() { - if("ExcalidrawMathJax" in window) { - delete window.ExcalidrawMathJax; - } - const scriptElement = document.getElementById("ExcalidrawMathJax"); - if(scriptElement) { - scriptElement.parentNode.removeChild(scriptElement); - } - } - - public loadMathJax() { - const self = this; - this.app.workspace.onLayoutReady(async () => { - //loading Obsidian MathJax as fallback - await loadMathJax(); - //@ts-ignore - const backup = window.MathJax; - try { - this.removeMathJax(); - const script = document.createElement("script"); - script.setAttribute("id","ExcalidrawMathJax"); - script.type = "text/javascript"; - script.onload = () => { - //@ts-ignore - window.ExcalidrawMathJax.startup.pagePromise.then(async () => { - - // Set the 'all' package to load all MathJax modules - const mathJaxConfig = { - tex: { - packages: { '[+]': ['all'] }, //this is required because during runtime loading fails due to the renaming of the package - // Add any other configurations you need here - }, - }; - - // Set the MathJax configuration - //@ts-ignore - window.ExcalidrawMathJax = { - //@ts-ignore - ...window.ExcalidrawMathJax, - options: { - //@ts-ignore - ...window.ExcalidrawMathJax.options, - ...mathJaxConfig, - }, - }; - - //https://github.com/xldenis/obsidian-latex/blob/master/main.ts - const file = this.app.vault.getAbstractFileByPath("preamble.sty"); - const preamble: string = - file && file instanceof TFile - ? await this.app.vault.read(file) - : null; - try { - if (preamble) { - //@ts-ignore - await window.ExcalidrawMathJax.tex2svg(preamble); - } - } catch (e) { - errorlog({ - where: self.loadMathJax, - description: "Unexpected error while loading preamble.sty", - error: e, - }); - } - //@ts-ignore - self.mathjax = window.ExcalidrawMathJax; - self.mathjaxLoaderFinished = true; - }); - }; - script.src = "data:text/javascript;base64," + LZString.decompressFromBase64(MATHJAX_SOURCE_LZCOMPRESSED); //self.settings.mathjaxSourceURL; // "https://cdn.jsdelivr.net/npm/mathjax@3.2.2/es5/tex-svg.js"; - //script.src = MATHJAX_DATAURL; - document.head.appendChild(script); - } catch { - new Notice("Excalidraw: Error initializing LaTeX support"); - self.mathjaxLoaderFinished = true; - } - }); - } - private switchToExcalidarwAfterLoad() { const self = this; this.app.workspace.onLayoutReady(() => { @@ -2473,11 +2387,6 @@ export default class ExcalidrawPlugin extends Plugin { this.setMarkdownView(leaf); }); - this.removeMathJax(); -/* if (this.mathjaxDiv) { - document.body.removeChild(this.mathjaxDiv); - }*/ - Object.values(this.packageMap).forEach((p:Packages)=>{ delete p.excalidrawLib; delete p.reactDOM; diff --git a/src/settings.ts b/src/settings.ts index 241a315..c172f2e 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -398,7 +398,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab { private requestReloadDrawings: boolean = false; private requestUpdatePinnedPens: boolean = false; private requestUpdateDynamicStyling: boolean = false; - private reloadMathJax: boolean = false; + //private reloadMathJax: boolean = false; //private applyDebounceTimer: number = 0; constructor(app: App, plugin: ExcalidrawPlugin) { @@ -452,9 +452,9 @@ export class ExcalidrawSettingTab extends PluginSettingTab { this.plugin.triggerEmbedUpdates(); } this.plugin.scriptEngine.updateScriptPath(); - if(this.reloadMathJax) { +/* if(this.reloadMathJax) { this.plugin.loadMathJax(); - } + }*/ } async display() { diff --git a/src/utils/FileUtils.ts b/src/utils/FileUtils.ts index d374171..c351b78 100644 --- a/src/utils/FileUtils.ts +++ b/src/utils/FileUtils.ts @@ -329,7 +329,6 @@ export const getPathWithoutExtension = (f:TFile): string => { return f.path.substring(0, f.path.lastIndexOf(".")); } -debugger; const VAULT_BASE_URL = DEVICE.isDesktop ? app.vault.adapter.url.pathToFileURL(app.vault.adapter.basePath).toString() : ""; diff --git a/tsconfig.dev.json b/tsconfig.dev.json index 5f4876b..48ae747 100644 --- a/tsconfig.dev.json +++ b/tsconfig.dev.json @@ -2,7 +2,7 @@ "compilerOptions": { "baseUrl": ".", "sourceMap": true, - "module": "es2015", + "module": "ES2015", "target": "es2017", //es2017 because script engine requires for async execution "allowJs": true, "noImplicitAny": true,