diff --git a/dist/vue3-mathjax.es.js b/dist/vue3-mathjax.es.js index 9114b68..64d3019 100644 --- a/dist/vue3-mathjax.es.js +++ b/dist/vue3-mathjax.es.js @@ -1,4 +1,54 @@ import { defineComponent, onMounted, getCurrentInstance, nextTick, onUpdated, onUnmounted, renderSlot } from "vue"; +function throttle(delay, noTrailing, callback, debounceMode) { + var timeoutID; + var cancelled = false; + var lastExec = 0; + function clearExistingTimeout() { + if (timeoutID) { + clearTimeout(timeoutID); + } + } + function cancel() { + clearExistingTimeout(); + cancelled = true; + } + if (typeof noTrailing !== "boolean") { + debounceMode = callback; + callback = noTrailing; + noTrailing = void 0; + } + function wrapper() { + for (var _len = arguments.length, arguments_ = new Array(_len), _key = 0; _key < _len; _key++) { + arguments_[_key] = arguments[_key]; + } + var self = this; + var elapsed = Date.now() - lastExec; + if (cancelled) { + return; + } + function exec() { + lastExec = Date.now(); + callback.apply(self, arguments_); + } + function clear() { + timeoutID = void 0; + } + if (debounceMode && !timeoutID) { + exec(); + } + clearExistingTimeout(); + if (debounceMode === void 0 && elapsed > delay) { + exec(); + } else if (noTrailing !== true) { + timeoutID = setTimeout(debounceMode ? clear : exec, debounceMode === void 0 ? delay - elapsed : delay); + } + } + wrapper.cancel = cancel; + return wrapper; +} +function debounce(delay, atBegin, callback) { + return callback === void 0 ? throttle(delay, atBegin, false) : throttle(delay, callback, atBegin !== false); +} let mathJaxInjected = false; let mathJaxReady = false; let pendingQueue = []; @@ -107,13 +157,48 @@ async function renderByMathJax(el) { } }); } +let waitingQueue = /* @__PURE__ */ new Set(); +let doRendering = () => { + let batch = []; + for (const el of waitingQueue.values()) { + batch.push(el); + window.MathJax.typeset(batch); + } + waitingQueue.clear(); +}; +let debouncedRendering = debounce(500, false, doRendering); +function renderByMathJaxQueued(el, flush = false) { + if (!mathJaxReady) { + if (Array.isArray(el)) { + pendingQueue.concat(el.map((v) => { + return { + type: "sync", + el: v + }; + })); + } else { + pendingQueue.push({ type: "sync", el }); + } + } + if (Array.isArray(el)) { + el.forEach((v) => waitingQueue.add(v)); + } else { + waitingQueue.add(el); + } + if (flush) { + debouncedRendering.cancel(); + doRendering(); + } else { + debouncedRendering(); + } +} const _sfc_main = /* @__PURE__ */ defineComponent({ setup(__props) { let el; - const renderMathJax = async () => { + const renderMathJax = () => { if (!el) return; - await renderByMathJax(el); + renderByMathJaxQueued(el); }; onMounted(() => { var _a, _b, _c; diff --git a/dist/vue3-mathjax.umd.js b/dist/vue3-mathjax.umd.js index 900868d..1696a6b 100644 --- a/dist/vue3-mathjax.umd.js +++ b/dist/vue3-mathjax.umd.js @@ -1 +1 @@ -(function(n,i){typeof exports=="object"&&typeof module!="undefined"?module.exports=i(require("vue")):typeof define=="function"&&define.amd?define(["vue"],i):(n=typeof globalThis!="undefined"?globalThis:n||self,n["vue-mathjax"]=i(n.Vue))})(this,function(n){"use strict";let i=!1,c=!1,s=[];function d(){return window.MathJax}function h(){const e=d();if((!e||!e.version)&&(i=!1,c=!1,s.splice(0,s.length)),!i){const t=document.createElement("script");t.src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js",t.async=!0,document.head.appendChild(t),i=!0}}function u(e={},t){const a=Object.assign({},{tex:{inlineMath:[["$","$"]],displayMath:[["$$","$$"]],processEnvironments:!0,processRefs:!0},options:{skipHtmlTags:["script","noscript","style","textarea","pre","code","annotation","annotation-xml"],ignoreHtmlClass:"tex2jax_ignore"},startup:{pageReady:()=>{c=!0,d().typeset(s.map(r=>r.el)),s.forEach(r=>{r.type=="async"&&r.callback()}),s.splice(0,s.length),t&&t()}},svg:{fontCache:"global"}},e);window.MathJax=a,h()}function y(e){if(!c){Array.isArray(e)?s.concat(e.map(t=>({type:"sync",el:t}))):s.push({type:"sync",el:e});return}window.MathJax.typeset(Array.isArray(e)?e:[e])}async function l(e){return new Promise((t,p)=>{if(c)return window.MathJax.typesetPromise(Array.isArray(e)?e:[e]);if(Array.isArray(e)){for(let a=0;a{!t||await l(t)};return n.onMounted(()=>{var a,r,o;u(),t=(o=(r=(a=n.getCurrentInstance())==null?void 0:a.vnode)==null?void 0:r.el)==null?void 0:o.parentNode,n.nextTick(()=>{p()})}),n.onUpdated(()=>{var a,r,o;t=(o=(r=(a=n.getCurrentInstance())==null?void 0:a.vnode)==null?void 0:r.el)==null?void 0:o.parentNode,p()}),n.onUnmounted(()=>{t=null}),(a,r)=>n.renderSlot(a.$slots,"default")}});function m(e){e.component("math-jax",f)}var x={install:m,MathJax:f,initMathJax:u,renderByMathJax:l,renderByMathJaxSync:y};return x}); +(function(s,c){typeof exports=="object"&&typeof module!="undefined"?module.exports=c(require("vue")):typeof define=="function"&&define.amd?define(["vue"],c):(s=typeof globalThis!="undefined"?globalThis:s||self,s["vue-mathjax"]=c(s.Vue))})(this,function(s){"use strict";function c(e,t,r,n){var a,o=!1,g=0;function J(){a&&clearTimeout(a)}function T(){J(),o=!0}typeof t!="boolean"&&(n=r,r=t,t=void 0);function A(){for(var j=arguments.length,M=new Array(j),p=0;pe?l():t!==!0&&(a=setTimeout(n?Q:l,n===void 0?e-v:e))}return A.cancel=T,A}function $(e,t,r){return r===void 0?c(e,t,!1):c(e,r,t!==!1)}let d=!1,u=!1,i=[];function h(){return window.MathJax}function C(){const e=h();if((!e||!e.version)&&(d=!1,u=!1,i.splice(0,i.length)),!d){const t=document.createElement("script");t.src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js",t.async=!0,document.head.appendChild(t),d=!0}}function y(e={},t){const n=Object.assign({},{tex:{inlineMath:[["$","$"]],displayMath:[["$$","$$"]],processEnvironments:!0,processRefs:!0},options:{skipHtmlTags:["script","noscript","style","textarea","pre","code","annotation","annotation-xml"],ignoreHtmlClass:"tex2jax_ignore"},startup:{pageReady:()=>{u=!0,h().typeset(i.map(a=>a.el)),i.forEach(a=>{a.type=="async"&&a.callback()}),i.splice(0,i.length),t&&t()}},svg:{fontCache:"global"}},e);window.MathJax=n,C()}function E(e){if(!u){Array.isArray(e)?i.concat(e.map(t=>({type:"sync",el:t}))):i.push({type:"sync",el:e});return}window.MathJax.typeset(Array.isArray(e)?e:[e])}async function R(e){return new Promise((t,r)=>{if(u)return window.MathJax.typesetPromise(Array.isArray(e)?e:[e]);if(Array.isArray(e)){for(let n=0;n{let e=[];for(const t of f.values())e.push(t),window.MathJax.typeset(e);f.clear()},x=$(500,!1,m);function S(e,t=!1){u||(Array.isArray(e)?i.concat(e.map(r=>({type:"sync",el:r}))):i.push({type:"sync",el:e})),Array.isArray(e)?e.forEach(r=>f.add(r)):f.add(e),t?(x.cancel(),m()):x()}const w=s.defineComponent({setup(e){let t;const r=()=>{!t||S(t)};return s.onMounted(()=>{var n,a,o;y(),t=(o=(a=(n=s.getCurrentInstance())==null?void 0:n.vnode)==null?void 0:a.el)==null?void 0:o.parentNode,s.nextTick(()=>{r()})}),s.onUpdated(()=>{var n,a,o;t=(o=(a=(n=s.getCurrentInstance())==null?void 0:n.vnode)==null?void 0:a.el)==null?void 0:o.parentNode,r()}),s.onUnmounted(()=>{t=null}),(n,a)=>s.renderSlot(n.$slots,"default")}});function I(e){e.component("math-jax",w)}var O={install:I,MathJax:w,initMathJax:y,renderByMathJax:R,renderByMathJaxSync:E};return O}); diff --git a/package.json b/package.json index e25ab38..3948018 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vue3-mathjax", "private": false, - "version": "0.0.2", + "version": "0.0.3", "main": "dist/vue3-mathjax.umd.js", "module": "dist/vue3-mathjax.es.js", "types": "types/index.d.ts", @@ -25,10 +25,12 @@ "format": "prettier --write src/**/*.{js,ts,vue,tsx}" }, "dependencies": { + "throttle-debounce": "^3.0.1", "vue": "^3.2.25" }, "devDependencies": { "@types/node": "^17.0.21", + "@types/throttle-debounce": "^2.1.0", "@vitejs/plugin-vue": "^2.2.0", "typescript": "^4.5.4", "vite": "^2.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f60308e..e0064de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,7 +2,9 @@ lockfileVersion: 5.3 specifiers: '@types/node': ^17.0.21 + '@types/throttle-debounce': ^2.1.0 '@vitejs/plugin-vue': ^2.2.0 + throttle-debounce: ^3.0.1 typescript: ^4.5.4 vite: ^2.8.0 vite-plugin-dts: ^0.9.9 @@ -10,10 +12,12 @@ specifiers: vue-tsc: ^0.29.8 dependencies: + throttle-debounce: 3.0.1 vue: 3.2.31 devDependencies: '@types/node': 17.0.21 + '@types/throttle-debounce': 2.1.0 '@vitejs/plugin-vue': 2.2.4_vite@2.8.5+vue@3.2.31 typescript: 4.6.2 vite: 2.8.5 @@ -90,6 +94,10 @@ packages: resolution: {integrity: sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==} dev: true + /@types/throttle-debounce/2.1.0: + resolution: {integrity: sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==} + dev: true + /@vitejs/plugin-vue/2.2.4_vite@2.8.5+vue@3.2.31: resolution: {integrity: sha512-ev9AOlp0ljCaDkFZF3JwC/pD2N4Hh+r5srl5JHM6BKg5+99jiiK0rE/XaRs3pVm1wzyKkjUy/StBSoXX5fFzcw==} engines: {node: '>=12.0.0'} @@ -952,6 +960,11 @@ packages: engines: {node: '>= 0.4'} dev: true + /throttle-debounce/3.0.1: + resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} + engines: {node: '>=10'} + dev: false + /to-fast-properties/2.0.0: resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=} engines: {node: '>=4'} diff --git a/src/components/MathJax.vue b/src/components/MathJax.vue index 788f781..79e188e 100644 --- a/src/components/MathJax.vue +++ b/src/components/MathJax.vue @@ -8,16 +8,16 @@ import { getCurrentInstance, nextTick, onUpdated, - onUnmounted + onUnmounted, } from "vue"; -import { renderByMathJax, initMathJax } from "../utils/util"; +import { initMathJax, renderByMathJaxQueued } from "../utils/util"; let el: HTMLElement | null; -const renderMathJax = async () => { +const renderMathJax = () => { if (!el) return; - await renderByMathJax(el); + renderByMathJaxQueued(el); }; onMounted(() => { diff --git a/src/utils/util.ts b/src/utils/util.ts index 1d771ad..a2f7b64 100644 --- a/src/utils/util.ts +++ b/src/utils/util.ts @@ -1,3 +1,5 @@ +import { debounce } from "throttle-debounce"; + let mathJaxInjected = false; let mathJaxReady = false; let pendingQueue: ( @@ -42,7 +44,7 @@ export function initMathJax(options = {}, callback?: () => void) { inlineMath: [["$", "$"]], displayMath: [["$$", "$$"]], processEnvironments: true, - processRefs: true + processRefs: true, }, options: { skipHtmlTags: [ @@ -53,28 +55,28 @@ export function initMathJax(options = {}, callback?: () => void) { "pre", "code", "annotation", - "annotation-xml" + "annotation-xml", ], - ignoreHtmlClass: "tex2jax_ignore" + ignoreHtmlClass: "tex2jax_ignore", }, startup: { pageReady: () => { mathJaxReady = true; - mathJax().typeset(pendingQueue.map(v => v.el)); + mathJax().typeset(pendingQueue.map((v) => v.el)); - pendingQueue.forEach(v => { + pendingQueue.forEach((v) => { if (v.type == "async") v.callback(); }); pendingQueue.splice(0, pendingQueue.length); callback && callback(); - } + }, }, svg: { - fontCache: "global" - } + fontCache: "global", + }, }; const mergedOptions = Object.assign({}, defaultOptions, options); @@ -96,17 +98,17 @@ export function renderByMathJaxSync(el: HTMLElement | HTMLElement[]): void { if (!mathJaxReady) { if (Array.isArray(el)) { pendingQueue.concat( - el.map(v => { + el.map((v) => { return { type: "sync", - el: v + el: v, }; }) ); } else { pendingQueue.push({ type: "sync", - el + el, }); } @@ -129,22 +131,70 @@ export async function renderByMathJax( for (let i = 0; i < el.length; i++) { pendingQueue.push({ type: "sync", - el: el[i] + el: el[i], }); } pendingQueue.push({ type: "async", el: el[el.length - 1], - callback: resolve + callback: resolve, }); } else { pendingQueue.push({ type: "async", el, - callback: resolve + callback: resolve, }); } } }); } + +let waitingQueue: Set = new Set(); +let doRendering = () => { + let batch: HTMLElement[] = []; + + for (const el of waitingQueue.values()) { + batch.push(el); + + (window as any).MathJax.typeset(batch); + } + + waitingQueue.clear(); +}; + +let debouncedRendering = debounce(500, false, doRendering); + +export function renderByMathJaxQueued( + el: HTMLElement | HTMLElement[], + flush: boolean = false +) { + if (!mathJaxReady) { + if (Array.isArray(el)) { + pendingQueue.concat( + el.map((v) => { + return { + type: "sync", + el: v, + }; + }) + ); + } else { + pendingQueue.push({ type: "sync", el }); + } + } + + if (Array.isArray(el)) { + el.forEach((v) => waitingQueue.add(v)); + } else { + waitingQueue.add(el); + } + + if (flush) { + debouncedRendering.cancel(); + doRendering(); + } else { + debouncedRendering(); + } +} diff --git a/types/src/components/MathJax.vue.d.ts b/types/src/components/MathJax.vue.d.ts index 3fdcdf2..2b36fd6 100644 --- a/types/src/components/MathJax.vue.d.ts +++ b/types/src/components/MathJax.vue.d.ts @@ -1,5 +1,5 @@ declare const _sfc_main: import("vue").DefineComponent<{}, { el: HTMLElement | null; - renderMathJax: () => Promise; + renderMathJax: () => void; }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, import("vue").EmitsOptions, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly>, {}>; export default _sfc_main; diff --git a/types/src/index.d.ts b/types/src/index.d.ts index 3c358e8..548eb31 100644 --- a/types/src/index.d.ts +++ b/types/src/index.d.ts @@ -4,7 +4,7 @@ declare const _default: { install: typeof install; MathJax: import("vue").DefineComponent<{}, { el: HTMLElement | null; - renderMathJax: () => Promise; + renderMathJax: () => void; }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, import("vue").EmitsOptions, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly>, {}>; initMathJax: typeof initMathJax; renderByMathJax: typeof renderByMathJax; diff --git a/types/src/utils/util.d.ts b/types/src/utils/util.d.ts index 947252b..965ae96 100644 --- a/types/src/utils/util.d.ts +++ b/types/src/utils/util.d.ts @@ -5,3 +5,4 @@ export declare function isMathJaxInjected(): boolean; export declare function isMathJaxReady(): boolean; export declare function renderByMathJaxSync(el: HTMLElement | HTMLElement[]): void; export declare function renderByMathJax(el: HTMLElement | HTMLElement[]): Promise; +export declare function renderByMathJaxQueued(el: HTMLElement | HTMLElement[], flush?: boolean): void;