Commit e894bbad authored by Mario Botsch's avatar Mario Botsch
Browse files

Merge branch 'master' into mario

parents 2ed2d99e 60ba40a9
......@@ -258,14 +258,23 @@ run = do
need [src]
command [] "sass" [src, out]
--
"**/*.plantuml.svg" %> \out -> do
let src = dropExtension out
need [src]
putNormal $ "# plantuml (for " <> out <> ")"
plantuml [src]
liftIO $ Dir.renameFile (src -<.> "svg") out
--
"**/*.dot.svg" %> \out -> do
let src = dropExtension out
need [src]
putNormal $ "# dot (for " <> out <> ")"
dot ["-o" ++ out, src]
--
"**/*.gnuplot.svg" %> \out -> do
let src = dropExtension out
need [src]
putNormal $ "# gnuplot (for " <> out <> ")"
gnuplot ["-e", "\"set output '" ++ out ++ "'\"", src]
--
"**/*-recording.mp4" %> \out -> do
......
......@@ -59,10 +59,26 @@ An SVG image that is embedded into the HTML document.
translates to
``` {.html}
<span class="decker svg embed" style="background-color:magenta;">
<svg>This space intentionally left blank</svg>
</span>
<div class="decker image error">
<h2 class="title">
<i class="fa fa-exclamation-triangle">
</i>
Decker error
</h2>
<p class="message">
test/decks/empty.svg: openFile: does not exist (No such file or directory)
</p>
<p>
encountered while processing
</p>
<pre class="markup">
<code class="markup">
![](/test/decks/empty.svg){.embed css:background-color=&quot;magenta&quot;}
</code>
</pre>
</div>
```
------------------------------------------------------------------------
......
......@@ -382,56 +382,56 @@ div.q-panel div.q-footer div.q-login:hover {
color: var(--whiteboard-active-color);
}
div.q-panel div.content {
div.q-panel div.item {
font-size: 1em;
}
div.q-panel div.content em {
div.q-panel div.item em {
font-style: italic;
}
div.q-panel div.content strong {
div.q-panel div.item strong {
font-weight: bold;
}
div.q-panel div.content a {
div.q-panel div.item a {
color: darkblue;
}
div.q-panel div.content p,
div.q-panel div.item p,
div.q-panel ul,
div.q-panel ol {
padding-bottom: 0.3em;
}
div.q-panel div.content p:last-child,
div.q-panel div.content ul:last-child,
div.q-panel div.content ol:last-child {
div.q-panel div.item p:last-child,
div.q-panel div.item ul:last-child,
div.q-panel div.item ol:last-child {
padding-bottom: 0;
}
div.q-panel div.content ol {
div.q-panel div.item ol {
list-style-type: lower-alpha;
list-style-position: inside;
}
div.q-panel div.content ul {
div.q-panel div.item ul {
list-style-type: disc;
list-style-position: inside;
}
div.q-panel div.content code {
div.q-panel div.item code {
font-family: Consolas, Monaco, monospace;
font-size: 0.9em;
}
div.q-panel div.content pre {
div.q-panel div.item pre {
padding: 0.2em;
background-color: #eee;
white-space: pre-wrap;
}
div.q-panel div.content h1 {
div.q-panel div.item h1 {
font-size: 1.2em;
font-weight: bold;
padding-bottom: 0.2em;
......@@ -439,7 +439,7 @@ div.q-panel div.content h1 {
color: #333;
}
div.q-panel div.content h2 {
div.q-panel div.item h2 {
font-size: 1.1em;
font-weight: bold;
padding-bottom: 0.2em;
......@@ -447,7 +447,7 @@ div.q-panel div.content h2 {
color: #333;
}
div.q-panel div.content img {
div.q-panel div.item img {
width: 100%;
image-rendering: pixelated;
}
......
......@@ -33,7 +33,6 @@ function deckerStart() {
// if (!printMode) {
// setTimeout(continueWhereYouLeftOff, 500);
// }
renderSvgMath();
}
function prepareTaskLists() {
......@@ -294,22 +293,6 @@ function continueWhereYouLeftOff() {
}
}
// TODO: Make geometry.js into a proper module and arrange it to be loaded after
// TODO: MathJax.
function renderSvgMath() {
// Create a copy of the script with type 'geometry' that has type 'module' and
// will be executed immediately. Defers script execution until after MathJax
// has been initialized. Deletes the original 'geometry' script.
let scripts = document.querySelectorAll("script[type=geometry]");
for (let script of scripts) {
let js = document.createElement("script");
js.setAttribute("type", "module");
js.innerText = script.innerText;
script.insertAdjacentElement("beforebegin", js);
script.parentNode.removeChild(script);
}
}
// List of predicates that all must return true for a requested reload to
// actually be performed.
let reloadInhibitors = [];
......
......@@ -12,7 +12,7 @@
* - 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
* - fix links generated by referencing equations to jump to the slide
* containing the referenced equation
* - inject class=fragment to incrementally show multi-line equations
* (if MathJax element in enclosed in div.math-incremental)
......@@ -23,105 +23,96 @@
"use strict";
let RevealMath = window.RevealMath || (function(){
let options = Reveal.getConfig().math || {};
let mathjax = options.mathjax || 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/';
let url = mathjax + 'tex-svg.js';
function loadScript( url, callback )
{
var head = document.querySelector( 'head' );
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.id = 'MathJax-script';
script.src = url;
// Wrapper for callback to make sure it only fires once
var finish = function()
{
if( typeof callback === 'function' )
{
callback.call();
callback = null;
}
}
script.onload = finish;
// IE
script.onreadystatechange = function() {
if ( this.readyState === 'loaded' ) {
finish();
}
}
// Normal browsers
head.appendChild( script );
}
let RevealMath =
window.RevealMath ||
(function () {
let options = Reveal.getConfig().math || {};
let mathjax =
options.mathjax || "https://cdn.jsdelivr.net/npm/mathjax@3/es5/";
let url = mathjax + "tex-svg.js";
function loadScript(url, callback) {
var head = document.querySelector("head");
var script = document.createElement("script");
script.type = "text/javascript";
script.id = "MathJax-script";
script.src = url;
// Wrapper for callback to make sure it only fires once
var finish = function () {
if (typeof callback === "function") {
callback.call();
callback = null;
}
};
script.onload = finish;
// IE
script.onreadystatechange = function () {
if (this.readyState === "loaded") {
finish();
}
};
// Normal browsers
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 (var a of document.getElementsByTagName("a"))
{
var href = a.href;
if (href.baseVal)
{
var label = href.baseVal;
if (label.includes("#mjx-eqn"))
{
label = decodeURIComponent(label.substring(1));
var eqn = document.getElementById(label);
if (eqn)
{
var s = eqn.closest("section");
if (s)
{
a.href.baseVal = location.origin + location.pathname + "#" + s.id;
}
}
}
function fixLinks() {
for (var a of document.getElementsByTagName("a")) {
var href = a.href;
if (href.baseVal) {
var label = href.baseVal;
if (label.includes("#mjx-eqn")) {
label = decodeURIComponent(label.substring(1));
var eqn = document.getElementById(label);
if (eqn) {
var s = eqn.closest("section");
if (s) {
a.href.baseVal =
location.origin + location.pathname + "#" + s.id;
}
}
}
}
}
}
/*
* 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");
}
// 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 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");
}
// 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");
}
}
/*
* Inject CSS rules that (i) make SVG equations automatically shrink down to
* fit the enclosing container and (ii) remove pointer events from the
* fit the enclosing container and (ii) remove pointer events from the
* equation parts, such that Reveal's zoom plugin work nicely on equations, too.
*/
function injectStyle()
{
const style = document.createElement('style');
style.textContent = String.raw`
function injectStyle() {
const style = document.createElement("style");
style.textContent = String.raw`
/* fit equation into container */
mjx-container > svg {
object-fit: contain;
......@@ -139,113 +130,104 @@ let RevealMath = window.RevealMath || (function(){
pointer-events: all;
}
`;
document.head.append(style);
document.head.append(style);
}
return {
init: function() {
// 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");
}
// configure through global MathJax object
window.MathJax = {
loader: {
load: ['[tex]/ams'],
typeset: false
},
startup: {
ready: () => {
console.log('mathjax loaded');
//MathJax.startup.defaultReady();
}
},
svg: {
scale: 0.9, // global scaling factor for all expressions
minScale: .5, // smallest scaling factor to use
matchFontHeight: false, // true to match ex-height of surrounding font
mtextInheritFont: true, // true to make mtext elements use surrounding font
merrorInheritFont: true, // true to make merror text use surrounding font
mathmlSpacing: false, // true for MathML spacing rules, false for TeX rules
skipAttributes: {}, // RFDa and other attributes NOT to copy to the output
exFactor: .5, // default size of ex in em units
displayAlign: 'center', // default for indentalign when set to 'auto'
displayIndent: '0', // default for indentshift when set to 'auto'
fontCache: 'none', // or 'global' or 'none'
localID: null, // ID to use for local font cache (for single equation processing)
internalSpeechTitles: true, // insert <title> tags with speech content
titleID: 0 // initial id number to use for aria-labeledby titles
},
tex: {
tags: 'ams',
packages: {
'[+]': ['ams']
},
inlineMath: [ // start/end delimiter pairs for in-line math
['$', '$'],
['\\(', '\\)']
],
displayMath: [ // start/end delimiter pairs for display math
['$$', '$$'],
['\\[', '\\]']
]
},
options: {
enableMenu: false,
// disable assistive-mml, since it messes up speaker notes
menuOptions: {
settings: {
assistiveMml: false
}
},
renderActions: {
assistiveMml: [] // disable assistive mathml
}
}
};
// add user-defined Latex macros
let macros = { fragment: [ "\\class{fragment}{#1}", 1 ] };
if (options.macros)
{
macros = Object.assign(macros, options.macros);
}
window.MathJax.tex.macros = macros;
// use promise mechanism to make sure that math typesetting
// is performend before Reveal fires ready-event or
// generates a PDF
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
window.MathJax.startup.defaultReady();
MathJax.startup.promise.then(() => {
console.log("mathjax typeset done");
Reveal.layout();
fixLinks();
setupMathIncremental();
injectStyle();
resolve();
});
});
});
return {
init: function () {
// 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");
}
}
})();
// configure through global MathJax object
window.MathJax = {
loader: {
load: ["[tex]/ams"],
typeset: false,
},
startup: {
ready: () => {
console.log("mathjax loaded");
//MathJax.startup.defaultReady();
},
},
svg: {
scale: 0.9, // global scaling factor for all expressions
minScale: 0.5, // smallest scaling factor to use
matchFontHeight: false, // true to match ex-height of surrounding font
mtextInheritFont: true, // true to make mtext elements use surrounding font
merrorInheritFont: true, // true to make merror text use surrounding font
mathmlSpacing: false, // true for MathML spacing rules, false for TeX rules
skipAttributes: {}, // RFDa and other attributes NOT to copy to the output
exFactor: 0.5, // default size of ex in em units
displayAlign: "center", // default for indentalign when set to 'auto'
displayIndent: "0", // default for indentshift when set to 'auto'
fontCache: "none", // or 'global' or 'none'
localID: null, // ID to use for local font cache (for single equation processing)
internalSpeechTitles: true, // insert <title> tags with speech content
titleID: 0, // initial id number to use for aria-labeledby titles
},
tex: {
tags: "ams",
packages: {
"[+]": ["ams"],
},
inlineMath: [
// start/end delimiter pairs for in-line math
["$", "$"],
["\\(", "\\)"],
],
displayMath: [
// start/end delimiter pairs for display math
["$$", "$$"],
["\\[", "\\]"],
],
},
options: {
enableMenu: false,
// disable assistive-mml, since it messes up speaker notes
menuOptions: {
settings: {
assistiveMml: false,
},
},
renderActions: {
assistiveMml: [], // disable assistive mathml
},
},
};
// add user-defined Latex macros
let macros = { fragment: ["\\class{fragment}{#1}", 1] };
if (options.macros) {
macros = Object.assign(macros, options.macros);
}
window.MathJax.tex.macros = macros;
// use promise mechanism to make sure that math typesetting
// is performend before Reveal fires ready-event or
// generates a PDF
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
window.MathJax.startup.defaultReady();
MathJax.startup.promise.then(() => {
console.log("mathjax typeset done");
Reveal.layout();
fixLinks();
setupMathIncremental();
injectStyle();
resolve();
});
});
});
},
};
})();
Reveal.registerPlugin( 'math', RevealMath );
Reveal.registerPlugin("math", RevealMath);
......@@ -35,7 +35,6 @@ $endif$
<link rel="stylesheet" href="$decker-support-dir$/vendor/reveal/css/reveal.css">
<link rel="stylesheet" href="$decker-support-dir$/plugins/whiteboard/whiteboard.css">
<link rel="stylesheet" href="$decker-support-dir$/plugins/menu/menu.css">
<link rel="stylesheet" href="$decker-support-dir$/geometry/geometry.css">
$if(thebelab.enable)$
<link rel="stylesheet" href="$decker-support-dir$/plugins/thebelab/thebelab.css">
$endif$
......
......@@ -98,7 +98,7 @@ transformImages images caption = do
H.div ! A.class_ "decker image-row" $ toHtml $ map toHtml imageRow
H.figcaption captionHtml
language cls = find (`elem` ["dot", "gnuplot", "tex"]) cls
language cls = find (`elem` ["plantuml", "dot", "gnuplot", "tex"]) cls
-- TODO this is incomplete
-- - captions are just swallowed but never rendered.
......@@ -107,6 +107,8 @@ transformCodeBlock :: Block -> [Inline] -> Filter Block
transformCodeBlock code@(CodeBlock attr@(_, classes, _) text) caption =
handle (blockError code) $
if
| all (`elem` classes) ["plantuml", "render"] ->
runAttr attr (transform "plantuml") >>= renderHtml
| all (`elem` classes) ["dot", "render"] ->
runAttr attr (transform "dot") >>= renderHtml
| all (`elem` classes) ["gnuplot", "render"] ->
......@@ -365,5 +367,5 @@ renderJavascriptHtml code = do
id <- liftIO randomId
let anchor = "let anchor = document.getElementById(\"" <> id <> "\");\n"
return $ do
H.div ! A.id (toValue id) ! A.class_ "geometry" $ ""
H.script ! A.class_ "geometry" ! A.type_ "geometry" $ toHtml (anchor <> code)
H.div ! A.id (toValue id) ! A.class_ "es6 module anchor" $ ""
H.script ! A.type_ "module" ! A.defer "" $ toHtml (anchor <> code)
......@@ -61,7 +61,7 @@ svgExt = ["svg"]
yamlExt = ["yaml", "yml"]
renderExt = ["dot", "gnuplot", "tex"]
renderExt = ["dot", "gnuplot", "tex", "plantuml"]