intial commit (forked from private repo)

This commit is contained in:
2025-04-11 11:08:28 +02:00
commit 3bdd37f46c
154 changed files with 45901 additions and 0 deletions

View File

@ -0,0 +1,110 @@
.reveal .slide-logo {
display: block;
position: fixed;
bottom: 0;
right: 12px;
max-height: 2.2rem;
height: 100%;
width: auto;
z-index: 2;
}
.reveal .footer {
display: block;
position: fixed;
bottom: 18px;
width: 100%;
margin: 0 auto;
text-align: center;
font-size: 18px;
z-index: 2;
}
.reveal .footer > * {
margin-top: 0;
margin-bottom: 0;
}
.reveal .slide .footer {
display: none;
}
.reveal .slide-number {
bottom: 10px;
right: 10px;
font-size: 16px;
background-color: transparent;
}
.reveal.has-logo .slide-number {
bottom: initial;
top: 8px;
right: 8px;
}
.reveal .slide-number .slide-number-delimiter {
margin: 0;
}
.reveal .slide-menu-button {
left: 8px;
bottom: 8px;
}
.reveal .slide-chalkboard-buttons {
position: fixed;
left: 12px;
bottom: 8px;
z-index: 30;
font-size: 24px;
}
.reveal .slide-chalkboard-buttons.slide-menu-offset {
left: 54px;
}
.reveal .slide-chalkboard-buttons > span {
margin-right: 14px;
cursor: pointer;
}
@media screen and (max-width: 800px) {
.reveal .slide-logo {
max-height: 1.1rem;
bottom: -2px;
right: 10px;
}
.reveal .footer {
font-size: 14px;
bottom: 12px;
}
.reveal .slide-number {
font-size: 12px;
bottom: 7px;
}
.reveal .slide-menu-button .fas::before {
height: 1.3rem;
width: 1.3rem;
vertical-align: -0.125em;
background-size: 1.3rem 1.3rem;
}
.reveal .slide-chalkboard-buttons .fas::before {
height: 0.95rem;
width: 0.95rem;
background-size: 0.95rem 0.95rem;
vertical-align: -0em;
}
.reveal .slide-chalkboard-buttons.slide-menu-offset {
left: 36px;
}
.reveal .slide-chalkboard-buttons > span {
margin-right: 9px;
}
}
html.print-pdf .reveal .slide-menu-button,
html.print-pdf .reveal .slide-chalkboard-buttons {
display: none;
}

View File

@ -0,0 +1,5 @@
name: QuartoSupport
script: support.js
stylesheet: footer.css
config:
smaller: false

View File

