diff --git a/news/changelog-1.7.md b/news/changelog-1.7.md index 23a7ff159ed..ff925c0891b 100644 --- a/news/changelog-1.7.md +++ b/news/changelog-1.7.md @@ -120,6 +120,7 @@ All changes included in 1.7: ### `jupyter` - ([#9089](https://github.com/quarto-dev/quarto-cli/issues/9089)): Serialize compound `jupyter` metadata into a special key-value attribute to not break Pandoc's fenced div parsing. +- ([#10113](https://github.com/quarto-dev/quarto-cli/issues/10113)): KaTeX will now load correctly in `engine: jupyter` documents using `emebed-resources: true`. - ([#12114](https://github.com/quarto-dev/quarto-cli/issues/12114)): `JUPYTERCACHE` environment variable from [Jupyter cache CLI](https://jupyter-cache.readthedocs.io/en/latest/using/cli.html) is now respected by Quarto when `cache: true` is used. This environment variable allows to change the path of the cache directory. - ([#12228](https://github.com/quarto-dev/quarto-cli/issues/12228)): `quarto render` will now fails if errors are detected at IPython display level. Setting `error: true` globally or at cell level will keep the error to show in output and not stop the rendering. - ([#12374](https://github.com/quarto-dev/quarto-cli/issues/12374)): Detect language properly in Jupyter notebooks that lack the `language` field in their `kernelspec`s. diff --git a/src/command/render/template.ts b/src/command/render/template.ts index 7a70ca25470..7870e772728 100644 --- a/src/command/render/template.ts +++ b/src/command/render/template.ts @@ -270,26 +270,47 @@ function katexScript(url: string) { link.rel = "stylesheet"; link.href = "${url}katex.min.css"; head.appendChild(link); - - var script = document.createElement("script"); - script.type = "text/javascript"; - script.src = "${url}katex.min.js"; - script.async = false; - script.addEventListener('load', function() { + + function renderMathElements() { var mathElements = document.getElementsByClassName("math"); - var macros = []; - for (var i = 0; i < mathElements.length; i++) { - var texText = mathElements[i].firstChild; - if (mathElements[i].tagName == "SPAN") { + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + if (window.katex) { window.katex.render(texText.data, mathElements[i], { displayMode: mathElements[i].classList.contains('display'), throwOnError: false, macros: macros, fleqn: false }); + } else { + console.error("KaTeX has not been loaded correctly, as not found globally."); } } - }); + } + } + + var script = document.createElement("script"); + script.src = "${url}katex.min.js"; + script.onload = renderMathElements; + + // Check for RequireJS and AMD detection as it conflicts with KaTeX loading. + if (typeof require === 'function' && typeof define === 'function' && define.amd) { + // Disable require.js AMD detection temporarily, as it conflicts with KaTeX loading using CommonJS + var disableAmdScript = document.createElement("script"); + disableAmdScript.textContent = 'window._amd_backup = window.define.amd; window.define.amd = false;'; + head.appendChild(disableAmdScript); + + // overwrite onload to restore Require.js AMD detection + script.onload = function() { + // Restore Require.js AMD detection + window.define.amd = window._amd_backup; + delete window._amd_backup; + renderMathElements(); + }; + } + head.appendChild(script); }); diff --git a/tests/docs/playwright/html/math/katex/embed-except-math.qmd b/tests/docs/playwright/html/math/katex/embed-except-math.qmd new file mode 100644 index 00000000000..bb4c9f9e30e --- /dev/null +++ b/tests/docs/playwright/html/math/katex/embed-except-math.qmd @@ -0,0 +1,12 @@ +--- +format: html +html-math-method: katex +embed-resources: true +--- + +$\alpha$ + +```{python} +import pandas as pd +pd.DataFrame([1]) +``` diff --git a/tests/docs/playwright/html/math/katex/embed-with-math.qmd b/tests/docs/playwright/html/math/katex/embed-with-math.qmd new file mode 100644 index 00000000000..aa20c3a4c77 --- /dev/null +++ b/tests/docs/playwright/html/math/katex/embed-with-math.qmd @@ -0,0 +1,13 @@ +--- +format: html +html-math-method: katex +embed-resources: true +self-contained-math: true +--- + +$\alpha$ + +```{python} +import pandas as pd +pd.DataFrame([1]) +``` diff --git a/tests/docs/playwright/html/math/katex/not-embed.qmd b/tests/docs/playwright/html/math/katex/not-embed.qmd new file mode 100644 index 00000000000..0c7860132ed --- /dev/null +++ b/tests/docs/playwright/html/math/katex/not-embed.qmd @@ -0,0 +1,11 @@ +--- +format: html +html-math-method: katex +--- + +$\alpha$ + +```{python} +import pandas as pd +pd.DataFrame([1]) +``` diff --git a/tests/integration/playwright/tests/html-math-katex.spec.ts b/tests/integration/playwright/tests/html-math-katex.spec.ts new file mode 100644 index 00000000000..3075f1625fc --- /dev/null +++ b/tests/integration/playwright/tests/html-math-katex.spec.ts @@ -0,0 +1,17 @@ +import { test, expect } from '@playwright/test'; + +test.describe('KaTeX math rendering in Jupyter engine document', () => { + const testCases = [ + { url: 'html/math/katex/not-embed.html', description: 'not embedding resources' }, + { url: 'html/math/katex/embed-with-math.html', description: 'embedding resources including Math' }, + { url: 'html/math/katex/embed-except-math.html', description: 'embedding resources except Math' } + ]; + + for (const { url, description } of testCases) { + test(`KaTeX math is rendered while ${description}`, async ({ page }) => { + await page.goto(url); + // Check that math is rendered + await expect(page.locator("span.katex")).toContainText('α'); + }); + } +});