diff --git a/resource/decker/support/flyingFocus/flying-focus.js b/resource/decker/support/flyingFocus/flying-focus.js index 2c49bf9e..a0066bfc 100644 --- a/resource/decker/support/flyingFocus/flying-focus.js +++ b/resource/decker/support/flyingFocus/flying-focus.js @@ -35,6 +35,15 @@ export function showFlyingFocus(event) { } target = event.target; + // Navigate to the slide the focus target is located in if not in handout mode + if (!document.documentElement.classList.contains("handout")) { + const section = target.closest("section"); + if (section && !section.classList.contains("present")) { + const index = window.Reveal.getIndices(section); + window.Reveal.slide(index.h, index.v); + } + } + // set new position of flying focus Object.assign(flyingFocus.style, rectOf(target)); diff --git a/resource/decker/support/plugins/a11y/a11y.js b/resource/decker/support/plugins/a11y/a11y.js index a606bf29..e2163cad 100644 --- a/resource/decker/support/plugins/a11y/a11y.js +++ b/resource/decker/support/plugins/a11y/a11y.js @@ -27,7 +27,7 @@ function addScreenReaderSlideNumbers() { function addScreenReaderSlideNumber(slide, h, v) { const header = slide.querySelector("h1"); - if (header) { + if (header && header.textContent.trim() !== "") { const innerHTML = header.innerHTML; const replacementHTML = `${localization.slide} ${ h + 1 @@ -95,7 +95,7 @@ function addCustomSpacebarHandler() { } } -function toggleA11YMode() { +function toggleAccessibility() { a11yMode = !a11yMode; if (a11yMode) { @@ -111,6 +111,15 @@ function toggleA11YMode() { modifyMedia(audio); } Decker.flash.message(localization.accessible_colors_on); + if (window.MathJax) { + window.MathJax.startup.document.options.enableMenu = true; + window.MathJax.startup.document.menu.menu + .findID("Accessibility", "Activate") + .variable.setter(true); + window.MathJax.startup.document.menu.loadingPromise.then(() => { + window.MathJax.startup.document.rerender(); + }); + } } else { pluginButton.ariaPressed = false; pluginButton.setLabel(localization.activate_accessibility); @@ -124,6 +133,16 @@ function toggleA11YMode() { restoreMedia(audio); } Decker.flash.message(localization.accessible_colors_off); + if (window.MathJax) { + // Does it make sense to remove this again if once activated? + window.MathJax.startup.document.options.enableMenu = false; + window.MathJax.startup.document.menu.menu + .findID("Accessibility", "Activate") + .variable.setter(false); + window.MathJax.startup.document.menu.loadingPromise.then(() => { + window.MathJax.startup.document.rerender(); + }); + } } } @@ -162,9 +181,7 @@ const Plugin = { description: "Toggle Decker Accessibility Adjustments (Triple Click)", }, - Decker.tripleClick(() => { - toggleA11YMode(); - }) + Decker.tripleClick(toggleAccessibility) ); reveal.addEventListener("ready", () => { const menuPlugin = reveal.getPlugin("decker-menu"); @@ -173,13 +190,13 @@ const Plugin = { "decker-menu-a11y-button", "fa-universal-access", localization.activate_accessibility, - toggleA11YMode + toggleAccessibility ); } }); if (a11y) { Reveal.addEventListener("ready", () => { - toggleA11YMode(); + toggleAccessibility(); }); } }, diff --git a/resource/decker/support/plugins/math/math.js b/resource/decker/support/plugins/math/math.js index 27433f1d..8b0533c5 100644 --- a/resource/decker/support/plugins/math/math.js +++ b/resource/decker/support/plugins/math/math.js @@ -9,9 +9,7 @@ * Modifications by Mario Botsch: * - upgrade to MathJax v3 * - disable math typesetting on each slide change - * - disable AssistiveMML, since it duplicates math in speaker notes * - disable SVG font caches, since it doesn't work in speaker notes - * - reset menu settings in localStorage * - use promise mechanism to ensure that math is typset before PDF print * - fix links generated by referencing equations to jump to the slide * containing the referenced equation @@ -22,7 +20,7 @@ * Reveal's zoom plugin work on equations. */ -// reference to Reveal object +// This module's reference to Reveal let Reveal; function loadScript(url, callback) { @@ -53,23 +51,33 @@ function loadScript(url, callback) { head.appendChild(script); } -/* - * correct links generated by referencing equations, such that they - * point to the slide containing the referenced equation. - * Requires that each slide has a CSS id (as generated e.g. by pandoc/decker) - */ -function fixLinks() { - for (let a of document.getElementsByTagName("a")) { - let href = a.href; - if (href.baseVal) { - let label = href.baseVal; - if (label.includes("#mjx-eqn")) { - label = decodeURIComponent(label.substring(1)); - const eqn = document.getElementById(label); - if (eqn) { - const s = eqn.closest("section"); - if (s) { - a.href.baseVal = location.origin + location.pathname + "#" + s.id; +function adjustLinksDocument(doc) { + for (const item of doc.math) { + adjustLinksItem(item, doc); + } +} + +function adjustLinksItem(item, doc) { + const root = item.typesetRoot; + if (root) { + const anchors = root.querySelectorAll("a"); + for (const anchor of anchors) { + const href = anchor.href; + if (href.baseVal) { + let label = href.baseVal; + if (label.includes("#mjx-eqn")) { + label = decodeURIComponent(label.substring(1)); + const eqn = document.getElementById(label); + if (eqn) { + const s = eqn.closest("section"); + if (s) { + anchor.href.baseVal = + location.origin + + location.pathname + + location.search + + "#" + + s.id; + } } } } @@ -77,31 +85,40 @@ function fixLinks() { } } -/* - * If a multi-line equation is enclosed in a div with class math-incremental, - * then add class fragment to the individual rows of the equation, making it - * appear row-by-row. - */ -function setupMathIncremental() { - // unlabeled equations - for (let mrow of document.querySelectorAll( - '.reveal .math-incremental mjx-container svg g[data-mml-node="mtable"]:first-of-type > g[data-mml-node="mtr"]' - )) { - mrow.classList.add("fragment"); +function incrementalDocument(doc) { + for (const item of doc.math) { + incrementalItem(item, doc); } +} - // unlabeled equations - for (let mrow of document.querySelectorAll( - '.reveal .math-incremental mjx-container svg g[data-mml-node="mtable"]:first-of-type g[data-mml-node="mlabeledtr"]' - )) { - mrow.classList.add("fragment"); +function incrementalItem(item, mdoc) { + const doc = document.documentElement; + const root = item.typesetRoot; + if (root && root.closest(".math-incremental")) { + for (let mrow of root.querySelectorAll( + 'g[data-mml-node="mtable"]:first-of-type > g[data-mml-node="mtr"]' + )) { + mrow.classList.add("fragment"); + if (doc.classList.contains("handout") || doc.classList.contains("a11y")) { + mrow.classList.add("visible"); + } + } + for (let mrow of document.querySelectorAll( + 'g[data-mml-node="mtable"]:first-of-type g[data-mml-node="mlabeledtr"]' + )) { + mrow.classList.add("fragment"); + if (doc.classList.contains("handout") || doc.classList.contains("a11y")) { + mrow.classList.add("visible"); + } + } } } +/* /* * remove fragments from assistive MML blocks */ -function fixAssistiveMML() { +function fixAssistiveMML(doc) { for (let elem of document.querySelectorAll("mjx-assistive-mml .fragment")) { elem.classList.remove("fragment"); } @@ -135,6 +152,9 @@ function injectStyle() { document.head.append(style); } +// Is initial a11y mode requested? +const a11y = /a11y/gi.test(window.location.search); + const Plugin = { id: "math", @@ -144,38 +164,43 @@ const Plugin = { // get configuration, built MathJax URL const options = Reveal.getConfig().math || {}; if (!options.mathjax) { - console.error("MathJax not properly configured. Call Hauer."); + console.error( + "No MathJax source URI has been configured. This should not happen!", + "The config.math.mathjax value is usually configured in your resource pack's 'deck.html'", + "Please contact the developers: https://github.com/decker-edu/decker" + ); return; } const url = options.mathjax + "tex-svg.js"; - // remove menu settings, which are stored in localStorage. - // otherwise user could select CHTML renderer, which is not - // installed in decker. - if (window.localStorage) { - window.localStorage.removeItem("MathJax-Menu-Settings"); + // define \fragment{...} funtion + let macros = { fragment: ["\\class{fragment}{#1}", 1] }; + // add user-defined Latex macros + if (options.macros) { + macros = Object.assign(macros, options.macros); } - // configure through global MathJax object + const language = Decker.meta.lang || navigator.language; + + /* MathJax configuration object */ window.MathJax = { - loader: { - load: [ - "[tex]/ams", - // "a11y/assistive-mml", - // "a11y/explorer", - // "a11y/semantic-enrich", - // "a11y/complexity", - // "a11y/sre", - ], - typeset: false, - }, startup: { ready: () => { - console.log("mathjax loaded"); + /* Workaround to allow loading of a11y features past initial load + * Necessary due do a bug in 3.2.2 throwing a Mathjax.retry error. */ + const { mathjax } = window.MathJax._.mathjax; + const { STATE } = window.MathJax._.core.MathItem; + const { Menu } = window.MathJax._.ui.menu.Menu; + const rerender = Menu.prototype.rerender; + Menu.prototype.rerender = function (start = STATE.TYPESET) { + mathjax.handleRetriesFor(() => { + rerender.call(this, start); + }); + }; }, }, svg: { - scale: Decker.meta.math.scale || 1.0, // global scaling factor for all expressions + scale: window.Decker.meta.math.scale || 1.0, // global scaling factor for all expressions minScale: 0.5, // smallest scaling factor to use mtextInheritFont: true, // true to make mtext elements use surrounding font merrorInheritFont: true, // true to make merror text use surrounding font @@ -191,9 +216,6 @@ const Plugin = { }, tex: { tags: "ams", - packages: { - "[+]": ["ams"], - }, inlineMath: [ // start/end delimiter pairs for in-line math ["$", "$"], @@ -204,60 +226,42 @@ const Plugin = { ["$$", "$$"], ["\\[", "\\]"], ], + macros: macros, }, options: { - enableMenu: false, - // enableMenu: true, - // enableEnrichment: true, - // enableComplexity: true, - // enableExplorer: true, - // menuOptions: { - // settings: { - // assistiveMml: true, - // collapsible: false, // messes up spacing in some equations - // explorer: true, - // }, - // }, - // a11y: { - // speech: true, - // braille: true, - // }, - // sre: { - // speech: "deep", - // domain: "mathspeak", - // style: "default", - // locale: window.navigator.language, - // }, + renderActions: { + incremental: [1000, incrementalDocument, incrementalItem, false], + adjustLinks: [1001, adjustLinksDocument, adjustLinksItem, false], + fixmml: [1002, fixAssistiveMML, "", false], + }, + sre: { + locale: language === "de" ? "de" : "en", + }, + enableMenu: a11y, + menuOptions: { + settings: { + explorer: a11y, //if in a11y page mode: active by default + }, + }, + a11y: { + backgroundColor: "Green", + backgroundOpacity: 50, + foregroundColor: "Black", + foregroundOpacity: 100, + }, }, }; - // define \fragment{...} funtion - let macros = { fragment: ["\\class{fragment}{#1}", 1] }; - // add user-defined Latex macros - if (options.macros) { - macros = Object.assign(macros, options.macros); - } - window.MathJax.tex.macros = macros; + injectStyle(); - // use promise mechanism to make sure that math typesetting - // is performend before Reveal fires ready-event or - // generates a PDF + /* Return a promise to reveal to make it wait until startup.promise resolves. */ return new Promise((resolve) => { - // load mathjax script loadScript(url, () => { - // Typeset followed by an immediate reveal.js layout since - // the typesetting process could affect slide height - console.time("mathjax typesetting"); - window.MathJax.startup.defaultReady(); window.MathJax.startup.promise.then(() => { - console.timeEnd("mathjax typesetting"); Reveal.layout(); - fixLinks(); - setupMathIncremental(); - fixAssistiveMML(); - injectStyle(); resolve(); }); + window.MathJax.startup.defaultReady(); }); }); }, diff --git a/resource/decker/support/plugins/whiteboard/whiteboard.js b/resource/decker/support/plugins/whiteboard/whiteboard.js index 270be126..6830cd38 100644 --- a/resource/decker/support/plugins/whiteboard/whiteboard.js +++ b/resource/decker/support/plugins/whiteboard/whiteboard.js @@ -108,8 +108,8 @@ function readConfig() { ]; // reveal setting wrt slide dimension - pageHeight = Reveal.getConfig().height; - pageWidth = Reveal.getConfig().width; + pageHeight = parseInt(Reveal.getConfig().height); + pageWidth = parseInt(Reveal.getConfig().width); // reveal elements slides = document.querySelector(".reveal .slides"); diff --git a/resource/mario/support/css/mario-page.css b/resource/mario/support/css/mario-page.css index 9de2b7fd..8479197c 100644 --- a/resource/mario/support/css/mario-page.css +++ b/resource/mario/support/css/mario-page.css @@ -1,119 +1,120 @@ @import url("../fonts/lato.css"); :root { - --blue: #2a9ddf; - --light-blue: #30B3FF; - --emphColor: var(--blue); - --icon-active-color: #2a9ddf; - --icon-inactive-color: lightgrey; - --icon-size: 2vmin; + --blue: #2a9ddf; + --light-blue: #30b3ff; + --emphColor: var(--blue); + --icon-active-color: #2a9ddf; + --icon-inactive-color: lightgrey; + --icon-size: 2vmin; } /* repeat light mode settings from light.css to override dark mode settings, which don't look nice */ :root { - --background-body: #ffffff; - --background: #efefef; - --background-alt: #f7f7f7; - - --selection: #9e9e9e; - - --text-main: #363636; - --text-bright: #000000; - --text-muted: #999999; - - --links: #0076d1; - --focus: #0096bfab; - --border: #dbdbdb; - --code: #000000; - - --animation-duration: 0.1s; - --button-hover: #dddddd; - - --scrollbar-thumb: rgb(213, 213, 213); - --scrollbar-thumb-hover: rgb(196, 196, 196); - - --form-placeholder: #949494; - --form-text: #000000; - - --variable: #39a33c; - --highlight: #ffff00; + --background-body: #ffffff; + --background: #efefef; + --background-alt: #f7f7f7; + + --selection: #9e9e9e; + + --text-main: #363636; + --text-bright: #000000; + --text-muted: #999999; + + --links: #0076d1; + --focus: #0096bfab; + --border: #dbdbdb; + --code: #000000; + + --animation-duration: 0.1s; + --button-hover: #dddddd; + + --scrollbar-thumb: rgb(213, 213, 213); + --scrollbar-thumb-hover: rgb(196, 196, 196); + + --form-placeholder: #949494; + --form-text: #000000; + + --variable: #39a33c; + --highlight: #ffff00; } body { - background: #ffffff; - background-color: #ffffff; - font-family: "Lato"; - color: #222; + background: #ffffff; + background-color: #ffffff; + font-family: "Lato"; + color: #222; } header { - background: var(--blue); - text-align: center; + background: var(--blue); + text-align: center; } -header > h1, header > h2 { - color: white; +header > h1, +header > h2 { + color: white; } header > h1 { - font-size: 50px; + font-size: 50px; } h1 { - margin-top: 3rem; + margin-top: 3rem; } hr { - margin-top: 2rem; + margin-top: 2rem; } a { - color: var(--blue); + color: var(--blue); } a:hover { - color: var(--lightblue); + color: var(--lightblue); } details { - outline: none; - border: 1px solid black; - border-radius: 4px; - padding: 10px; - margin-bottom:10px; + outline: none; + border: 1px solid black; + border-radius: 4px; + padding: 10px; + margin-bottom: 10px; } details summary { - outline: none; - padding: 4px; + outline: none; + padding: 4px; } details summary:hover { - background-color: #2a9ddf58; + background-color: #2a9ddf58; } details summary[icon]::marker { - display: inline-block; - font-style: normal; - font-variant: normal; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - font-family: "Font Awesome 5 Free"; - font-weight: 900; - color: var(--blue); - content: attr(icon); + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + font-family: "Font Awesome 5 Free"; + font-weight: 900; + color: var(--blue); + content: attr(icon); } details summary::after { - font-style: italic; - content: '(click)...' + font-style: italic; + content: "(click)..."; } :lang(de) details summary::after { - content: '(klicken)...' + content: "(klicken)..."; } details input { - box-sizing: border-box; - width: 100%; -} \ No newline at end of file + box-sizing: border-box; + width: 100%; +} diff --git a/resource/tudo/support/css/tudo-deck.css b/resource/tudo/support/css/tudo-deck.css index 15b638fe..d8ef29e6 100644 --- a/resource/tudo/support/css/tudo-deck.css +++ b/resource/tudo/support/css/tudo-deck.css @@ -1,5 +1,4 @@ @import url("../vendor/fontawesome/css/all.css"); -@import url("../fonts/lato.css"); /********************************************* * GLOBAL STYLES @@ -11,7 +10,6 @@ body { background: var(--background-color); - font-family: "Lato", sans-serif; color: var(--foreground-color); accent-color: var(--accent3); } diff --git a/resource/tudo/support/css/tudo-index.css b/resource/tudo/support/css/tudo-index.css index aef63704..9680db76 100644 --- a/resource/tudo/support/css/tudo-index.css +++ b/resource/tudo/support/css/tudo-index.css @@ -1,5 +1,4 @@ @import url("../vendor/fontawesome/css/all.css"); -@import url("../fonts/lato.css"); /**********************/ /* Variables @@ -90,13 +89,11 @@ details input { html { width: 100%; height: 100dvh; - font-family: "Lato"; position: relative; accent-color: var(--accent3); } body.index { - font-family: "Lato"; display: flex; flex-direction: column; flex-wrap: nowrap; diff --git a/resource/tudo/support/css/tudo-page.css b/resource/tudo/support/css/tudo-page.css index 61a3de98..74efed39 100644 --- a/resource/tudo/support/css/tudo-page.css +++ b/resource/tudo/support/css/tudo-page.css @@ -1,5 +1,4 @@ @import url("../vendor/fontawesome/css/all.css"); -@import url("../fonts/lato.css"); /**********************/ /* Variables @@ -349,12 +348,10 @@ details input { html { width: 100%; height: 100vh; - font-family: "Lato"; position: relative; } body { - font-family: "Lato"; display: flex; flex-direction: column; flex-wrap: nowrap; diff --git a/resource/tudo/support/fonts/AtkinsonHyperlegible-Bold.ttf b/resource/tudo/support/fonts/AtkinsonHyperlegible-Bold.ttf new file mode 100644 index 00000000..c72b4889 Binary files /dev/null and b/resource/tudo/support/fonts/AtkinsonHyperlegible-Bold.ttf differ diff --git a/resource/tudo/support/fonts/AtkinsonHyperlegible-BoldItalic.ttf b/resource/tudo/support/fonts/AtkinsonHyperlegible-BoldItalic.ttf new file mode 100644 index 00000000..ff966b11 Binary files /dev/null and b/resource/tudo/support/fonts/AtkinsonHyperlegible-BoldItalic.ttf differ diff --git a/resource/tudo/support/fonts/AtkinsonHyperlegible-Italic.ttf b/resource/tudo/support/fonts/AtkinsonHyperlegible-Italic.ttf new file mode 100644 index 00000000..1cf113a0 Binary files /dev/null and b/resource/tudo/support/fonts/AtkinsonHyperlegible-Italic.ttf differ diff --git a/resource/tudo/support/fonts/AtkinsonHyperlegible-Regular.ttf b/resource/tudo/support/fonts/AtkinsonHyperlegible-Regular.ttf new file mode 100644 index 00000000..23614a4d Binary files /dev/null and b/resource/tudo/support/fonts/AtkinsonHyperlegible-Regular.ttf differ diff --git a/resource/tudo/support/fonts/atkinson.css b/resource/tudo/support/fonts/atkinson.css new file mode 100644 index 00000000..5d2f8a1c --- /dev/null +++ b/resource/tudo/support/fonts/atkinson.css @@ -0,0 +1,35 @@ +@font-face { + font-family: "Atkinson"; + src: url("AtkinsonHyperlegible-Bold.ttf") format("truetype"); + font-style: normal; + font-weight: bold; + text-rendering: optimizeLegibility; +} + +@font-face { + font-family: "Atkinson"; + src: url("AtkinsonHyperlegible-BoldItalic.ttf") format("truetype"); + font-style: italic; + font-weight: bold; + text-rendering: optimizeLegibility; +} + +@font-face { + font-family: "Atkinson"; + src: url("AtkinsonHyperlegible-Italic.ttf") format("truetype"); + font-style: italic; + font-weight: normal; + text-rendering: optimizeLegibility; +} + +@font-face { + font-family: "Atkinson"; + src: url("AtkinsonHyperlegible-Regular.ttf") format("truetype"); + font-style: normal; + font-weight: normal; + text-rendering: optimizeLegibility; +} + +body { + font-family: "Atkinson", sans-serif; +} diff --git a/resource/tudo/support/fonts/lato.css b/resource/tudo/support/fonts/lato.css index 7a4e83d3..d74aa08e 100644 --- a/resource/tudo/support/fonts/lato.css +++ b/resource/tudo/support/fonts/lato.css @@ -33,3 +33,7 @@ font-weight: normal; text-rendering: optimizeLegibility; } + +body { + font-family: "Lato", sans-serif; +} diff --git a/resource/tudo/template/deck-styles.html b/resource/tudo/template/deck-styles.html index 1e05ee48..45a2c0fd 100644 --- a/resource/tudo/template/deck-styles.html +++ b/resource/tudo/template/deck-styles.html @@ -38,6 +38,11 @@ + $if(template.font)$ + + $else$ + + $endif$ $for(template.css)$ diff --git a/resource/tudo/template/index.html b/resource/tudo/template/index.html index f44518fe..1754dd2c 100644 --- a/resource/tudo/template/index.html +++ b/resource/tudo/template/index.html @@ -56,6 +56,11 @@ + $if(template.font)$ + + $else$ + + $endif$ $for(template.index.css)$ diff --git a/resource/tudo/template/page.html b/resource/tudo/template/page.html index ef9e2e88..0d48e1b9 100644 --- a/resource/tudo/template/page.html +++ b/resource/tudo/template/page.html @@ -49,6 +49,11 @@ + $if(template.font)$ + + $else$ + + $endif$ $for(template.css)$ diff --git a/test/decks/math-deck.md b/test/decks/math-deck.md index bac39019..52a4dd4d 100644 --- a/test/decks/math-deck.md +++ b/test/decks/math-deck.md @@ -40,15 +40,40 @@ $$ $$\lim_{x \to \infty} \exp(-x) = 0$$ +# labeled equation + +$$\begin{equation} + E = mc^2 + \label{eq:einstein} +\end{equation}$$ + # test4 + [$$ + \begin{eqnarray*} + a &=& b \\ + a^2 &=& ab \\ + 2a^2 &=& a^2 + ab \\ + 2a^2-2ab &=& a^2 - ab \\ + 2a(a-b) &=& a (a-b) \\ + 2a &=& a \\ + 2 &=& 1 + \end{eqnarray*} + $$]{ .math-incremental } + +::: footer +Reference label: $\eqref{eq:einstein}$ +::: + +# test5 + This slide contains a math equation in the speaker notes. Press `s` to show it. ::: notes Notes with math! $$\sum_i \pi^i \to \infty$$ ::: -# test5 +# test6 Test speaker notes again. diff --git a/third-party/Font-Awesome b/third-party/Font-Awesome index 0698449d..f0c25837 160000 --- a/third-party/Font-Awesome +++ b/third-party/Font-Awesome @@ -1 +1 @@ -Subproject commit 0698449d50f2b95517562295a59d414afc68b369 +Subproject commit f0c25837a3fe0e03783b939559e088abcbfb3c4b diff --git a/third-party/MathJax b/third-party/MathJax index 7146ffa4..600692ad 160000 --- a/third-party/MathJax +++ b/third-party/MathJax @@ -1 +1 @@ -Subproject commit 7146ffa47956e7dae05739cfe905d8aaf1e4780a +Subproject commit 600692ad9d3552cc25f85510d5797bc942ecc9f7