@ -0,0 +1,405 @@
// catch all plugin for various quarto features
window.QuartoSupport = function () {
function isPrintView() {
return /print-pdf/gi.test(window.location.search) || /view=print/gi.test(window.location.search);
}
// helper for theme toggling
function toggleBackgroundTheme(el, onDarkBackground, onLightBackground) {
if (onDarkBackground) {
el.classList.add('has-dark-background')
} else {
el.classList.remove('has-dark-background')
}
if (onLightBackground) {
el.classList.add('has-light-background')
} else {
el.classList.remove('has-light-background')
}
}
// implement controlsAudo
function controlsAuto(deck) {
const config = deck.getConfig();
if (config.controlsAuto === true) {
const iframe = window.location !== window.parent.location;
const localhost =
window.location.hostname === "localhost" ||
window.location.hostname === "127.0.0.1";
deck.configure({
controls:
(iframe && !localhost) ||
(deck.hasVerticalSlides() && config.navigationMode !== "linear"),
});
}
}
// helper to provide event handlers for all links in a container
function handleLinkClickEvents(deck, container) {
Array.from(container.querySelectorAll("a")).forEach((el) => {
const url = el.getAttribute("href");
if (/^(http|www)/gi.test(url)) {
el.addEventListener(
"click",
(ev) => {
const fullscreen = !!window.document.fullscreen;
const dataPreviewLink = el.getAttribute("data-preview-link");
// if there is a local specifcation then use that
if (dataPreviewLink) {
if (
dataPreviewLink === "true" ||
(dataPreviewLink === "auto" && fullscreen)
) {
ev.preventDefault();
deck.showPreview(url);
return false;
}
} else {
const previewLinks = !!deck.getConfig().previewLinks;
const previewLinksAuto =
deck.getConfig().previewLinksAuto === true;
if (previewLinks == true || (previewLinksAuto && fullscreen)) {
ev.preventDefault();
deck.showPreview(url);
return false;
}
}
// if the deck is in an iframe we want to open it externally
// (don't do this when in vscode though as it has its own
// handler for opening links externally that will be play)
const iframe = window.location !== window.parent.location;
if (
iframe &&
!window.location.search.includes("quartoPreviewReqId=")
) {
ev.preventDefault();
ev.stopImmediatePropagation();
window.open(url, "_blank");
return false;
}
// if the user has set data-preview-link to "auto" we need to handle the event
// (because reveal will interpret "auto" as true)
if (dataPreviewLink === "auto") {
ev.preventDefault();
ev.stopImmediatePropagation();
const target =
el.getAttribute("target") ||
(ev.ctrlKey || ev.metaKey ? "_blank" : "");
if (target) {
window.open(url, target);
} else {
window.location.href = url;
}
return false;
}
},
false
);
}
});
}
// implement previewLinksAuto
function previewLinksAuto(deck) {
handleLinkClickEvents(deck, deck.getRevealElement());
}
// apply styles
function applyGlobalStyles(deck) {
if (deck.getConfig()["smaller"] === true) {
const revealParent = deck.getRevealElement();
revealParent.classList.add("smaller");
}
}
// add logo image
function addLogoImage(deck) {
const revealParent = deck.getRevealElement();
const logoImg = document.querySelector(".slide-logo");
if (logoImg) {
revealParent.appendChild(logoImg);
revealParent.classList.add("has-logo");
}
}
// tweak slide-number element
function tweakSlideNumber(deck) {
deck.on("slidechanged", function (ev) {
// No slide number in scroll view
if (deck.isScrollView()) { return }
const revealParent = deck.getRevealElement();
const slideNumberEl = revealParent.querySelector(".slide-number");
const slideBackground = Reveal.getSlideBackground(ev.currentSlide);
const onDarkBackground = slideBackground.classList.contains('has-dark-background')
const onLightBackground = slideBackground.classList.contains('has-light-background')
toggleBackgroundTheme(slideNumberEl, onDarkBackground, onLightBackground);
})
}
// add footer text
function addFooter(deck) {
const revealParent = deck.getRevealElement();
const defaultFooterDiv = document.querySelector(".footer-default");
// Set per slide footer if any defined,
// or show default unless data-footer="false" for no footer on this slide
const setSlideFooter = (ev, defaultFooterDiv) => {
const currentSlideFooter = ev.currentSlide.querySelector(".footer");
const onDarkBackground = deck.getSlideBackground(ev.currentSlide).classList.contains('has-dark-background')
const onLightBackground = deck.getSlideBackground(ev.currentSlide).classList.contains('has-light-background')
if (currentSlideFooter) {
defaultFooterDiv.style.display = "none";
const slideFooter = currentSlideFooter.cloneNode(true);
handleLinkClickEvents(deck, slideFooter);
deck.getRevealElement().appendChild(slideFooter);
toggleBackgroundTheme(slideFooter, onDarkBackground, onLightBackground)
} else if (ev.currentSlide.getAttribute("data-footer") === "false") {
defaultFooterDiv.style.display = "none";
} else {
defaultFooterDiv.style.display = "block";
toggleBackgroundTheme(defaultFooterDiv, onDarkBackground, onLightBackground)
}
}
if (defaultFooterDiv) {
// move default footnote to the div.reveal element
revealParent.appendChild(defaultFooterDiv);
handleLinkClickEvents(deck, defaultFooterDiv);
if (!isPrintView()) {
// Ready even is needed so that footer customization applies on first loaded slide
deck.on('ready', (ev) => {
// Set footer (custom, default or none)
setSlideFooter(ev, defaultFooterDiv)
});
// Any new navigated new slide will get the custom footnote check
deck.on("slidechanged", function (ev) {
// Remove presentation footer defined by previous slide
const prevSlideFooter = document.querySelector(
".reveal > .footer:not(.footer-default)"
);
if (prevSlideFooter) {
prevSlideFooter.remove();
}
// Set new one (custom, default or none)
setSlideFooter(ev, defaultFooterDiv)
});
}
}
}
// add chalkboard buttons
function addChalkboardButtons(deck) {
const chalkboard = deck.getPlugin("RevealChalkboard");
if (chalkboard && !isPrintView()) {
const revealParent = deck.getRevealElement();
const chalkboardDiv = document.createElement("div");
chalkboardDiv.classList.add("slide-chalkboard-buttons");
if (document.querySelector(".slide-menu-button")) {
chalkboardDiv.classList.add("slide-menu-offset");
}
// add buttons
const buttons = [
{
icon: "easel2",
title: "Toggle Chalkboard (b)",
onclick: chalkboard.toggleChalkboard,
},
{
icon: "brush",
title: "Toggle Notes Canvas (c)",
onclick: chalkboard.toggleNotesCanvas,
},
];
buttons.forEach(function (button) {
const span = document.createElement("span");
span.title = button.title;
const icon = document.createElement("i");
icon.classList.add("fas");
icon.classList.add("fa-" + button.icon);
span.appendChild(icon);
span.onclick = function (event) {
event.preventDefault();
button.onclick();
};
chalkboardDiv.appendChild(span);
});
revealParent.appendChild(chalkboardDiv);
const config = deck.getConfig();
if (!config.chalkboard.buttons) {
chalkboardDiv.classList.add("hidden");
}
// show and hide chalkboard buttons on slidechange
deck.on("slidechanged", function (ev) {
const config = deck.getConfig();
let buttons = !!config.chalkboard.buttons;
const slideButtons = ev.currentSlide.getAttribute(
"data-chalkboard-buttons"
);
if (slideButtons) {
if (slideButtons === "true" || slideButtons === "1") {
buttons = true;
} else if (slideButtons === "false" || slideButtons === "0") {
buttons = false;
}
}
if (buttons) {
chalkboardDiv.classList.remove("hidden");
} else {
chalkboardDiv.classList.add("hidden");
}
});
}
}
function handleTabbyClicks() {
const tabs = document.querySelectorAll(".panel-tabset-tabby > li > a");
for (let i = 0; i < tabs.length; i++) {
const tab = tabs[i];
tab.onclick = function (ev) {
ev.preventDefault();
ev.stopPropagation();
return false;
};
}
}
function fixupForPrint(deck) {
if (isPrintView()) {
const slides = deck.getSlides();
slides.forEach(function (slide) {
slide.removeAttribute("data-auto-animate");
});
window.document.querySelectorAll(".hljs").forEach(function (el) {
el.classList.remove("hljs");
});
window.document.querySelectorAll(".hljs-ln-code").forEach(function (el) {
el.classList.remove("hljs-ln-code");
});
}
}
function handleSlideChanges(deck) {
// dispatch for htmlwidgets
const fireSlideEnter = () => {
const event = window.document.createEvent("Event");
event.initEvent("slideenter", true, true);
window.document.dispatchEvent(event);
};
const fireSlideChanged = (previousSlide, currentSlide) => {
fireSlideEnter();
// dispatch for shiny
if (window.jQuery) {
if (previousSlide) {
window.jQuery(previousSlide).trigger("hidden");
}
if (currentSlide) {
window.jQuery(currentSlide).trigger("shown");
}
}
};
// fire slideEnter for tabby tab activations (for htmlwidget resize behavior)
document.addEventListener("tabby", fireSlideEnter, false);
deck.on("slidechanged", function (event) {
fireSlideChanged(event.previousSlide, event.currentSlide);
});
}
function workaroundMermaidDistance(deck) {
if (window.document.querySelector("pre.mermaid-js")) {
const slideCount = deck.getTotalSlides();
deck.configure({
mobileViewDistance: slideCount,
viewDistance: slideCount,
});
}
}
function handleWhiteSpaceInColumns(deck) {
for (const outerDiv of window.document.querySelectorAll("div.columns")) {
// remove all whitespace text nodes
// whitespace nodes cause the columns to be misaligned
// since they have inline-block layout
//
// Quarto emits no whitespace nodes, but third-party tooling
// has bugs that can cause whitespace nodes to be emitted.
// See https://github.com/quarto-dev/quarto-cli/issues/8382
for (const node of outerDiv.childNodes) {
if (node.nodeType === 3 && node.nodeValue.trim() === "") {
outerDiv.removeChild(node);
}
}
}
}
function cleanEmptyAutoGeneratedContent(deck) {
const div = document.querySelector('div.quarto-auto-generated-content')
if (div && div.textContent.trim() === '') {
div.remove()
}
}
// FIXME: Possibly remove this wrapper class when upstream trigger is fixed
// https://github.com/hakimel/reveal.js/issues/3688
// Currently, scrollActivationWidth needs to be unset for toggle to work
class ScrollViewToggler {
constructor(deck) {
this.deck = deck;
this.oldScrollActivationWidth = deck.getConfig()['scrollActivationWidth'];
}
toggleScrollViewWrapper() {
if (this.deck.isScrollView() === true) {
this.deck.configure({ scrollActivationWidth: this.oldScrollActivationWidth });
this.deck.toggleScrollView(false);
} else if (this.deck.isScrollView() === false) {
this.deck.configure({ scrollActivationWidth: null });
this.deck.toggleScrollView(true);
}
}
}
let scrollViewToggler;
function installScollViewKeyBindings(deck) {
var config = deck.getConfig();
var shortcut = config.scrollViewShortcut || 'R';
Reveal.addKeyBinding({
keyCode: shortcut.toUpperCase().charCodeAt( 0 ),
key: shortcut.toUpperCase(),
description: 'Scroll View Mode'
}, () => { scrollViewToggler.toggleScrollViewWrapper() } );
}
return {
id: "quarto-support",
init: function (deck) {
scrollViewToggler = new ScrollViewToggler(deck);
controlsAuto(deck);
previewLinksAuto(deck);
fixupForPrint(deck);
applyGlobalStyles(deck);
addLogoImage(deck);
tweakSlideNumber(deck);
addFooter(deck);
addChalkboardButtons(deck);
handleTabbyClicks();
handleSlideChanges(deck);
workaroundMermaidDistance(deck);
handleWhiteSpaceInColumns(deck);
installScollViewKeyBindings(deck);
// should stay last
cleanEmptyAutoGeneratedContent(deck);
},
// Export for adding in menu
toggleScrollView: function() {
scrollViewToggler.toggleScrollViewWrapper();
}
};
};