mirror of
https://github.com/wilsonfreitas/awesome-quant.git
synced 2026-08-22 16:28:06 +00:00
deploy: 2fb8b30769
This commit is contained in:
+375
-392
@@ -2,7 +2,7 @@
|
|||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||||
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="generator" content="quarto-1.6.43">
|
<meta name="generator" content="quarto-1.7.29">
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||||
|
|
||||||
@@ -30,15 +30,16 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
||||||
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
||||||
<meta name="quarto:offset" content="./">
|
<meta name="quarto:offset" content="./">
|
||||||
<script src="site_libs/quarto-html/quarto.js"></script>
|
<script src="site_libs/quarto-html/quarto.js" type="module"></script>
|
||||||
|
<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
|
||||||
<script src="site_libs/quarto-html/popper.min.js"></script>
|
<script src="site_libs/quarto-html/popper.min.js"></script>
|
||||||
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||||
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
||||||
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||||
<link href="site_libs/quarto-html/quarto-syntax-highlighting-d4d76bf8491c20bad77d141916dc28e1.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
<link href="site_libs/quarto-html/quarto-syntax-highlighting-0815c480559380816a4d1ea211a47e91.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||||
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
||||||
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||||
<link href="site_libs/bootstrap/bootstrap-12858c9ce0885248945210bbd3c85d1a.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
<link href="site_libs/bootstrap/bootstrap-630147fbe0b9ab2b2a517857e522e257.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||||
<script id="quarto-search-options" type="application/json">{
|
<script id="quarto-search-options" type="application/json">{
|
||||||
"location": "navbar",
|
"location": "navbar",
|
||||||
"copy-button": false,
|
"copy-button": false,
|
||||||
@@ -72,7 +73,7 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="nav-fixed">
|
<body class="nav-fixed quarto-light">
|
||||||
|
|
||||||
<div id="quarto-search-results"></div>
|
<div id="quarto-search-results"></div>
|
||||||
<header id="quarto-header" class="headroom fixed-top">
|
<header id="quarto-header" class="headroom fixed-top">
|
||||||
@@ -228,236 +229,242 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
|
|
||||||
</main> <!-- /main -->
|
</main> <!-- /main -->
|
||||||
<script id="quarto-html-after-body" type="application/javascript">
|
<script id="quarto-html-after-body" type="application/javascript">
|
||||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||||
const toggleBodyColorMode = (bsSheetEl) => {
|
const icon = "";
|
||||||
const mode = bsSheetEl.getAttribute("data-mode");
|
const anchorJS = new window.AnchorJS();
|
||||||
const bodyEl = window.document.querySelector("body");
|
anchorJS.options = {
|
||||||
if (mode === "dark") {
|
placement: 'right',
|
||||||
bodyEl.classList.add("quarto-dark");
|
icon: icon
|
||||||
bodyEl.classList.remove("quarto-light");
|
|
||||||
} else {
|
|
||||||
bodyEl.classList.add("quarto-light");
|
|
||||||
bodyEl.classList.remove("quarto-dark");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const toggleBodyColorPrimary = () => {
|
|
||||||
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
|
||||||
if (bsSheetEl) {
|
|
||||||
toggleBodyColorMode(bsSheetEl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
toggleBodyColorPrimary();
|
|
||||||
const icon = "";
|
|
||||||
const anchorJS = new window.AnchorJS();
|
|
||||||
anchorJS.options = {
|
|
||||||
placement: 'right',
|
|
||||||
icon: icon
|
|
||||||
};
|
|
||||||
anchorJS.add('.anchored');
|
|
||||||
const isCodeAnnotation = (el) => {
|
|
||||||
for (const clz of el.classList) {
|
|
||||||
if (clz.startsWith('code-annotation-')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const onCopySuccess = function(e) {
|
|
||||||
// button target
|
|
||||||
const button = e.trigger;
|
|
||||||
// don't keep focus
|
|
||||||
button.blur();
|
|
||||||
// flash "checked"
|
|
||||||
button.classList.add('code-copy-button-checked');
|
|
||||||
var currentTitle = button.getAttribute("title");
|
|
||||||
button.setAttribute("title", "Copied!");
|
|
||||||
let tooltip;
|
|
||||||
if (window.bootstrap) {
|
|
||||||
button.setAttribute("data-bs-toggle", "tooltip");
|
|
||||||
button.setAttribute("data-bs-placement", "left");
|
|
||||||
button.setAttribute("data-bs-title", "Copied!");
|
|
||||||
tooltip = new bootstrap.Tooltip(button,
|
|
||||||
{ trigger: "manual",
|
|
||||||
customClass: "code-copy-button-tooltip",
|
|
||||||
offset: [0, -8]});
|
|
||||||
tooltip.show();
|
|
||||||
}
|
|
||||||
setTimeout(function() {
|
|
||||||
if (tooltip) {
|
|
||||||
tooltip.hide();
|
|
||||||
button.removeAttribute("data-bs-title");
|
|
||||||
button.removeAttribute("data-bs-toggle");
|
|
||||||
button.removeAttribute("data-bs-placement");
|
|
||||||
}
|
|
||||||
button.setAttribute("title", currentTitle);
|
|
||||||
button.classList.remove('code-copy-button-checked');
|
|
||||||
}, 1000);
|
|
||||||
// clear code selection
|
|
||||||
e.clearSelection();
|
|
||||||
}
|
|
||||||
const getTextToCopy = function(trigger) {
|
|
||||||
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
|
||||||
for (const childEl of codeEl.children) {
|
|
||||||
if (isCodeAnnotation(childEl)) {
|
|
||||||
childEl.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return codeEl.innerText;
|
|
||||||
}
|
|
||||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
|
||||||
text: getTextToCopy
|
|
||||||
});
|
|
||||||
clipboard.on('success', onCopySuccess);
|
|
||||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
|
||||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
|
||||||
text: getTextToCopy,
|
|
||||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
|
||||||
});
|
|
||||||
clipboardModal.on('success', onCopySuccess);
|
|
||||||
}
|
|
||||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
|
||||||
var mailtoRegex = new RegExp(/^mailto:/);
|
|
||||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
|
||||||
var isInternal = (href) => {
|
|
||||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
|
||||||
}
|
|
||||||
// Inspect non-navigation links and adorn them if external
|
|
||||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
|
||||||
for (var i=0; i<links.length; i++) {
|
|
||||||
const link = links[i];
|
|
||||||
if (!isInternal(link.href)) {
|
|
||||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
|
||||||
// links that we want to consider external
|
|
||||||
if (link.dataset.originalHref !== undefined) {
|
|
||||||
link.href = link.dataset.originalHref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
|
||||||
const config = {
|
|
||||||
allowHTML: true,
|
|
||||||
maxWidth: 500,
|
|
||||||
delay: 100,
|
|
||||||
arrow: false,
|
|
||||||
appendTo: function(el) {
|
|
||||||
return el.parentElement;
|
|
||||||
},
|
|
||||||
interactive: true,
|
|
||||||
interactiveBorder: 10,
|
|
||||||
theme: 'quarto',
|
|
||||||
placement: 'bottom-start',
|
|
||||||
};
|
};
|
||||||
if (contentFn) {
|
anchorJS.add('.anchored');
|
||||||
config.content = contentFn;
|
const isCodeAnnotation = (el) => {
|
||||||
}
|
for (const clz of el.classList) {
|
||||||
if (onTriggerFn) {
|
if (clz.startsWith('code-annotation-')) {
|
||||||
config.onTrigger = onTriggerFn;
|
return true;
|
||||||
}
|
|
||||||
if (onUntriggerFn) {
|
|
||||||
config.onUntrigger = onUntriggerFn;
|
|
||||||
}
|
|
||||||
window.tippy(el, config);
|
|
||||||
}
|
|
||||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
|
||||||
for (var i=0; i<noterefs.length; i++) {
|
|
||||||
const ref = noterefs[i];
|
|
||||||
tippyHover(ref, function() {
|
|
||||||
// use id or data attribute instead here
|
|
||||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
|
||||||
try { href = new URL(href).hash; } catch {}
|
|
||||||
const id = href.replace(/^#\/?/, "");
|
|
||||||
const note = window.document.getElementById(id);
|
|
||||||
if (note) {
|
|
||||||
return note.innerHTML;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
|
||||||
const processXRef = (id, note) => {
|
|
||||||
// Strip column container classes
|
|
||||||
const stripColumnClz = (el) => {
|
|
||||||
el.classList.remove("page-full", "page-columns");
|
|
||||||
if (el.children) {
|
|
||||||
for (const child of el.children) {
|
|
||||||
stripColumnClz(child);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
stripColumnClz(note)
|
const onCopySuccess = function(e) {
|
||||||
if (id === null || id.startsWith('sec-')) {
|
// button target
|
||||||
// Special case sections, only their first couple elements
|
const button = e.trigger;
|
||||||
const container = document.createElement("div");
|
// don't keep focus
|
||||||
if (note.children && note.children.length > 2) {
|
button.blur();
|
||||||
container.appendChild(note.children[0].cloneNode(true));
|
// flash "checked"
|
||||||
for (let i = 1; i < note.children.length; i++) {
|
button.classList.add('code-copy-button-checked');
|
||||||
const child = note.children[i];
|
var currentTitle = button.getAttribute("title");
|
||||||
if (child.tagName === "P" && child.innerText === "") {
|
button.setAttribute("title", "Copied!");
|
||||||
continue;
|
let tooltip;
|
||||||
} else {
|
if (window.bootstrap) {
|
||||||
container.appendChild(child.cloneNode(true));
|
button.setAttribute("data-bs-toggle", "tooltip");
|
||||||
break;
|
button.setAttribute("data-bs-placement", "left");
|
||||||
|
button.setAttribute("data-bs-title", "Copied!");
|
||||||
|
tooltip = new bootstrap.Tooltip(button,
|
||||||
|
{ trigger: "manual",
|
||||||
|
customClass: "code-copy-button-tooltip",
|
||||||
|
offset: [0, -8]});
|
||||||
|
tooltip.show();
|
||||||
|
}
|
||||||
|
setTimeout(function() {
|
||||||
|
if (tooltip) {
|
||||||
|
tooltip.hide();
|
||||||
|
button.removeAttribute("data-bs-title");
|
||||||
|
button.removeAttribute("data-bs-toggle");
|
||||||
|
button.removeAttribute("data-bs-placement");
|
||||||
|
}
|
||||||
|
button.setAttribute("title", currentTitle);
|
||||||
|
button.classList.remove('code-copy-button-checked');
|
||||||
|
}, 1000);
|
||||||
|
// clear code selection
|
||||||
|
e.clearSelection();
|
||||||
|
}
|
||||||
|
const getTextToCopy = function(trigger) {
|
||||||
|
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
||||||
|
for (const childEl of codeEl.children) {
|
||||||
|
if (isCodeAnnotation(childEl)) {
|
||||||
|
childEl.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (window.Quarto?.typesetMath) {
|
return codeEl.innerText;
|
||||||
window.Quarto.typesetMath(container);
|
}
|
||||||
|
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||||
|
text: getTextToCopy
|
||||||
|
});
|
||||||
|
clipboard.on('success', onCopySuccess);
|
||||||
|
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||||
|
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||||
|
text: getTextToCopy,
|
||||||
|
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||||
|
});
|
||||||
|
clipboardModal.on('success', onCopySuccess);
|
||||||
|
}
|
||||||
|
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||||
|
var mailtoRegex = new RegExp(/^mailto:/);
|
||||||
|
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||||
|
var isInternal = (href) => {
|
||||||
|
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||||
|
}
|
||||||
|
// Inspect non-navigation links and adorn them if external
|
||||||
|
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||||
|
for (var i=0; i<links.length; i++) {
|
||||||
|
const link = links[i];
|
||||||
|
if (!isInternal(link.href)) {
|
||||||
|
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||||
|
// links that we want to consider external
|
||||||
|
if (link.dataset.originalHref !== undefined) {
|
||||||
|
link.href = link.dataset.originalHref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||||
|
const config = {
|
||||||
|
allowHTML: true,
|
||||||
|
maxWidth: 500,
|
||||||
|
delay: 100,
|
||||||
|
arrow: false,
|
||||||
|
appendTo: function(el) {
|
||||||
|
return el.parentElement;
|
||||||
|
},
|
||||||
|
interactive: true,
|
||||||
|
interactiveBorder: 10,
|
||||||
|
theme: 'quarto',
|
||||||
|
placement: 'bottom-start',
|
||||||
|
};
|
||||||
|
if (contentFn) {
|
||||||
|
config.content = contentFn;
|
||||||
|
}
|
||||||
|
if (onTriggerFn) {
|
||||||
|
config.onTrigger = onTriggerFn;
|
||||||
|
}
|
||||||
|
if (onUntriggerFn) {
|
||||||
|
config.onUntrigger = onUntriggerFn;
|
||||||
|
}
|
||||||
|
window.tippy(el, config);
|
||||||
|
}
|
||||||
|
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||||
|
for (var i=0; i<noterefs.length; i++) {
|
||||||
|
const ref = noterefs[i];
|
||||||
|
tippyHover(ref, function() {
|
||||||
|
// use id or data attribute instead here
|
||||||
|
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||||
|
try { href = new URL(href).hash; } catch {}
|
||||||
|
const id = href.replace(/^#\/?/, "");
|
||||||
|
const note = window.document.getElementById(id);
|
||||||
|
if (note) {
|
||||||
|
return note.innerHTML;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||||
|
const processXRef = (id, note) => {
|
||||||
|
// Strip column container classes
|
||||||
|
const stripColumnClz = (el) => {
|
||||||
|
el.classList.remove("page-full", "page-columns");
|
||||||
|
if (el.children) {
|
||||||
|
for (const child of el.children) {
|
||||||
|
stripColumnClz(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stripColumnClz(note)
|
||||||
|
if (id === null || id.startsWith('sec-')) {
|
||||||
|
// Special case sections, only their first couple elements
|
||||||
|
const container = document.createElement("div");
|
||||||
|
if (note.children && note.children.length > 2) {
|
||||||
|
container.appendChild(note.children[0].cloneNode(true));
|
||||||
|
for (let i = 1; i < note.children.length; i++) {
|
||||||
|
const child = note.children[i];
|
||||||
|
if (child.tagName === "P" && child.innerText === "") {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
container.appendChild(child.cloneNode(true));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (window.Quarto?.typesetMath) {
|
||||||
|
window.Quarto.typesetMath(container);
|
||||||
|
}
|
||||||
|
return container.innerHTML
|
||||||
|
} else {
|
||||||
|
if (window.Quarto?.typesetMath) {
|
||||||
|
window.Quarto.typesetMath(note);
|
||||||
|
}
|
||||||
|
return note.innerHTML;
|
||||||
}
|
}
|
||||||
return container.innerHTML
|
|
||||||
} else {
|
} else {
|
||||||
|
// Remove any anchor links if they are present
|
||||||
|
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||||
|
if (anchorLink) {
|
||||||
|
anchorLink.remove();
|
||||||
|
}
|
||||||
if (window.Quarto?.typesetMath) {
|
if (window.Quarto?.typesetMath) {
|
||||||
window.Quarto.typesetMath(note);
|
window.Quarto.typesetMath(note);
|
||||||
}
|
}
|
||||||
return note.innerHTML;
|
if (note.classList.contains("callout")) {
|
||||||
}
|
return note.outerHTML;
|
||||||
} else {
|
} else {
|
||||||
// Remove any anchor links if they are present
|
return note.innerHTML;
|
||||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
}
|
||||||
if (anchorLink) {
|
|
||||||
anchorLink.remove();
|
|
||||||
}
|
|
||||||
if (window.Quarto?.typesetMath) {
|
|
||||||
window.Quarto.typesetMath(note);
|
|
||||||
}
|
|
||||||
if (note.classList.contains("callout")) {
|
|
||||||
return note.outerHTML;
|
|
||||||
} else {
|
|
||||||
return note.innerHTML;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (var i=0; i<xrefs.length; i++) {
|
||||||
for (var i=0; i<xrefs.length; i++) {
|
const xref = xrefs[i];
|
||||||
const xref = xrefs[i];
|
tippyHover(xref, undefined, function(instance) {
|
||||||
tippyHover(xref, undefined, function(instance) {
|
instance.disable();
|
||||||
instance.disable();
|
let url = xref.getAttribute('href');
|
||||||
let url = xref.getAttribute('href');
|
let hash = undefined;
|
||||||
let hash = undefined;
|
if (url.startsWith('#')) {
|
||||||
if (url.startsWith('#')) {
|
hash = url;
|
||||||
hash = url;
|
} else {
|
||||||
} else {
|
try { hash = new URL(url).hash; } catch {}
|
||||||
try { hash = new URL(url).hash; } catch {}
|
}
|
||||||
}
|
if (hash) {
|
||||||
if (hash) {
|
const id = hash.replace(/^#\/?/, "");
|
||||||
const id = hash.replace(/^#\/?/, "");
|
const note = window.document.getElementById(id);
|
||||||
const note = window.document.getElementById(id);
|
if (note !== null) {
|
||||||
if (note !== null) {
|
try {
|
||||||
try {
|
const html = processXRef(id, note.cloneNode(true));
|
||||||
const html = processXRef(id, note.cloneNode(true));
|
instance.setContent(html);
|
||||||
instance.setContent(html);
|
} finally {
|
||||||
} finally {
|
instance.enable();
|
||||||
instance.enable();
|
instance.show();
|
||||||
instance.show();
|
}
|
||||||
|
} else {
|
||||||
|
// See if we can fetch this
|
||||||
|
fetch(url.split('#')[0])
|
||||||
|
.then(res => res.text())
|
||||||
|
.then(html => {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||||
|
const note = htmlDoc.getElementById(id);
|
||||||
|
if (note !== null) {
|
||||||
|
const html = processXRef(id, note);
|
||||||
|
instance.setContent(html);
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
instance.enable();
|
||||||
|
instance.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// See if we can fetch this
|
// See if we can fetch a full url (with no hash to target)
|
||||||
fetch(url.split('#')[0])
|
// This is a special case and we should probably do some content thinning / targeting
|
||||||
|
fetch(url)
|
||||||
.then(res => res.text())
|
.then(res => res.text())
|
||||||
.then(html => {
|
.then(html => {
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||||
const note = htmlDoc.getElementById(id);
|
const note = htmlDoc.querySelector('main.content');
|
||||||
if (note !== null) {
|
if (note !== null) {
|
||||||
const html = processXRef(id, note);
|
// This should only happen for chapter cross references
|
||||||
|
// (since there is no id in the URL)
|
||||||
|
// remove the first header
|
||||||
|
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||||
|
note.children[0].remove();
|
||||||
|
}
|
||||||
|
const html = processXRef(null, note);
|
||||||
instance.setContent(html);
|
instance.setContent(html);
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -465,185 +472,161 @@ window.document.addEventListener("DOMContentLoaded", function (event) {
|
|||||||
instance.show();
|
instance.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
}, function(instance) {
|
||||||
// See if we can fetch a full url (with no hash to target)
|
|
||||||
// This is a special case and we should probably do some content thinning / targeting
|
|
||||||
fetch(url)
|
|
||||||
.then(res => res.text())
|
|
||||||
.then(html => {
|
|
||||||
const parser = new DOMParser();
|
|
||||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
|
||||||
const note = htmlDoc.querySelector('main.content');
|
|
||||||
if (note !== null) {
|
|
||||||
// This should only happen for chapter cross references
|
|
||||||
// (since there is no id in the URL)
|
|
||||||
// remove the first header
|
|
||||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
|
||||||
note.children[0].remove();
|
|
||||||
}
|
|
||||||
const html = processXRef(null, note);
|
|
||||||
instance.setContent(html);
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
instance.enable();
|
|
||||||
instance.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, function(instance) {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let selectedAnnoteEl;
|
|
||||||
const selectorForAnnotation = ( cell, annotation) => {
|
|
||||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
|
||||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
|
||||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
|
||||||
return selector;
|
|
||||||
}
|
|
||||||
const selectCodeLines = (annoteEl) => {
|
|
||||||
const doc = window.document;
|
|
||||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
|
||||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
|
||||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
|
||||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
|
||||||
const lineIds = lines.map((line) => {
|
|
||||||
return targetCell + "-" + line;
|
|
||||||
})
|
|
||||||
let top = null;
|
|
||||||
let height = null;
|
|
||||||
let parent = null;
|
|
||||||
if (lineIds.length > 0) {
|
|
||||||
//compute the position of the single el (top and bottom and make a div)
|
|
||||||
const el = window.document.getElementById(lineIds[0]);
|
|
||||||
top = el.offsetTop;
|
|
||||||
height = el.offsetHeight;
|
|
||||||
parent = el.parentElement.parentElement;
|
|
||||||
if (lineIds.length > 1) {
|
|
||||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
|
||||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
|
||||||
height = bottom - top;
|
|
||||||
}
|
|
||||||
if (top !== null && height !== null && parent !== null) {
|
|
||||||
// cook up a div (if necessary) and position it
|
|
||||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
|
||||||
if (div === null) {
|
|
||||||
div = window.document.createElement("div");
|
|
||||||
div.setAttribute("id", "code-annotation-line-highlight");
|
|
||||||
div.style.position = 'absolute';
|
|
||||||
parent.appendChild(div);
|
|
||||||
}
|
|
||||||
div.style.top = top - 2 + "px";
|
|
||||||
div.style.height = height + 4 + "px";
|
|
||||||
div.style.left = 0;
|
|
||||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
|
||||||
if (gutterDiv === null) {
|
|
||||||
gutterDiv = window.document.createElement("div");
|
|
||||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
|
||||||
gutterDiv.style.position = 'absolute';
|
|
||||||
const codeCell = window.document.getElementById(targetCell);
|
|
||||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
|
||||||
gutter.appendChild(gutterDiv);
|
|
||||||
}
|
|
||||||
gutterDiv.style.top = top - 2 + "px";
|
|
||||||
gutterDiv.style.height = height + 4 + "px";
|
|
||||||
}
|
|
||||||
selectedAnnoteEl = annoteEl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const unselectCodeLines = () => {
|
|
||||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
|
||||||
elementsIds.forEach((elId) => {
|
|
||||||
const div = window.document.getElementById(elId);
|
|
||||||
if (div) {
|
|
||||||
div.remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
selectedAnnoteEl = undefined;
|
|
||||||
};
|
|
||||||
// Handle positioning of the toggle
|
|
||||||
window.addEventListener(
|
|
||||||
"resize",
|
|
||||||
throttle(() => {
|
|
||||||
elRect = undefined;
|
|
||||||
if (selectedAnnoteEl) {
|
|
||||||
selectCodeLines(selectedAnnoteEl);
|
|
||||||
}
|
|
||||||
}, 10)
|
|
||||||
);
|
|
||||||
function throttle(fn, ms) {
|
|
||||||
let throttle = false;
|
|
||||||
let timer;
|
|
||||||
return (...args) => {
|
|
||||||
if(!throttle) { // first call gets through
|
|
||||||
fn.apply(this, args);
|
|
||||||
throttle = true;
|
|
||||||
} else { // all the others get throttled
|
|
||||||
if(timer) clearTimeout(timer); // cancel #2
|
|
||||||
timer = setTimeout(() => {
|
|
||||||
fn.apply(this, args);
|
|
||||||
timer = throttle = false;
|
|
||||||
}, ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// Attach click handler to the DT
|
|
||||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
|
||||||
for (const annoteDlNode of annoteDls) {
|
|
||||||
annoteDlNode.addEventListener('click', (event) => {
|
|
||||||
const clickedEl = event.target;
|
|
||||||
if (clickedEl !== selectedAnnoteEl) {
|
|
||||||
unselectCodeLines();
|
|
||||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
|
||||||
if (activeEl) {
|
|
||||||
activeEl.classList.remove('code-annotation-active');
|
|
||||||
}
|
|
||||||
selectCodeLines(clickedEl);
|
|
||||||
clickedEl.classList.add('code-annotation-active');
|
|
||||||
} else {
|
|
||||||
// Unselect the line
|
|
||||||
unselectCodeLines();
|
|
||||||
clickedEl.classList.remove('code-annotation-active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const findCites = (el) => {
|
|
||||||
const parentEl = el.parentElement;
|
|
||||||
if (parentEl) {
|
|
||||||
const cites = parentEl.dataset.cites;
|
|
||||||
if (cites) {
|
|
||||||
return {
|
|
||||||
el,
|
|
||||||
cites: cites.split(' ')
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return findCites(el.parentElement)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
|
||||||
for (var i=0; i<bibliorefs.length; i++) {
|
|
||||||
const ref = bibliorefs[i];
|
|
||||||
const citeInfo = findCites(ref);
|
|
||||||
if (citeInfo) {
|
|
||||||
tippyHover(citeInfo.el, function() {
|
|
||||||
var popup = window.document.createElement('div');
|
|
||||||
citeInfo.cites.forEach(function(cite) {
|
|
||||||
var citeDiv = window.document.createElement('div');
|
|
||||||
citeDiv.classList.add('hanging-indent');
|
|
||||||
citeDiv.classList.add('csl-entry');
|
|
||||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
|
||||||
if (biblioDiv) {
|
|
||||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
|
||||||
}
|
|
||||||
popup.appendChild(citeDiv);
|
|
||||||
});
|
|
||||||
return popup.innerHTML;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
let selectedAnnoteEl;
|
||||||
});
|
const selectorForAnnotation = ( cell, annotation) => {
|
||||||
</script>
|
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||||
|
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||||
|
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
const selectCodeLines = (annoteEl) => {
|
||||||
|
const doc = window.document;
|
||||||
|
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||||
|
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||||
|
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||||
|
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||||
|
const lineIds = lines.map((line) => {
|
||||||
|
return targetCell + "-" + line;
|
||||||
|
})
|
||||||
|
let top = null;
|
||||||
|
let height = null;
|
||||||
|
let parent = null;
|
||||||
|
if (lineIds.length > 0) {
|
||||||
|
//compute the position of the single el (top and bottom and make a div)
|
||||||
|
const el = window.document.getElementById(lineIds[0]);
|
||||||
|
top = el.offsetTop;
|
||||||
|
height = el.offsetHeight;
|
||||||
|
parent = el.parentElement.parentElement;
|
||||||
|
if (lineIds.length > 1) {
|
||||||
|
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||||
|
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||||
|
height = bottom - top;
|
||||||
|
}
|
||||||
|
if (top !== null && height !== null && parent !== null) {
|
||||||
|
// cook up a div (if necessary) and position it
|
||||||
|
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||||
|
if (div === null) {
|
||||||
|
div = window.document.createElement("div");
|
||||||
|
div.setAttribute("id", "code-annotation-line-highlight");
|
||||||
|
div.style.position = 'absolute';
|
||||||
|
parent.appendChild(div);
|
||||||
|
}
|
||||||
|
div.style.top = top - 2 + "px";
|
||||||
|
div.style.height = height + 4 + "px";
|
||||||
|
div.style.left = 0;
|
||||||
|
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||||
|
if (gutterDiv === null) {
|
||||||
|
gutterDiv = window.document.createElement("div");
|
||||||
|
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||||
|
gutterDiv.style.position = 'absolute';
|
||||||
|
const codeCell = window.document.getElementById(targetCell);
|
||||||
|
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||||
|
gutter.appendChild(gutterDiv);
|
||||||
|
}
|
||||||
|
gutterDiv.style.top = top - 2 + "px";
|
||||||
|
gutterDiv.style.height = height + 4 + "px";
|
||||||
|
}
|
||||||
|
selectedAnnoteEl = annoteEl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const unselectCodeLines = () => {
|
||||||
|
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||||
|
elementsIds.forEach((elId) => {
|
||||||
|
const div = window.document.getElementById(elId);
|
||||||
|
if (div) {
|
||||||
|
div.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
selectedAnnoteEl = undefined;
|
||||||
|
};
|
||||||
|
// Handle positioning of the toggle
|
||||||
|
window.addEventListener(
|
||||||
|
"resize",
|
||||||
|
throttle(() => {
|
||||||
|
elRect = undefined;
|
||||||
|
if (selectedAnnoteEl) {
|
||||||
|
selectCodeLines(selectedAnnoteEl);
|
||||||
|
}
|
||||||
|
}, 10)
|
||||||
|
);
|
||||||
|
function throttle(fn, ms) {
|
||||||
|
let throttle = false;
|
||||||
|
let timer;
|
||||||
|
return (...args) => {
|
||||||
|
if(!throttle) { // first call gets through
|
||||||
|
fn.apply(this, args);
|
||||||
|
throttle = true;
|
||||||
|
} else { // all the others get throttled
|
||||||
|
if(timer) clearTimeout(timer); // cancel #2
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fn.apply(this, args);
|
||||||
|
timer = throttle = false;
|
||||||
|
}, ms);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Attach click handler to the DT
|
||||||
|
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||||
|
for (const annoteDlNode of annoteDls) {
|
||||||
|
annoteDlNode.addEventListener('click', (event) => {
|
||||||
|
const clickedEl = event.target;
|
||||||
|
if (clickedEl !== selectedAnnoteEl) {
|
||||||
|
unselectCodeLines();
|
||||||
|
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||||
|
if (activeEl) {
|
||||||
|
activeEl.classList.remove('code-annotation-active');
|
||||||
|
}
|
||||||
|
selectCodeLines(clickedEl);
|
||||||
|
clickedEl.classList.add('code-annotation-active');
|
||||||
|
} else {
|
||||||
|
// Unselect the line
|
||||||
|
unselectCodeLines();
|
||||||
|
clickedEl.classList.remove('code-annotation-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const findCites = (el) => {
|
||||||
|
const parentEl = el.parentElement;
|
||||||
|
if (parentEl) {
|
||||||
|
const cites = parentEl.dataset.cites;
|
||||||
|
if (cites) {
|
||||||
|
return {
|
||||||
|
el,
|
||||||
|
cites: cites.split(' ')
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return findCites(el.parentElement)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||||
|
for (var i=0; i<bibliorefs.length; i++) {
|
||||||
|
const ref = bibliorefs[i];
|
||||||
|
const citeInfo = findCites(ref);
|
||||||
|
if (citeInfo) {
|
||||||
|
tippyHover(citeInfo.el, function() {
|
||||||
|
var popup = window.document.createElement('div');
|
||||||
|
citeInfo.cites.forEach(function(cite) {
|
||||||
|
var citeDiv = window.document.createElement('div');
|
||||||
|
citeDiv.classList.add('hanging-indent');
|
||||||
|
citeDiv.classList.add('csl-entry');
|
||||||
|
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||||
|
if (biblioDiv) {
|
||||||
|
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||||
|
}
|
||||||
|
popup.appendChild(citeDiv);
|
||||||
|
});
|
||||||
|
return popup.innerHTML;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</div> <!-- /content -->
|
</div> <!-- /content -->
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+375
-392
@@ -2,7 +2,7 @@
|
|||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||||
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="generator" content="quarto-1.6.43">
|
<meta name="generator" content="quarto-1.7.29">
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||||
|
|
||||||
@@ -30,15 +30,16 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
||||||
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
||||||
<meta name="quarto:offset" content="./">
|
<meta name="quarto:offset" content="./">
|
||||||
<script src="site_libs/quarto-html/quarto.js"></script>
|
<script src="site_libs/quarto-html/quarto.js" type="module"></script>
|
||||||
|
<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
|
||||||
<script src="site_libs/quarto-html/popper.min.js"></script>
|
<script src="site_libs/quarto-html/popper.min.js"></script>
|
||||||
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||||
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
||||||
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||||
<link href="site_libs/quarto-html/quarto-syntax-highlighting-d4d76bf8491c20bad77d141916dc28e1.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
<link href="site_libs/quarto-html/quarto-syntax-highlighting-0815c480559380816a4d1ea211a47e91.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||||
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
||||||
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||||
<link href="site_libs/bootstrap/bootstrap-12858c9ce0885248945210bbd3c85d1a.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
<link href="site_libs/bootstrap/bootstrap-630147fbe0b9ab2b2a517857e522e257.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||||
<script id="quarto-search-options" type="application/json">{
|
<script id="quarto-search-options" type="application/json">{
|
||||||
"location": "navbar",
|
"location": "navbar",
|
||||||
"copy-button": false,
|
"copy-button": false,
|
||||||
@@ -72,7 +73,7 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="nav-fixed">
|
<body class="nav-fixed quarto-light">
|
||||||
|
|
||||||
<div id="quarto-search-results"></div>
|
<div id="quarto-search-results"></div>
|
||||||
<header id="quarto-header" class="headroom fixed-top">
|
<header id="quarto-header" class="headroom fixed-top">
|
||||||
@@ -143,236 +144,242 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
|
|
||||||
</main> <!-- /main -->
|
</main> <!-- /main -->
|
||||||
<script id="quarto-html-after-body" type="application/javascript">
|
<script id="quarto-html-after-body" type="application/javascript">
|
||||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||||
const toggleBodyColorMode = (bsSheetEl) => {
|
const icon = "";
|
||||||
const mode = bsSheetEl.getAttribute("data-mode");
|
const anchorJS = new window.AnchorJS();
|
||||||
const bodyEl = window.document.querySelector("body");
|
anchorJS.options = {
|
||||||
if (mode === "dark") {
|
placement: 'right',
|
||||||
bodyEl.classList.add("quarto-dark");
|
icon: icon
|
||||||
bodyEl.classList.remove("quarto-light");
|
|
||||||
} else {
|
|
||||||
bodyEl.classList.add("quarto-light");
|
|
||||||
bodyEl.classList.remove("quarto-dark");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const toggleBodyColorPrimary = () => {
|
|
||||||
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
|
||||||
if (bsSheetEl) {
|
|
||||||
toggleBodyColorMode(bsSheetEl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
toggleBodyColorPrimary();
|
|
||||||
const icon = "";
|
|
||||||
const anchorJS = new window.AnchorJS();
|
|
||||||
anchorJS.options = {
|
|
||||||
placement: 'right',
|
|
||||||
icon: icon
|
|
||||||
};
|
|
||||||
anchorJS.add('.anchored');
|
|
||||||
const isCodeAnnotation = (el) => {
|
|
||||||
for (const clz of el.classList) {
|
|
||||||
if (clz.startsWith('code-annotation-')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const onCopySuccess = function(e) {
|
|
||||||
// button target
|
|
||||||
const button = e.trigger;
|
|
||||||
// don't keep focus
|
|
||||||
button.blur();
|
|
||||||
// flash "checked"
|
|
||||||
button.classList.add('code-copy-button-checked');
|
|
||||||
var currentTitle = button.getAttribute("title");
|
|
||||||
button.setAttribute("title", "Copied!");
|
|
||||||
let tooltip;
|
|
||||||
if (window.bootstrap) {
|
|
||||||
button.setAttribute("data-bs-toggle", "tooltip");
|
|
||||||
button.setAttribute("data-bs-placement", "left");
|
|
||||||
button.setAttribute("data-bs-title", "Copied!");
|
|
||||||
tooltip = new bootstrap.Tooltip(button,
|
|
||||||
{ trigger: "manual",
|
|
||||||
customClass: "code-copy-button-tooltip",
|
|
||||||
offset: [0, -8]});
|
|
||||||
tooltip.show();
|
|
||||||
}
|
|
||||||
setTimeout(function() {
|
|
||||||
if (tooltip) {
|
|
||||||
tooltip.hide();
|
|
||||||
button.removeAttribute("data-bs-title");
|
|
||||||
button.removeAttribute("data-bs-toggle");
|
|
||||||
button.removeAttribute("data-bs-placement");
|
|
||||||
}
|
|
||||||
button.setAttribute("title", currentTitle);
|
|
||||||
button.classList.remove('code-copy-button-checked');
|
|
||||||
}, 1000);
|
|
||||||
// clear code selection
|
|
||||||
e.clearSelection();
|
|
||||||
}
|
|
||||||
const getTextToCopy = function(trigger) {
|
|
||||||
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
|
||||||
for (const childEl of codeEl.children) {
|
|
||||||
if (isCodeAnnotation(childEl)) {
|
|
||||||
childEl.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return codeEl.innerText;
|
|
||||||
}
|
|
||||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
|
||||||
text: getTextToCopy
|
|
||||||
});
|
|
||||||
clipboard.on('success', onCopySuccess);
|
|
||||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
|
||||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
|
||||||
text: getTextToCopy,
|
|
||||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
|
||||||
});
|
|
||||||
clipboardModal.on('success', onCopySuccess);
|
|
||||||
}
|
|
||||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
|
||||||
var mailtoRegex = new RegExp(/^mailto:/);
|
|
||||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
|
||||||
var isInternal = (href) => {
|
|
||||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
|
||||||
}
|
|
||||||
// Inspect non-navigation links and adorn them if external
|
|
||||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
|
||||||
for (var i=0; i<links.length; i++) {
|
|
||||||
const link = links[i];
|
|
||||||
if (!isInternal(link.href)) {
|
|
||||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
|
||||||
// links that we want to consider external
|
|
||||||
if (link.dataset.originalHref !== undefined) {
|
|
||||||
link.href = link.dataset.originalHref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
|
||||||
const config = {
|
|
||||||
allowHTML: true,
|
|
||||||
maxWidth: 500,
|
|
||||||
delay: 100,
|
|
||||||
arrow: false,
|
|
||||||
appendTo: function(el) {
|
|
||||||
return el.parentElement;
|
|
||||||
},
|
|
||||||
interactive: true,
|
|
||||||
interactiveBorder: 10,
|
|
||||||
theme: 'quarto',
|
|
||||||
placement: 'bottom-start',
|
|
||||||
};
|
};
|
||||||
if (contentFn) {
|
anchorJS.add('.anchored');
|
||||||
config.content = contentFn;
|
const isCodeAnnotation = (el) => {
|
||||||
}
|
for (const clz of el.classList) {
|
||||||
if (onTriggerFn) {
|
if (clz.startsWith('code-annotation-')) {
|
||||||
config.onTrigger = onTriggerFn;
|
return true;
|
||||||
}
|
|
||||||
if (onUntriggerFn) {
|
|
||||||
config.onUntrigger = onUntriggerFn;
|
|
||||||
}
|
|
||||||
window.tippy(el, config);
|
|
||||||
}
|
|
||||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
|
||||||
for (var i=0; i<noterefs.length; i++) {
|
|
||||||
const ref = noterefs[i];
|
|
||||||
tippyHover(ref, function() {
|
|
||||||
// use id or data attribute instead here
|
|
||||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
|
||||||
try { href = new URL(href).hash; } catch {}
|
|
||||||
const id = href.replace(/^#\/?/, "");
|
|
||||||
const note = window.document.getElementById(id);
|
|
||||||
if (note) {
|
|
||||||
return note.innerHTML;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
|
||||||
const processXRef = (id, note) => {
|
|
||||||
// Strip column container classes
|
|
||||||
const stripColumnClz = (el) => {
|
|
||||||
el.classList.remove("page-full", "page-columns");
|
|
||||||
if (el.children) {
|
|
||||||
for (const child of el.children) {
|
|
||||||
stripColumnClz(child);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
stripColumnClz(note)
|
const onCopySuccess = function(e) {
|
||||||
if (id === null || id.startsWith('sec-')) {
|
// button target
|
||||||
// Special case sections, only their first couple elements
|
const button = e.trigger;
|
||||||
const container = document.createElement("div");
|
// don't keep focus
|
||||||
if (note.children && note.children.length > 2) {
|
button.blur();
|
||||||
container.appendChild(note.children[0].cloneNode(true));
|
// flash "checked"
|
||||||
for (let i = 1; i < note.children.length; i++) {
|
button.classList.add('code-copy-button-checked');
|
||||||
const child = note.children[i];
|
var currentTitle = button.getAttribute("title");
|
||||||
if (child.tagName === "P" && child.innerText === "") {
|
button.setAttribute("title", "Copied!");
|
||||||
continue;
|
let tooltip;
|
||||||
} else {
|
if (window.bootstrap) {
|
||||||
container.appendChild(child.cloneNode(true));
|
button.setAttribute("data-bs-toggle", "tooltip");
|
||||||
break;
|
button.setAttribute("data-bs-placement", "left");
|
||||||
|
button.setAttribute("data-bs-title", "Copied!");
|
||||||
|
tooltip = new bootstrap.Tooltip(button,
|
||||||
|
{ trigger: "manual",
|
||||||
|
customClass: "code-copy-button-tooltip",
|
||||||
|
offset: [0, -8]});
|
||||||
|
tooltip.show();
|
||||||
|
}
|
||||||
|
setTimeout(function() {
|
||||||
|
if (tooltip) {
|
||||||
|
tooltip.hide();
|
||||||
|
button.removeAttribute("data-bs-title");
|
||||||
|
button.removeAttribute("data-bs-toggle");
|
||||||
|
button.removeAttribute("data-bs-placement");
|
||||||
|
}
|
||||||
|
button.setAttribute("title", currentTitle);
|
||||||
|
button.classList.remove('code-copy-button-checked');
|
||||||
|
}, 1000);
|
||||||
|
// clear code selection
|
||||||
|
e.clearSelection();
|
||||||
|
}
|
||||||
|
const getTextToCopy = function(trigger) {
|
||||||
|
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
||||||
|
for (const childEl of codeEl.children) {
|
||||||
|
if (isCodeAnnotation(childEl)) {
|
||||||
|
childEl.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (window.Quarto?.typesetMath) {
|
return codeEl.innerText;
|
||||||
window.Quarto.typesetMath(container);
|
}
|
||||||
|
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||||
|
text: getTextToCopy
|
||||||
|
});
|
||||||
|
clipboard.on('success', onCopySuccess);
|
||||||
|
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||||
|
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||||
|
text: getTextToCopy,
|
||||||
|
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||||
|
});
|
||||||
|
clipboardModal.on('success', onCopySuccess);
|
||||||
|
}
|
||||||
|
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||||
|
var mailtoRegex = new RegExp(/^mailto:/);
|
||||||
|
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||||
|
var isInternal = (href) => {
|
||||||
|
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||||
|
}
|
||||||
|
// Inspect non-navigation links and adorn them if external
|
||||||
|
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||||
|
for (var i=0; i<links.length; i++) {
|
||||||
|
const link = links[i];
|
||||||
|
if (!isInternal(link.href)) {
|
||||||
|
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||||
|
// links that we want to consider external
|
||||||
|
if (link.dataset.originalHref !== undefined) {
|
||||||
|
link.href = link.dataset.originalHref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||||
|
const config = {
|
||||||
|
allowHTML: true,
|
||||||
|
maxWidth: 500,
|
||||||
|
delay: 100,
|
||||||
|
arrow: false,
|
||||||
|
appendTo: function(el) {
|
||||||
|
return el.parentElement;
|
||||||
|
},
|
||||||
|
interactive: true,
|
||||||
|
interactiveBorder: 10,
|
||||||
|
theme: 'quarto',
|
||||||
|
placement: 'bottom-start',
|
||||||
|
};
|
||||||
|
if (contentFn) {
|
||||||
|
config.content = contentFn;
|
||||||
|
}
|
||||||
|
if (onTriggerFn) {
|
||||||
|
config.onTrigger = onTriggerFn;
|
||||||
|
}
|
||||||
|
if (onUntriggerFn) {
|
||||||
|
config.onUntrigger = onUntriggerFn;
|
||||||
|
}
|
||||||
|
window.tippy(el, config);
|
||||||
|
}
|
||||||
|
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||||
|
for (var i=0; i<noterefs.length; i++) {
|
||||||
|
const ref = noterefs[i];
|
||||||
|
tippyHover(ref, function() {
|
||||||
|
// use id or data attribute instead here
|
||||||
|
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||||
|
try { href = new URL(href).hash; } catch {}
|
||||||
|
const id = href.replace(/^#\/?/, "");
|
||||||
|
const note = window.document.getElementById(id);
|
||||||
|
if (note) {
|
||||||
|
return note.innerHTML;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||||
|
const processXRef = (id, note) => {
|
||||||
|
// Strip column container classes
|
||||||
|
const stripColumnClz = (el) => {
|
||||||
|
el.classList.remove("page-full", "page-columns");
|
||||||
|
if (el.children) {
|
||||||
|
for (const child of el.children) {
|
||||||
|
stripColumnClz(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stripColumnClz(note)
|
||||||
|
if (id === null || id.startsWith('sec-')) {
|
||||||
|
// Special case sections, only their first couple elements
|
||||||
|
const container = document.createElement("div");
|
||||||
|
if (note.children && note.children.length > 2) {
|
||||||
|
container.appendChild(note.children[0].cloneNode(true));
|
||||||
|
for (let i = 1; i < note.children.length; i++) {
|
||||||
|
const child = note.children[i];
|
||||||
|
if (child.tagName === "P" && child.innerText === "") {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
container.appendChild(child.cloneNode(true));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (window.Quarto?.typesetMath) {
|
||||||
|
window.Quarto.typesetMath(container);
|
||||||
|
}
|
||||||
|
return container.innerHTML
|
||||||
|
} else {
|
||||||
|
if (window.Quarto?.typesetMath) {
|
||||||
|
window.Quarto.typesetMath(note);
|
||||||
|
}
|
||||||
|
return note.innerHTML;
|
||||||
}
|
}
|
||||||
return container.innerHTML
|
|
||||||
} else {
|
} else {
|
||||||
|
// Remove any anchor links if they are present
|
||||||
|
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||||
|
if (anchorLink) {
|
||||||
|
anchorLink.remove();
|
||||||
|
}
|
||||||
if (window.Quarto?.typesetMath) {
|
if (window.Quarto?.typesetMath) {
|
||||||
window.Quarto.typesetMath(note);
|
window.Quarto.typesetMath(note);
|
||||||
}
|
}
|
||||||
return note.innerHTML;
|
if (note.classList.contains("callout")) {
|
||||||
}
|
return note.outerHTML;
|
||||||
} else {
|
} else {
|
||||||
// Remove any anchor links if they are present
|
return note.innerHTML;
|
||||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
}
|
||||||
if (anchorLink) {
|
|
||||||
anchorLink.remove();
|
|
||||||
}
|
|
||||||
if (window.Quarto?.typesetMath) {
|
|
||||||
window.Quarto.typesetMath(note);
|
|
||||||
}
|
|
||||||
if (note.classList.contains("callout")) {
|
|
||||||
return note.outerHTML;
|
|
||||||
} else {
|
|
||||||
return note.innerHTML;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (var i=0; i<xrefs.length; i++) {
|
||||||
for (var i=0; i<xrefs.length; i++) {
|
const xref = xrefs[i];
|
||||||
const xref = xrefs[i];
|
tippyHover(xref, undefined, function(instance) {
|
||||||
tippyHover(xref, undefined, function(instance) {
|
instance.disable();
|
||||||
instance.disable();
|
let url = xref.getAttribute('href');
|
||||||
let url = xref.getAttribute('href');
|
let hash = undefined;
|
||||||
let hash = undefined;
|
if (url.startsWith('#')) {
|
||||||
if (url.startsWith('#')) {
|
hash = url;
|
||||||
hash = url;
|
} else {
|
||||||
} else {
|
try { hash = new URL(url).hash; } catch {}
|
||||||
try { hash = new URL(url).hash; } catch {}
|
}
|
||||||
}
|
if (hash) {
|
||||||
if (hash) {
|
const id = hash.replace(/^#\/?/, "");
|
||||||
const id = hash.replace(/^#\/?/, "");
|
const note = window.document.getElementById(id);
|
||||||
const note = window.document.getElementById(id);
|
if (note !== null) {
|
||||||
if (note !== null) {
|
try {
|
||||||
try {
|
const html = processXRef(id, note.cloneNode(true));
|
||||||
const html = processXRef(id, note.cloneNode(true));
|
instance.setContent(html);
|
||||||
instance.setContent(html);
|
} finally {
|
||||||
} finally {
|
instance.enable();
|
||||||
instance.enable();
|
instance.show();
|
||||||
instance.show();
|
}
|
||||||
|
} else {
|
||||||
|
// See if we can fetch this
|
||||||
|
fetch(url.split('#')[0])
|
||||||
|
.then(res => res.text())
|
||||||
|
.then(html => {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||||
|
const note = htmlDoc.getElementById(id);
|
||||||
|
if (note !== null) {
|
||||||
|
const html = processXRef(id, note);
|
||||||
|
instance.setContent(html);
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
instance.enable();
|
||||||
|
instance.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// See if we can fetch this
|
// See if we can fetch a full url (with no hash to target)
|
||||||
fetch(url.split('#')[0])
|
// This is a special case and we should probably do some content thinning / targeting
|
||||||
|
fetch(url)
|
||||||
.then(res => res.text())
|
.then(res => res.text())
|
||||||
.then(html => {
|
.then(html => {
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||||
const note = htmlDoc.getElementById(id);
|
const note = htmlDoc.querySelector('main.content');
|
||||||
if (note !== null) {
|
if (note !== null) {
|
||||||
const html = processXRef(id, note);
|
// This should only happen for chapter cross references
|
||||||
|
// (since there is no id in the URL)
|
||||||
|
// remove the first header
|
||||||
|
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||||
|
note.children[0].remove();
|
||||||
|
}
|
||||||
|
const html = processXRef(null, note);
|
||||||
instance.setContent(html);
|
instance.setContent(html);
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -380,185 +387,161 @@ window.document.addEventListener("DOMContentLoaded", function (event) {
|
|||||||
instance.show();
|
instance.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
}, function(instance) {
|
||||||
// See if we can fetch a full url (with no hash to target)
|
|
||||||
// This is a special case and we should probably do some content thinning / targeting
|
|
||||||
fetch(url)
|
|
||||||
.then(res => res.text())
|
|
||||||
.then(html => {
|
|
||||||
const parser = new DOMParser();
|
|
||||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
|
||||||
const note = htmlDoc.querySelector('main.content');
|
|
||||||
if (note !== null) {
|
|
||||||
// This should only happen for chapter cross references
|
|
||||||
// (since there is no id in the URL)
|
|
||||||
// remove the first header
|
|
||||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
|
||||||
note.children[0].remove();
|
|
||||||
}
|
|
||||||
const html = processXRef(null, note);
|
|
||||||
instance.setContent(html);
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
instance.enable();
|
|
||||||
instance.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, function(instance) {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let selectedAnnoteEl;
|
|
||||||
const selectorForAnnotation = ( cell, annotation) => {
|
|
||||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
|
||||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
|
||||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
|
||||||
return selector;
|
|
||||||
}
|
|
||||||
const selectCodeLines = (annoteEl) => {
|
|
||||||
const doc = window.document;
|
|
||||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
|
||||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
|
||||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
|
||||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
|
||||||
const lineIds = lines.map((line) => {
|
|
||||||
return targetCell + "-" + line;
|
|
||||||
})
|
|
||||||
let top = null;
|
|
||||||
let height = null;
|
|
||||||
let parent = null;
|
|
||||||
if (lineIds.length > 0) {
|
|
||||||
//compute the position of the single el (top and bottom and make a div)
|
|
||||||
const el = window.document.getElementById(lineIds[0]);
|
|
||||||
top = el.offsetTop;
|
|
||||||
height = el.offsetHeight;
|
|
||||||
parent = el.parentElement.parentElement;
|
|
||||||
if (lineIds.length > 1) {
|
|
||||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
|
||||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
|
||||||
height = bottom - top;
|
|
||||||
}
|
|
||||||
if (top !== null && height !== null && parent !== null) {
|
|
||||||
// cook up a div (if necessary) and position it
|
|
||||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
|
||||||
if (div === null) {
|
|
||||||
div = window.document.createElement("div");
|
|
||||||
div.setAttribute("id", "code-annotation-line-highlight");
|
|
||||||
div.style.position = 'absolute';
|
|
||||||
parent.appendChild(div);
|
|
||||||
}
|
|
||||||
div.style.top = top - 2 + "px";
|
|
||||||
div.style.height = height + 4 + "px";
|
|
||||||
div.style.left = 0;
|
|
||||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
|
||||||
if (gutterDiv === null) {
|
|
||||||
gutterDiv = window.document.createElement("div");
|
|
||||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
|
||||||
gutterDiv.style.position = 'absolute';
|
|
||||||
const codeCell = window.document.getElementById(targetCell);
|
|
||||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
|
||||||
gutter.appendChild(gutterDiv);
|
|
||||||
}
|
|
||||||
gutterDiv.style.top = top - 2 + "px";
|
|
||||||
gutterDiv.style.height = height + 4 + "px";
|
|
||||||
}
|
|
||||||
selectedAnnoteEl = annoteEl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const unselectCodeLines = () => {
|
|
||||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
|
||||||
elementsIds.forEach((elId) => {
|
|
||||||
const div = window.document.getElementById(elId);
|
|
||||||
if (div) {
|
|
||||||
div.remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
selectedAnnoteEl = undefined;
|
|
||||||
};
|
|
||||||
// Handle positioning of the toggle
|
|
||||||
window.addEventListener(
|
|
||||||
"resize",
|
|
||||||
throttle(() => {
|
|
||||||
elRect = undefined;
|
|
||||||
if (selectedAnnoteEl) {
|
|
||||||
selectCodeLines(selectedAnnoteEl);
|
|
||||||
}
|
|
||||||
}, 10)
|
|
||||||
);
|
|
||||||
function throttle(fn, ms) {
|
|
||||||
let throttle = false;
|
|
||||||
let timer;
|
|
||||||
return (...args) => {
|
|
||||||
if(!throttle) { // first call gets through
|
|
||||||
fn.apply(this, args);
|
|
||||||
throttle = true;
|
|
||||||
} else { // all the others get throttled
|
|
||||||
if(timer) clearTimeout(timer); // cancel #2
|
|
||||||
timer = setTimeout(() => {
|
|
||||||
fn.apply(this, args);
|
|
||||||
timer = throttle = false;
|
|
||||||
}, ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// Attach click handler to the DT
|
|
||||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
|
||||||
for (const annoteDlNode of annoteDls) {
|
|
||||||
annoteDlNode.addEventListener('click', (event) => {
|
|
||||||
const clickedEl = event.target;
|
|
||||||
if (clickedEl !== selectedAnnoteEl) {
|
|
||||||
unselectCodeLines();
|
|
||||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
|
||||||
if (activeEl) {
|
|
||||||
activeEl.classList.remove('code-annotation-active');
|
|
||||||
}
|
|
||||||
selectCodeLines(clickedEl);
|
|
||||||
clickedEl.classList.add('code-annotation-active');
|
|
||||||
} else {
|
|
||||||
// Unselect the line
|
|
||||||
unselectCodeLines();
|
|
||||||
clickedEl.classList.remove('code-annotation-active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const findCites = (el) => {
|
|
||||||
const parentEl = el.parentElement;
|
|
||||||
if (parentEl) {
|
|
||||||
const cites = parentEl.dataset.cites;
|
|
||||||
if (cites) {
|
|
||||||
return {
|
|
||||||
el,
|
|
||||||
cites: cites.split(' ')
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return findCites(el.parentElement)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
|
||||||
for (var i=0; i<bibliorefs.length; i++) {
|
|
||||||
const ref = bibliorefs[i];
|
|
||||||
const citeInfo = findCites(ref);
|
|
||||||
if (citeInfo) {
|
|
||||||
tippyHover(citeInfo.el, function() {
|
|
||||||
var popup = window.document.createElement('div');
|
|
||||||
citeInfo.cites.forEach(function(cite) {
|
|
||||||
var citeDiv = window.document.createElement('div');
|
|
||||||
citeDiv.classList.add('hanging-indent');
|
|
||||||
citeDiv.classList.add('csl-entry');
|
|
||||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
|
||||||
if (biblioDiv) {
|
|
||||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
|
||||||
}
|
|
||||||
popup.appendChild(citeDiv);
|
|
||||||
});
|
|
||||||
return popup.innerHTML;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
let selectedAnnoteEl;
|
||||||
});
|
const selectorForAnnotation = ( cell, annotation) => {
|
||||||
</script>
|
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||||
|
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||||
|
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
const selectCodeLines = (annoteEl) => {
|
||||||
|
const doc = window.document;
|
||||||
|
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||||
|
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||||
|
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||||
|
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||||
|
const lineIds = lines.map((line) => {
|
||||||
|
return targetCell + "-" + line;
|
||||||
|
})
|
||||||
|
let top = null;
|
||||||
|
let height = null;
|
||||||
|
let parent = null;
|
||||||
|
if (lineIds.length > 0) {
|
||||||
|
//compute the position of the single el (top and bottom and make a div)
|
||||||
|
const el = window.document.getElementById(lineIds[0]);
|
||||||
|
top = el.offsetTop;
|
||||||
|
height = el.offsetHeight;
|
||||||
|
parent = el.parentElement.parentElement;
|
||||||
|
if (lineIds.length > 1) {
|
||||||
|
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||||
|
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||||
|
height = bottom - top;
|
||||||
|
}
|
||||||
|
if (top !== null && height !== null && parent !== null) {
|
||||||
|
// cook up a div (if necessary) and position it
|
||||||
|
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||||
|
if (div === null) {
|
||||||
|
div = window.document.createElement("div");
|
||||||
|
div.setAttribute("id", "code-annotation-line-highlight");
|
||||||
|
div.style.position = 'absolute';
|
||||||
|
parent.appendChild(div);
|
||||||
|
}
|
||||||
|
div.style.top = top - 2 + "px";
|
||||||
|
div.style.height = height + 4 + "px";
|
||||||
|
div.style.left = 0;
|
||||||
|
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||||
|
if (gutterDiv === null) {
|
||||||
|
gutterDiv = window.document.createElement("div");
|
||||||
|
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||||
|
gutterDiv.style.position = 'absolute';
|
||||||
|
const codeCell = window.document.getElementById(targetCell);
|
||||||
|
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||||
|
gutter.appendChild(gutterDiv);
|
||||||
|
}
|
||||||
|
gutterDiv.style.top = top - 2 + "px";
|
||||||
|
gutterDiv.style.height = height + 4 + "px";
|
||||||
|
}
|
||||||
|
selectedAnnoteEl = annoteEl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const unselectCodeLines = () => {
|
||||||
|
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||||
|
elementsIds.forEach((elId) => {
|
||||||
|
const div = window.document.getElementById(elId);
|
||||||
|
if (div) {
|
||||||
|
div.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
selectedAnnoteEl = undefined;
|
||||||
|
};
|
||||||
|
// Handle positioning of the toggle
|
||||||
|
window.addEventListener(
|
||||||
|
"resize",
|
||||||
|
throttle(() => {
|
||||||
|
elRect = undefined;
|
||||||
|
if (selectedAnnoteEl) {
|
||||||
|
selectCodeLines(selectedAnnoteEl);
|
||||||
|
}
|
||||||
|
}, 10)
|
||||||
|
);
|
||||||
|
function throttle(fn, ms) {
|
||||||
|
let throttle = false;
|
||||||
|
let timer;
|
||||||
|
return (...args) => {
|
||||||
|
if(!throttle) { // first call gets through
|
||||||
|
fn.apply(this, args);
|
||||||
|
throttle = true;
|
||||||
|
} else { // all the others get throttled
|
||||||
|
if(timer) clearTimeout(timer); // cancel #2
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fn.apply(this, args);
|
||||||
|
timer = throttle = false;
|
||||||
|
}, ms);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Attach click handler to the DT
|
||||||
|
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||||
|
for (const annoteDlNode of annoteDls) {
|
||||||
|
annoteDlNode.addEventListener('click', (event) => {
|
||||||
|
const clickedEl = event.target;
|
||||||
|
if (clickedEl !== selectedAnnoteEl) {
|
||||||
|
unselectCodeLines();
|
||||||
|
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||||
|
if (activeEl) {
|
||||||
|
activeEl.classList.remove('code-annotation-active');
|
||||||
|
}
|
||||||
|
selectCodeLines(clickedEl);
|
||||||
|
clickedEl.classList.add('code-annotation-active');
|
||||||
|
} else {
|
||||||
|
// Unselect the line
|
||||||
|
unselectCodeLines();
|
||||||
|
clickedEl.classList.remove('code-annotation-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const findCites = (el) => {
|
||||||
|
const parentEl = el.parentElement;
|
||||||
|
if (parentEl) {
|
||||||
|
const cites = parentEl.dataset.cites;
|
||||||
|
if (cites) {
|
||||||
|
return {
|
||||||
|
el,
|
||||||
|
cites: cites.split(' ')
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return findCites(el.parentElement)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||||
|
for (var i=0; i<bibliorefs.length; i++) {
|
||||||
|
const ref = bibliorefs[i];
|
||||||
|
const citeInfo = findCites(ref);
|
||||||
|
if (citeInfo) {
|
||||||
|
tippyHover(citeInfo.el, function() {
|
||||||
|
var popup = window.document.createElement('div');
|
||||||
|
citeInfo.cites.forEach(function(cite) {
|
||||||
|
var citeDiv = window.document.createElement('div');
|
||||||
|
citeDiv.classList.add('hanging-indent');
|
||||||
|
citeDiv.classList.add('csl-entry');
|
||||||
|
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||||
|
if (biblioDiv) {
|
||||||
|
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||||
|
}
|
||||||
|
popup.appendChild(citeDiv);
|
||||||
|
});
|
||||||
|
return popup.innerHTML;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</div> <!-- /content -->
|
</div> <!-- /content -->
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+376
-393
@@ -2,7 +2,7 @@
|
|||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
||||||
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="generator" content="quarto-1.6.43">
|
<meta name="generator" content="quarto-1.7.29">
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||||
|
|
||||||
@@ -31,15 +31,16 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
||||||
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
||||||
<meta name="quarto:offset" content="./">
|
<meta name="quarto:offset" content="./">
|
||||||
<script src="site_libs/quarto-html/quarto.js"></script>
|
<script src="site_libs/quarto-html/quarto.js" type="module"></script>
|
||||||
|
<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
|
||||||
<script src="site_libs/quarto-html/popper.min.js"></script>
|
<script src="site_libs/quarto-html/popper.min.js"></script>
|
||||||
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
||||||
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
||||||
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
||||||
<link href="site_libs/quarto-html/quarto-syntax-highlighting-d4d76bf8491c20bad77d141916dc28e1.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
<link href="site_libs/quarto-html/quarto-syntax-highlighting-0815c480559380816a4d1ea211a47e91.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
||||||
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
||||||
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
||||||
<link href="site_libs/bootstrap/bootstrap-12858c9ce0885248945210bbd3c85d1a.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
<link href="site_libs/bootstrap/bootstrap-630147fbe0b9ab2b2a517857e522e257.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
||||||
<script id="quarto-search-options" type="application/json">{
|
<script id="quarto-search-options" type="application/json">{
|
||||||
"location": "navbar",
|
"location": "navbar",
|
||||||
"copy-button": false,
|
"copy-button": false,
|
||||||
@@ -73,7 +74,7 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="nav-fixed">
|
<body class="nav-fixed quarto-light">
|
||||||
|
|
||||||
<div id="quarto-search-results"></div>
|
<div id="quarto-search-results"></div>
|
||||||
<header id="quarto-header" class="headroom fixed-top">
|
<header id="quarto-header" class="headroom fixed-top">
|
||||||
@@ -186,7 +187,7 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
<div>
|
<div>
|
||||||
<div class="quarto-title-meta-heading">Modified</div>
|
<div class="quarto-title-meta-heading">Modified</div>
|
||||||
<div class="quarto-title-meta-contents">
|
<div class="quarto-title-meta-contents">
|
||||||
<p class="date-modified">April 28, 2025</p>
|
<p class="date-modified">April 30, 2025</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -837,236 +838,242 @@ ul.task-list li input[type="checkbox"] {
|
|||||||
|
|
||||||
</main> <!-- /main -->
|
</main> <!-- /main -->
|
||||||
<script id="quarto-html-after-body" type="application/javascript">
|
<script id="quarto-html-after-body" type="application/javascript">
|
||||||
window.document.addEventListener("DOMContentLoaded", function (event) {
|
window.document.addEventListener("DOMContentLoaded", function (event) {
|
||||||
const toggleBodyColorMode = (bsSheetEl) => {
|
const icon = "";
|
||||||
const mode = bsSheetEl.getAttribute("data-mode");
|
const anchorJS = new window.AnchorJS();
|
||||||
const bodyEl = window.document.querySelector("body");
|
anchorJS.options = {
|
||||||
if (mode === "dark") {
|
placement: 'right',
|
||||||
bodyEl.classList.add("quarto-dark");
|
icon: icon
|
||||||
bodyEl.classList.remove("quarto-light");
|
|
||||||
} else {
|
|
||||||
bodyEl.classList.add("quarto-light");
|
|
||||||
bodyEl.classList.remove("quarto-dark");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const toggleBodyColorPrimary = () => {
|
|
||||||
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
|
||||||
if (bsSheetEl) {
|
|
||||||
toggleBodyColorMode(bsSheetEl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
toggleBodyColorPrimary();
|
|
||||||
const icon = "";
|
|
||||||
const anchorJS = new window.AnchorJS();
|
|
||||||
anchorJS.options = {
|
|
||||||
placement: 'right',
|
|
||||||
icon: icon
|
|
||||||
};
|
|
||||||
anchorJS.add('.anchored');
|
|
||||||
const isCodeAnnotation = (el) => {
|
|
||||||
for (const clz of el.classList) {
|
|
||||||
if (clz.startsWith('code-annotation-')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const onCopySuccess = function(e) {
|
|
||||||
// button target
|
|
||||||
const button = e.trigger;
|
|
||||||
// don't keep focus
|
|
||||||
button.blur();
|
|
||||||
// flash "checked"
|
|
||||||
button.classList.add('code-copy-button-checked');
|
|
||||||
var currentTitle = button.getAttribute("title");
|
|
||||||
button.setAttribute("title", "Copied!");
|
|
||||||
let tooltip;
|
|
||||||
if (window.bootstrap) {
|
|
||||||
button.setAttribute("data-bs-toggle", "tooltip");
|
|
||||||
button.setAttribute("data-bs-placement", "left");
|
|
||||||
button.setAttribute("data-bs-title", "Copied!");
|
|
||||||
tooltip = new bootstrap.Tooltip(button,
|
|
||||||
{ trigger: "manual",
|
|
||||||
customClass: "code-copy-button-tooltip",
|
|
||||||
offset: [0, -8]});
|
|
||||||
tooltip.show();
|
|
||||||
}
|
|
||||||
setTimeout(function() {
|
|
||||||
if (tooltip) {
|
|
||||||
tooltip.hide();
|
|
||||||
button.removeAttribute("data-bs-title");
|
|
||||||
button.removeAttribute("data-bs-toggle");
|
|
||||||
button.removeAttribute("data-bs-placement");
|
|
||||||
}
|
|
||||||
button.setAttribute("title", currentTitle);
|
|
||||||
button.classList.remove('code-copy-button-checked');
|
|
||||||
}, 1000);
|
|
||||||
// clear code selection
|
|
||||||
e.clearSelection();
|
|
||||||
}
|
|
||||||
const getTextToCopy = function(trigger) {
|
|
||||||
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
|
||||||
for (const childEl of codeEl.children) {
|
|
||||||
if (isCodeAnnotation(childEl)) {
|
|
||||||
childEl.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return codeEl.innerText;
|
|
||||||
}
|
|
||||||
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
|
||||||
text: getTextToCopy
|
|
||||||
});
|
|
||||||
clipboard.on('success', onCopySuccess);
|
|
||||||
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
|
||||||
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
|
||||||
text: getTextToCopy,
|
|
||||||
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
|
||||||
});
|
|
||||||
clipboardModal.on('success', onCopySuccess);
|
|
||||||
}
|
|
||||||
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
|
||||||
var mailtoRegex = new RegExp(/^mailto:/);
|
|
||||||
var filterRegex = new RegExp('/' + window.location.host + '/');
|
|
||||||
var isInternal = (href) => {
|
|
||||||
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
|
||||||
}
|
|
||||||
// Inspect non-navigation links and adorn them if external
|
|
||||||
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
|
||||||
for (var i=0; i<links.length; i++) {
|
|
||||||
const link = links[i];
|
|
||||||
if (!isInternal(link.href)) {
|
|
||||||
// undo the damage that might have been done by quarto-nav.js in the case of
|
|
||||||
// links that we want to consider external
|
|
||||||
if (link.dataset.originalHref !== undefined) {
|
|
||||||
link.href = link.dataset.originalHref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
|
||||||
const config = {
|
|
||||||
allowHTML: true,
|
|
||||||
maxWidth: 500,
|
|
||||||
delay: 100,
|
|
||||||
arrow: false,
|
|
||||||
appendTo: function(el) {
|
|
||||||
return el.parentElement;
|
|
||||||
},
|
|
||||||
interactive: true,
|
|
||||||
interactiveBorder: 10,
|
|
||||||
theme: 'quarto',
|
|
||||||
placement: 'bottom-start',
|
|
||||||
};
|
};
|
||||||
if (contentFn) {
|
anchorJS.add('.anchored');
|
||||||
config.content = contentFn;
|
const isCodeAnnotation = (el) => {
|
||||||
}
|
for (const clz of el.classList) {
|
||||||
if (onTriggerFn) {
|
if (clz.startsWith('code-annotation-')) {
|
||||||
config.onTrigger = onTriggerFn;
|
return true;
|
||||||
}
|
|
||||||
if (onUntriggerFn) {
|
|
||||||
config.onUntrigger = onUntriggerFn;
|
|
||||||
}
|
|
||||||
window.tippy(el, config);
|
|
||||||
}
|
|
||||||
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
|
||||||
for (var i=0; i<noterefs.length; i++) {
|
|
||||||
const ref = noterefs[i];
|
|
||||||
tippyHover(ref, function() {
|
|
||||||
// use id or data attribute instead here
|
|
||||||
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
|
||||||
try { href = new URL(href).hash; } catch {}
|
|
||||||
const id = href.replace(/^#\/?/, "");
|
|
||||||
const note = window.document.getElementById(id);
|
|
||||||
if (note) {
|
|
||||||
return note.innerHTML;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
|
||||||
const processXRef = (id, note) => {
|
|
||||||
// Strip column container classes
|
|
||||||
const stripColumnClz = (el) => {
|
|
||||||
el.classList.remove("page-full", "page-columns");
|
|
||||||
if (el.children) {
|
|
||||||
for (const child of el.children) {
|
|
||||||
stripColumnClz(child);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
stripColumnClz(note)
|
const onCopySuccess = function(e) {
|
||||||
if (id === null || id.startsWith('sec-')) {
|
// button target
|
||||||
// Special case sections, only their first couple elements
|
const button = e.trigger;
|
||||||
const container = document.createElement("div");
|
// don't keep focus
|
||||||
if (note.children && note.children.length > 2) {
|
button.blur();
|
||||||
container.appendChild(note.children[0].cloneNode(true));
|
// flash "checked"
|
||||||
for (let i = 1; i < note.children.length; i++) {
|
button.classList.add('code-copy-button-checked');
|
||||||
const child = note.children[i];
|
var currentTitle = button.getAttribute("title");
|
||||||
if (child.tagName === "P" && child.innerText === "") {
|
button.setAttribute("title", "Copied!");
|
||||||
continue;
|
let tooltip;
|
||||||
} else {
|
if (window.bootstrap) {
|
||||||
container.appendChild(child.cloneNode(true));
|
button.setAttribute("data-bs-toggle", "tooltip");
|
||||||
break;
|
button.setAttribute("data-bs-placement", "left");
|
||||||
|
button.setAttribute("data-bs-title", "Copied!");
|
||||||
|
tooltip = new bootstrap.Tooltip(button,
|
||||||
|
{ trigger: "manual",
|
||||||
|
customClass: "code-copy-button-tooltip",
|
||||||
|
offset: [0, -8]});
|
||||||
|
tooltip.show();
|
||||||
|
}
|
||||||
|
setTimeout(function() {
|
||||||
|
if (tooltip) {
|
||||||
|
tooltip.hide();
|
||||||
|
button.removeAttribute("data-bs-title");
|
||||||
|
button.removeAttribute("data-bs-toggle");
|
||||||
|
button.removeAttribute("data-bs-placement");
|
||||||
|
}
|
||||||
|
button.setAttribute("title", currentTitle);
|
||||||
|
button.classList.remove('code-copy-button-checked');
|
||||||
|
}, 1000);
|
||||||
|
// clear code selection
|
||||||
|
e.clearSelection();
|
||||||
|
}
|
||||||
|
const getTextToCopy = function(trigger) {
|
||||||
|
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
||||||
|
for (const childEl of codeEl.children) {
|
||||||
|
if (isCodeAnnotation(childEl)) {
|
||||||
|
childEl.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (window.Quarto?.typesetMath) {
|
return codeEl.innerText;
|
||||||
window.Quarto.typesetMath(container);
|
}
|
||||||
|
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
||||||
|
text: getTextToCopy
|
||||||
|
});
|
||||||
|
clipboard.on('success', onCopySuccess);
|
||||||
|
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
||||||
|
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
||||||
|
text: getTextToCopy,
|
||||||
|
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
||||||
|
});
|
||||||
|
clipboardModal.on('success', onCopySuccess);
|
||||||
|
}
|
||||||
|
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
||||||
|
var mailtoRegex = new RegExp(/^mailto:/);
|
||||||
|
var filterRegex = new RegExp('/' + window.location.host + '/');
|
||||||
|
var isInternal = (href) => {
|
||||||
|
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
||||||
|
}
|
||||||
|
// Inspect non-navigation links and adorn them if external
|
||||||
|
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
||||||
|
for (var i=0; i<links.length; i++) {
|
||||||
|
const link = links[i];
|
||||||
|
if (!isInternal(link.href)) {
|
||||||
|
// undo the damage that might have been done by quarto-nav.js in the case of
|
||||||
|
// links that we want to consider external
|
||||||
|
if (link.dataset.originalHref !== undefined) {
|
||||||
|
link.href = link.dataset.originalHref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
||||||
|
const config = {
|
||||||
|
allowHTML: true,
|
||||||
|
maxWidth: 500,
|
||||||
|
delay: 100,
|
||||||
|
arrow: false,
|
||||||
|
appendTo: function(el) {
|
||||||
|
return el.parentElement;
|
||||||
|
},
|
||||||
|
interactive: true,
|
||||||
|
interactiveBorder: 10,
|
||||||
|
theme: 'quarto',
|
||||||
|
placement: 'bottom-start',
|
||||||
|
};
|
||||||
|
if (contentFn) {
|
||||||
|
config.content = contentFn;
|
||||||
|
}
|
||||||
|
if (onTriggerFn) {
|
||||||
|
config.onTrigger = onTriggerFn;
|
||||||
|
}
|
||||||
|
if (onUntriggerFn) {
|
||||||
|
config.onUntrigger = onUntriggerFn;
|
||||||
|
}
|
||||||
|
window.tippy(el, config);
|
||||||
|
}
|
||||||
|
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
||||||
|
for (var i=0; i<noterefs.length; i++) {
|
||||||
|
const ref = noterefs[i];
|
||||||
|
tippyHover(ref, function() {
|
||||||
|
// use id or data attribute instead here
|
||||||
|
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
||||||
|
try { href = new URL(href).hash; } catch {}
|
||||||
|
const id = href.replace(/^#\/?/, "");
|
||||||
|
const note = window.document.getElementById(id);
|
||||||
|
if (note) {
|
||||||
|
return note.innerHTML;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
||||||
|
const processXRef = (id, note) => {
|
||||||
|
// Strip column container classes
|
||||||
|
const stripColumnClz = (el) => {
|
||||||
|
el.classList.remove("page-full", "page-columns");
|
||||||
|
if (el.children) {
|
||||||
|
for (const child of el.children) {
|
||||||
|
stripColumnClz(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stripColumnClz(note)
|
||||||
|
if (id === null || id.startsWith('sec-')) {
|
||||||
|
// Special case sections, only their first couple elements
|
||||||
|
const container = document.createElement("div");
|
||||||
|
if (note.children && note.children.length > 2) {
|
||||||
|
container.appendChild(note.children[0].cloneNode(true));
|
||||||
|
for (let i = 1; i < note.children.length; i++) {
|
||||||
|
const child = note.children[i];
|
||||||
|
if (child.tagName === "P" && child.innerText === "") {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
container.appendChild(child.cloneNode(true));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (window.Quarto?.typesetMath) {
|
||||||
|
window.Quarto.typesetMath(container);
|
||||||
|
}
|
||||||
|
return container.innerHTML
|
||||||
|
} else {
|
||||||
|
if (window.Quarto?.typesetMath) {
|
||||||
|
window.Quarto.typesetMath(note);
|
||||||
|
}
|
||||||
|
return note.innerHTML;
|
||||||
}
|
}
|
||||||
return container.innerHTML
|
|
||||||
} else {
|
} else {
|
||||||
|
// Remove any anchor links if they are present
|
||||||
|
const anchorLink = note.querySelector('a.anchorjs-link');
|
||||||
|
if (anchorLink) {
|
||||||
|
anchorLink.remove();
|
||||||
|
}
|
||||||
if (window.Quarto?.typesetMath) {
|
if (window.Quarto?.typesetMath) {
|
||||||
window.Quarto.typesetMath(note);
|
window.Quarto.typesetMath(note);
|
||||||
}
|
}
|
||||||
return note.innerHTML;
|
if (note.classList.contains("callout")) {
|
||||||
}
|
return note.outerHTML;
|
||||||
} else {
|
} else {
|
||||||
// Remove any anchor links if they are present
|
return note.innerHTML;
|
||||||
const anchorLink = note.querySelector('a.anchorjs-link');
|
}
|
||||||
if (anchorLink) {
|
|
||||||
anchorLink.remove();
|
|
||||||
}
|
|
||||||
if (window.Quarto?.typesetMath) {
|
|
||||||
window.Quarto.typesetMath(note);
|
|
||||||
}
|
|
||||||
if (note.classList.contains("callout")) {
|
|
||||||
return note.outerHTML;
|
|
||||||
} else {
|
|
||||||
return note.innerHTML;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (var i=0; i<xrefs.length; i++) {
|
||||||
for (var i=0; i<xrefs.length; i++) {
|
const xref = xrefs[i];
|
||||||
const xref = xrefs[i];
|
tippyHover(xref, undefined, function(instance) {
|
||||||
tippyHover(xref, undefined, function(instance) {
|
instance.disable();
|
||||||
instance.disable();
|
let url = xref.getAttribute('href');
|
||||||
let url = xref.getAttribute('href');
|
let hash = undefined;
|
||||||
let hash = undefined;
|
if (url.startsWith('#')) {
|
||||||
if (url.startsWith('#')) {
|
hash = url;
|
||||||
hash = url;
|
} else {
|
||||||
} else {
|
try { hash = new URL(url).hash; } catch {}
|
||||||
try { hash = new URL(url).hash; } catch {}
|
}
|
||||||
}
|
if (hash) {
|
||||||
if (hash) {
|
const id = hash.replace(/^#\/?/, "");
|
||||||
const id = hash.replace(/^#\/?/, "");
|
const note = window.document.getElementById(id);
|
||||||
const note = window.document.getElementById(id);
|
if (note !== null) {
|
||||||
if (note !== null) {
|
try {
|
||||||
try {
|
const html = processXRef(id, note.cloneNode(true));
|
||||||
const html = processXRef(id, note.cloneNode(true));
|
instance.setContent(html);
|
||||||
instance.setContent(html);
|
} finally {
|
||||||
} finally {
|
instance.enable();
|
||||||
instance.enable();
|
instance.show();
|
||||||
instance.show();
|
}
|
||||||
|
} else {
|
||||||
|
// See if we can fetch this
|
||||||
|
fetch(url.split('#')[0])
|
||||||
|
.then(res => res.text())
|
||||||
|
.then(html => {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||||
|
const note = htmlDoc.getElementById(id);
|
||||||
|
if (note !== null) {
|
||||||
|
const html = processXRef(id, note);
|
||||||
|
instance.setContent(html);
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
instance.enable();
|
||||||
|
instance.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// See if we can fetch this
|
// See if we can fetch a full url (with no hash to target)
|
||||||
fetch(url.split('#')[0])
|
// This is a special case and we should probably do some content thinning / targeting
|
||||||
|
fetch(url)
|
||||||
.then(res => res.text())
|
.then(res => res.text())
|
||||||
.then(html => {
|
.then(html => {
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||||
const note = htmlDoc.getElementById(id);
|
const note = htmlDoc.querySelector('main.content');
|
||||||
if (note !== null) {
|
if (note !== null) {
|
||||||
const html = processXRef(id, note);
|
// This should only happen for chapter cross references
|
||||||
|
// (since there is no id in the URL)
|
||||||
|
// remove the first header
|
||||||
|
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
||||||
|
note.children[0].remove();
|
||||||
|
}
|
||||||
|
const html = processXRef(null, note);
|
||||||
instance.setContent(html);
|
instance.setContent(html);
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -1074,185 +1081,161 @@ window.document.addEventListener("DOMContentLoaded", function (event) {
|
|||||||
instance.show();
|
instance.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
}, function(instance) {
|
||||||
// See if we can fetch a full url (with no hash to target)
|
|
||||||
// This is a special case and we should probably do some content thinning / targeting
|
|
||||||
fetch(url)
|
|
||||||
.then(res => res.text())
|
|
||||||
.then(html => {
|
|
||||||
const parser = new DOMParser();
|
|
||||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
|
||||||
const note = htmlDoc.querySelector('main.content');
|
|
||||||
if (note !== null) {
|
|
||||||
// This should only happen for chapter cross references
|
|
||||||
// (since there is no id in the URL)
|
|
||||||
// remove the first header
|
|
||||||
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
|
||||||
note.children[0].remove();
|
|
||||||
}
|
|
||||||
const html = processXRef(null, note);
|
|
||||||
instance.setContent(html);
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
instance.enable();
|
|
||||||
instance.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, function(instance) {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let selectedAnnoteEl;
|
|
||||||
const selectorForAnnotation = ( cell, annotation) => {
|
|
||||||
let cellAttr = 'data-code-cell="' + cell + '"';
|
|
||||||
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
|
||||||
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
|
||||||
return selector;
|
|
||||||
}
|
|
||||||
const selectCodeLines = (annoteEl) => {
|
|
||||||
const doc = window.document;
|
|
||||||
const targetCell = annoteEl.getAttribute("data-target-cell");
|
|
||||||
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
|
||||||
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
|
||||||
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
|
||||||
const lineIds = lines.map((line) => {
|
|
||||||
return targetCell + "-" + line;
|
|
||||||
})
|
|
||||||
let top = null;
|
|
||||||
let height = null;
|
|
||||||
let parent = null;
|
|
||||||
if (lineIds.length > 0) {
|
|
||||||
//compute the position of the single el (top and bottom and make a div)
|
|
||||||
const el = window.document.getElementById(lineIds[0]);
|
|
||||||
top = el.offsetTop;
|
|
||||||
height = el.offsetHeight;
|
|
||||||
parent = el.parentElement.parentElement;
|
|
||||||
if (lineIds.length > 1) {
|
|
||||||
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
|
||||||
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
|
||||||
height = bottom - top;
|
|
||||||
}
|
|
||||||
if (top !== null && height !== null && parent !== null) {
|
|
||||||
// cook up a div (if necessary) and position it
|
|
||||||
let div = window.document.getElementById("code-annotation-line-highlight");
|
|
||||||
if (div === null) {
|
|
||||||
div = window.document.createElement("div");
|
|
||||||
div.setAttribute("id", "code-annotation-line-highlight");
|
|
||||||
div.style.position = 'absolute';
|
|
||||||
parent.appendChild(div);
|
|
||||||
}
|
|
||||||
div.style.top = top - 2 + "px";
|
|
||||||
div.style.height = height + 4 + "px";
|
|
||||||
div.style.left = 0;
|
|
||||||
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
|
||||||
if (gutterDiv === null) {
|
|
||||||
gutterDiv = window.document.createElement("div");
|
|
||||||
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
|
||||||
gutterDiv.style.position = 'absolute';
|
|
||||||
const codeCell = window.document.getElementById(targetCell);
|
|
||||||
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
|
||||||
gutter.appendChild(gutterDiv);
|
|
||||||
}
|
|
||||||
gutterDiv.style.top = top - 2 + "px";
|
|
||||||
gutterDiv.style.height = height + 4 + "px";
|
|
||||||
}
|
|
||||||
selectedAnnoteEl = annoteEl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const unselectCodeLines = () => {
|
|
||||||
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
|
||||||
elementsIds.forEach((elId) => {
|
|
||||||
const div = window.document.getElementById(elId);
|
|
||||||
if (div) {
|
|
||||||
div.remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
selectedAnnoteEl = undefined;
|
|
||||||
};
|
|
||||||
// Handle positioning of the toggle
|
|
||||||
window.addEventListener(
|
|
||||||
"resize",
|
|
||||||
throttle(() => {
|
|
||||||
elRect = undefined;
|
|
||||||
if (selectedAnnoteEl) {
|
|
||||||
selectCodeLines(selectedAnnoteEl);
|
|
||||||
}
|
|
||||||
}, 10)
|
|
||||||
);
|
|
||||||
function throttle(fn, ms) {
|
|
||||||
let throttle = false;
|
|
||||||
let timer;
|
|
||||||
return (...args) => {
|
|
||||||
if(!throttle) { // first call gets through
|
|
||||||
fn.apply(this, args);
|
|
||||||
throttle = true;
|
|
||||||
} else { // all the others get throttled
|
|
||||||
if(timer) clearTimeout(timer); // cancel #2
|
|
||||||
timer = setTimeout(() => {
|
|
||||||
fn.apply(this, args);
|
|
||||||
timer = throttle = false;
|
|
||||||
}, ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// Attach click handler to the DT
|
|
||||||
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
|
||||||
for (const annoteDlNode of annoteDls) {
|
|
||||||
annoteDlNode.addEventListener('click', (event) => {
|
|
||||||
const clickedEl = event.target;
|
|
||||||
if (clickedEl !== selectedAnnoteEl) {
|
|
||||||
unselectCodeLines();
|
|
||||||
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
|
||||||
if (activeEl) {
|
|
||||||
activeEl.classList.remove('code-annotation-active');
|
|
||||||
}
|
|
||||||
selectCodeLines(clickedEl);
|
|
||||||
clickedEl.classList.add('code-annotation-active');
|
|
||||||
} else {
|
|
||||||
// Unselect the line
|
|
||||||
unselectCodeLines();
|
|
||||||
clickedEl.classList.remove('code-annotation-active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const findCites = (el) => {
|
|
||||||
const parentEl = el.parentElement;
|
|
||||||
if (parentEl) {
|
|
||||||
const cites = parentEl.dataset.cites;
|
|
||||||
if (cites) {
|
|
||||||
return {
|
|
||||||
el,
|
|
||||||
cites: cites.split(' ')
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return findCites(el.parentElement)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
|
||||||
for (var i=0; i<bibliorefs.length; i++) {
|
|
||||||
const ref = bibliorefs[i];
|
|
||||||
const citeInfo = findCites(ref);
|
|
||||||
if (citeInfo) {
|
|
||||||
tippyHover(citeInfo.el, function() {
|
|
||||||
var popup = window.document.createElement('div');
|
|
||||||
citeInfo.cites.forEach(function(cite) {
|
|
||||||
var citeDiv = window.document.createElement('div');
|
|
||||||
citeDiv.classList.add('hanging-indent');
|
|
||||||
citeDiv.classList.add('csl-entry');
|
|
||||||
var biblioDiv = window.document.getElementById('ref-' + cite);
|
|
||||||
if (biblioDiv) {
|
|
||||||
citeDiv.innerHTML = biblioDiv.innerHTML;
|
|
||||||
}
|
|
||||||
popup.appendChild(citeDiv);
|
|
||||||
});
|
|
||||||
return popup.innerHTML;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
let selectedAnnoteEl;
|
||||||
});
|
const selectorForAnnotation = ( cell, annotation) => {
|
||||||
</script>
|
let cellAttr = 'data-code-cell="' + cell + '"';
|
||||||
|
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
||||||
|
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
const selectCodeLines = (annoteEl) => {
|
||||||
|
const doc = window.document;
|
||||||
|
const targetCell = annoteEl.getAttribute("data-target-cell");
|
||||||
|
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
||||||
|
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
||||||
|
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
||||||
|
const lineIds = lines.map((line) => {
|
||||||
|
return targetCell + "-" + line;
|
||||||
|
})
|
||||||
|
let top = null;
|
||||||
|
let height = null;
|
||||||
|
let parent = null;
|
||||||
|
if (lineIds.length > 0) {
|
||||||
|
//compute the position of the single el (top and bottom and make a div)
|
||||||
|
const el = window.document.getElementById(lineIds[0]);
|
||||||
|
top = el.offsetTop;
|
||||||
|
height = el.offsetHeight;
|
||||||
|
parent = el.parentElement.parentElement;
|
||||||
|
if (lineIds.length > 1) {
|
||||||
|
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
||||||
|
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
||||||
|
height = bottom - top;
|
||||||
|
}
|
||||||
|
if (top !== null && height !== null && parent !== null) {
|
||||||
|
// cook up a div (if necessary) and position it
|
||||||
|
let div = window.document.getElementById("code-annotation-line-highlight");
|
||||||
|
if (div === null) {
|
||||||
|
div = window.document.createElement("div");
|
||||||
|
div.setAttribute("id", "code-annotation-line-highlight");
|
||||||
|
div.style.position = 'absolute';
|
||||||
|
parent.appendChild(div);
|
||||||
|
}
|
||||||
|
div.style.top = top - 2 + "px";
|
||||||
|
div.style.height = height + 4 + "px";
|
||||||
|
div.style.left = 0;
|
||||||
|
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
||||||
|
if (gutterDiv === null) {
|
||||||
|
gutterDiv = window.document.createElement("div");
|
||||||
|
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
||||||
|
gutterDiv.style.position = 'absolute';
|
||||||
|
const codeCell = window.document.getElementById(targetCell);
|
||||||
|
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
||||||
|
gutter.appendChild(gutterDiv);
|
||||||
|
}
|
||||||
|
gutterDiv.style.top = top - 2 + "px";
|
||||||
|
gutterDiv.style.height = height + 4 + "px";
|
||||||
|
}
|
||||||
|
selectedAnnoteEl = annoteEl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const unselectCodeLines = () => {
|
||||||
|
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
||||||
|
elementsIds.forEach((elId) => {
|
||||||
|
const div = window.document.getElementById(elId);
|
||||||
|
if (div) {
|
||||||
|
div.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
selectedAnnoteEl = undefined;
|
||||||
|
};
|
||||||
|
// Handle positioning of the toggle
|
||||||
|
window.addEventListener(
|
||||||
|
"resize",
|
||||||
|
throttle(() => {
|
||||||
|
elRect = undefined;
|
||||||
|
if (selectedAnnoteEl) {
|
||||||
|
selectCodeLines(selectedAnnoteEl);
|
||||||
|
}
|
||||||
|
}, 10)
|
||||||
|
);
|
||||||
|
function throttle(fn, ms) {
|
||||||
|
let throttle = false;
|
||||||
|
let timer;
|
||||||
|
return (...args) => {
|
||||||
|
if(!throttle) { // first call gets through
|
||||||
|
fn.apply(this, args);
|
||||||
|
throttle = true;
|
||||||
|
} else { // all the others get throttled
|
||||||
|
if(timer) clearTimeout(timer); // cancel #2
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fn.apply(this, args);
|
||||||
|
timer = throttle = false;
|
||||||
|
}, ms);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Attach click handler to the DT
|
||||||
|
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
||||||
|
for (const annoteDlNode of annoteDls) {
|
||||||
|
annoteDlNode.addEventListener('click', (event) => {
|
||||||
|
const clickedEl = event.target;
|
||||||
|
if (clickedEl !== selectedAnnoteEl) {
|
||||||
|
unselectCodeLines();
|
||||||
|
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
||||||
|
if (activeEl) {
|
||||||
|
activeEl.classList.remove('code-annotation-active');
|
||||||
|
}
|
||||||
|
selectCodeLines(clickedEl);
|
||||||
|
clickedEl.classList.add('code-annotation-active');
|
||||||
|
} else {
|
||||||
|
// Unselect the line
|
||||||
|
unselectCodeLines();
|
||||||
|
clickedEl.classList.remove('code-annotation-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const findCites = (el) => {
|
||||||
|
const parentEl = el.parentElement;
|
||||||
|
if (parentEl) {
|
||||||
|
const cites = parentEl.dataset.cites;
|
||||||
|
if (cites) {
|
||||||
|
return {
|
||||||
|
el,
|
||||||
|
cites: cites.split(' ')
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return findCites(el.parentElement)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
||||||
|
for (var i=0; i<bibliorefs.length; i++) {
|
||||||
|
const ref = bibliorefs[i];
|
||||||
|
const citeInfo = findCites(ref);
|
||||||
|
if (citeInfo) {
|
||||||
|
tippyHover(citeInfo.el, function() {
|
||||||
|
var popup = window.document.createElement('div');
|
||||||
|
citeInfo.cites.forEach(function(cite) {
|
||||||
|
var citeDiv = window.document.createElement('div');
|
||||||
|
citeDiv.classList.add('hanging-indent');
|
||||||
|
citeDiv.classList.add('csl-entry');
|
||||||
|
var biblioDiv = window.document.getElementById('ref-' + cite);
|
||||||
|
if (biblioDiv) {
|
||||||
|
citeDiv.innerHTML = biblioDiv.innerHTML;
|
||||||
|
}
|
||||||
|
popup.appendChild(citeDiv);
|
||||||
|
});
|
||||||
|
return popup.innerHTML;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</div> <!-- /content -->
|
</div> <!-- /content -->
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+377
-394
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+135
-104
@@ -36,14 +36,11 @@
|
|||||||
--quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
--quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* syntax highlight based on Pandoc's rules */
|
||||||
pre > code.sourceCode > span {
|
pre > code.sourceCode > span {
|
||||||
color: #003B4F;
|
color: #003B4F;
|
||||||
}
|
}
|
||||||
|
|
||||||
code span {
|
|
||||||
color: #003B4F;
|
|
||||||
}
|
|
||||||
|
|
||||||
code.sourceCode > span {
|
code.sourceCode > span {
|
||||||
color: #003B4F;
|
color: #003B4F;
|
||||||
}
|
}
|
||||||
@@ -53,153 +50,187 @@ div.sourceCode pre.sourceCode {
|
|||||||
color: #003B4F;
|
color: #003B4F;
|
||||||
}
|
}
|
||||||
|
|
||||||
code span.ot {
|
/* Normal */
|
||||||
|
code span {
|
||||||
color: #003B4F;
|
color: #003B4F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alert */
|
||||||
|
code span.al {
|
||||||
|
color: #AD0000;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
code span.at {
|
/* Annotation */
|
||||||
color: #657422;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.ss {
|
|
||||||
color: #20794D;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.an {
|
code span.an {
|
||||||
color: #5E5E5E;
|
color: #5E5E5E;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
code span.fu {
|
/* Attribute */
|
||||||
color: #4758AB;
|
code span.at {
|
||||||
|
color: #657422;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
code span.st {
|
/* BaseN */
|
||||||
color: #20794D;
|
code span.bn {
|
||||||
|
color: #AD0000;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BuiltIn */
|
||||||
|
code span.bu {
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ControlFlow */
|
||||||
code span.cf {
|
code span.cf {
|
||||||
color: #003B4F;
|
color: #003B4F;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
code span.op {
|
/* Char */
|
||||||
color: #5E5E5E;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.er {
|
|
||||||
color: #AD0000;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.bn {
|
|
||||||
color: #AD0000;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.al {
|
|
||||||
color: #AD0000;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.va {
|
|
||||||
color: #111111;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.bu {
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.ex {
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.pp {
|
|
||||||
color: #AD0000;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.in {
|
|
||||||
color: #5E5E5E;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.vs {
|
|
||||||
color: #20794D;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.wa {
|
|
||||||
color: #5E5E5E;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.do {
|
|
||||||
color: #5E5E5E;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.im {
|
|
||||||
color: #00769E;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.ch {
|
code span.ch {
|
||||||
color: #20794D;
|
color: #20794D;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
code span.dt {
|
/* Constant */
|
||||||
color: #AD0000;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.fl {
|
|
||||||
color: #AD0000;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.co {
|
|
||||||
color: #5E5E5E;
|
|
||||||
font-style: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.cv {
|
|
||||||
color: #5E5E5E;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
code span.cn {
|
code span.cn {
|
||||||
color: #8f5902;
|
color: #8f5902;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
code span.sc {
|
/* Comment */
|
||||||
|
code span.co {
|
||||||
color: #5E5E5E;
|
color: #5E5E5E;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CommentVar */
|
||||||
|
code span.cv {
|
||||||
|
color: #5E5E5E;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Documentation */
|
||||||
|
code span.do {
|
||||||
|
color: #5E5E5E;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DataType */
|
||||||
|
code span.dt {
|
||||||
|
color: #AD0000;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DecVal */
|
||||||
code span.dv {
|
code span.dv {
|
||||||
color: #AD0000;
|
color: #AD0000;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Error */
|
||||||
|
code span.er {
|
||||||
|
color: #AD0000;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extension */
|
||||||
|
code span.ex {
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Float */
|
||||||
|
code span.fl {
|
||||||
|
color: #AD0000;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function */
|
||||||
|
code span.fu {
|
||||||
|
color: #4758AB;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Import */
|
||||||
|
code span.im {
|
||||||
|
color: #00769E;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Information */
|
||||||
|
code span.in {
|
||||||
|
color: #5E5E5E;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyword */
|
||||||
code span.kw {
|
code span.kw {
|
||||||
color: #003B4F;
|
color: #003B4F;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: inherit;
|
font-style: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Operator */
|
||||||
|
code span.op {
|
||||||
|
color: #5E5E5E;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Other */
|
||||||
|
code span.ot {
|
||||||
|
color: #003B4F;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preprocessor */
|
||||||
|
code span.pp {
|
||||||
|
color: #AD0000;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SpecialChar */
|
||||||
|
code span.sc {
|
||||||
|
color: #5E5E5E;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SpecialString */
|
||||||
|
code span.ss {
|
||||||
|
color: #20794D;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* String */
|
||||||
|
code span.st {
|
||||||
|
color: #20794D;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Variable */
|
||||||
|
code span.va {
|
||||||
|
color: #111111;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* VerbatimString */
|
||||||
|
code span.vs {
|
||||||
|
color: #20794D;
|
||||||
|
font-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Warning */
|
||||||
|
code span.wa {
|
||||||
|
color: #5E5E5E;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.prevent-inlining {
|
.prevent-inlining {
|
||||||
content: "</";
|
content: "</";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*# sourceMappingURL=c9c5d451c23b744f9cb2c98992a0aef2.css.map */
|
/*# sourceMappingURL=d398365ccb532ba00fe56d6aa1025863.css.map */
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import * as tabsets from "./tabsets/tabsets.js";
|
||||||
|
|
||||||
const sectionChanged = new CustomEvent("quarto-sectionChanged", {
|
const sectionChanged = new CustomEvent("quarto-sectionChanged", {
|
||||||
detail: {},
|
detail: {},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
@@ -64,19 +66,41 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior)
|
// dispatch for htmlwidgets
|
||||||
function fireSlideEnter(e) {
|
// they use slideenter event to trigger resize
|
||||||
|
function fireSlideEnter() {
|
||||||
const event = window.document.createEvent("Event");
|
const event = window.document.createEvent("Event");
|
||||||
event.initEvent("slideenter", true, true);
|
event.initEvent("slideenter", true, true);
|
||||||
window.document.dispatchEvent(event);
|
window.document.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]');
|
const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]');
|
||||||
tabs.forEach((tab) => {
|
tabs.forEach((tab) => {
|
||||||
tab.addEventListener("shown.bs.tab", fireSlideEnter);
|
tab.addEventListener("shown.bs.tab", fireSlideEnter);
|
||||||
});
|
});
|
||||||
|
|
||||||
// fire slideEnter for tabby tab activations (for htmlwidget resize behavior)
|
// dispatch for shiny
|
||||||
document.addEventListener("tabby", fireSlideEnter, false);
|
// they use BS shown and hidden events to trigger rendering
|
||||||
|
function distpatchShinyEvents(previous, current) {
|
||||||
|
if (window.jQuery) {
|
||||||
|
if (previous) {
|
||||||
|
window.jQuery(previous).trigger("hidden");
|
||||||
|
}
|
||||||
|
if (current) {
|
||||||
|
window.jQuery(current).trigger("shown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tabby.js listener: Trigger event for htmlwidget and shiny
|
||||||
|
document.addEventListener(
|
||||||
|
"tabby",
|
||||||
|
function (event) {
|
||||||
|
fireSlideEnter();
|
||||||
|
distpatchShinyEvents(event.detail.previousTab, event.detail.tab);
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
// Track scrolling and mark TOC links as active
|
// Track scrolling and mark TOC links as active
|
||||||
// get table of contents and sidebar (bail if we don't have at least one)
|
// get table of contents and sidebar (bail if we don't have at least one)
|
||||||
@@ -236,9 +260,10 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
|
|||||||
for (const listingPath of listingPaths) {
|
for (const listingPath of listingPaths) {
|
||||||
const pathWithoutLeadingSlash = listingPath.listing.substring(1);
|
const pathWithoutLeadingSlash = listingPath.listing.substring(1);
|
||||||
for (const item of listingPath.items) {
|
for (const item of listingPath.items) {
|
||||||
|
const encodedItem = encodeURI(item);
|
||||||
if (
|
if (
|
||||||
item === currentPagePath ||
|
encodedItem === currentPagePath ||
|
||||||
item === currentPagePath + "index.html"
|
encodedItem === currentPagePath + "index.html"
|
||||||
) {
|
) {
|
||||||
// Resolve this path against the offset to be sure
|
// Resolve this path against the offset to be sure
|
||||||
// we already are using the correct path to the listing
|
// we already are using the correct path to the listing
|
||||||
@@ -740,7 +765,7 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
|
|||||||
|
|
||||||
// See if there is an active child to this element
|
// See if there is an active child to this element
|
||||||
let hasActiveChild = false;
|
let hasActiveChild = false;
|
||||||
for (child of el.children) {
|
for (const child of el.children) {
|
||||||
hasActiveChild = walk(child, depth) || hasActiveChild;
|
hasActiveChild = walk(child, depth) || hasActiveChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,98 +825,7 @@ window.document.addEventListener("DOMContentLoaded", function (_event) {
|
|||||||
highlightReaderToggle(isReaderMode());
|
highlightReaderToggle(isReaderMode());
|
||||||
});
|
});
|
||||||
|
|
||||||
// grouped tabsets
|
tabsets.init();
|
||||||
window.addEventListener("pageshow", (_event) => {
|
|
||||||
function getTabSettings() {
|
|
||||||
const data = localStorage.getItem("quarto-persistent-tabsets-data");
|
|
||||||
if (!data) {
|
|
||||||
localStorage.setItem("quarto-persistent-tabsets-data", "{}");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (data) {
|
|
||||||
return JSON.parse(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTabSettings(data) {
|
|
||||||
localStorage.setItem(
|
|
||||||
"quarto-persistent-tabsets-data",
|
|
||||||
JSON.stringify(data)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTabState(groupName, groupValue) {
|
|
||||||
const data = getTabSettings();
|
|
||||||
data[groupName] = groupValue;
|
|
||||||
setTabSettings(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleTab(tab, active) {
|
|
||||||
const tabPanelId = tab.getAttribute("aria-controls");
|
|
||||||
const tabPanel = document.getElementById(tabPanelId);
|
|
||||||
if (active) {
|
|
||||||
tab.classList.add("active");
|
|
||||||
tabPanel.classList.add("active");
|
|
||||||
} else {
|
|
||||||
tab.classList.remove("active");
|
|
||||||
tabPanel.classList.remove("active");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleAll(selectedGroup, selectorsToSync) {
|
|
||||||
for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) {
|
|
||||||
const active = selectedGroup === thisGroup;
|
|
||||||
for (const tab of tabs) {
|
|
||||||
toggleTab(tab, active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findSelectorsToSyncByLanguage() {
|
|
||||||
const result = {};
|
|
||||||
const tabs = Array.from(
|
|
||||||
document.querySelectorAll(`div[data-group] a[id^='tabset-']`)
|
|
||||||
);
|
|
||||||
for (const item of tabs) {
|
|
||||||
const div = item.parentElement.parentElement.parentElement;
|
|
||||||
const group = div.getAttribute("data-group");
|
|
||||||
if (!result[group]) {
|
|
||||||
result[group] = {};
|
|
||||||
}
|
|
||||||
const selectorsToSync = result[group];
|
|
||||||
const value = item.innerHTML;
|
|
||||||
if (!selectorsToSync[value]) {
|
|
||||||
selectorsToSync[value] = [];
|
|
||||||
}
|
|
||||||
selectorsToSync[value].push(item);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupSelectorSync() {
|
|
||||||
const selectorsToSync = findSelectorsToSyncByLanguage();
|
|
||||||
Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => {
|
|
||||||
Object.entries(tabSetsByValue).forEach(([value, items]) => {
|
|
||||||
items.forEach((item) => {
|
|
||||||
item.addEventListener("click", (_event) => {
|
|
||||||
setTabState(group, value);
|
|
||||||
toggleAll(value, selectorsToSync[group]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return selectorsToSync;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectorsToSync = setupSelectorSync();
|
|
||||||
for (const [group, selectedName] of Object.entries(getTabSettings())) {
|
|
||||||
const selectors = selectorsToSync[group];
|
|
||||||
// it's possible that stale state gives us empty selections, so we explicitly check here.
|
|
||||||
if (selectors) {
|
|
||||||
toggleAll(selectedName, selectors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function throttle(func, wait) {
|
function throttle(func, wait) {
|
||||||
let waiting = false;
|
let waiting = false;
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
// grouped tabsets
|
||||||
|
|
||||||
|
export function init() {
|
||||||
|
window.addEventListener("pageshow", (_event) => {
|
||||||
|
function getTabSettings() {
|
||||||
|
const data = localStorage.getItem("quarto-persistent-tabsets-data");
|
||||||
|
if (!data) {
|
||||||
|
localStorage.setItem("quarto-persistent-tabsets-data", "{}");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
return JSON.parse(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTabSettings(data) {
|
||||||
|
localStorage.setItem(
|
||||||
|
"quarto-persistent-tabsets-data",
|
||||||
|
JSON.stringify(data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTabState(groupName, groupValue) {
|
||||||
|
const data = getTabSettings();
|
||||||
|
data[groupName] = groupValue;
|
||||||
|
setTabSettings(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleTab(tab, active) {
|
||||||
|
const tabPanelId = tab.getAttribute("aria-controls");
|
||||||
|
const tabPanel = document.getElementById(tabPanelId);
|
||||||
|
if (active) {
|
||||||
|
tab.classList.add("active");
|
||||||
|
tabPanel.classList.add("active");
|
||||||
|
} else {
|
||||||
|
tab.classList.remove("active");
|
||||||
|
tabPanel.classList.remove("active");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleAll(selectedGroup, selectorsToSync) {
|
||||||
|
for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) {
|
||||||
|
const active = selectedGroup === thisGroup;
|
||||||
|
for (const tab of tabs) {
|
||||||
|
toggleTab(tab, active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findSelectorsToSyncByLanguage() {
|
||||||
|
const result = {};
|
||||||
|
const tabs = Array.from(
|
||||||
|
document.querySelectorAll(`div[data-group] a[id^='tabset-']`)
|
||||||
|
);
|
||||||
|
for (const item of tabs) {
|
||||||
|
const div = item.parentElement.parentElement.parentElement;
|
||||||
|
const group = div.getAttribute("data-group");
|
||||||
|
if (!result[group]) {
|
||||||
|
result[group] = {};
|
||||||
|
}
|
||||||
|
const selectorsToSync = result[group];
|
||||||
|
const value = item.innerHTML;
|
||||||
|
if (!selectorsToSync[value]) {
|
||||||
|
selectorsToSync[value] = [];
|
||||||
|
}
|
||||||
|
selectorsToSync[value].push(item);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupSelectorSync() {
|
||||||
|
const selectorsToSync = findSelectorsToSyncByLanguage();
|
||||||
|
Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => {
|
||||||
|
Object.entries(tabSetsByValue).forEach(([value, items]) => {
|
||||||
|
items.forEach((item) => {
|
||||||
|
item.addEventListener("click", (_event) => {
|
||||||
|
setTabState(group, value);
|
||||||
|
toggleAll(value, selectorsToSync[group]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return selectorsToSync;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectorsToSync = setupSelectorSync();
|
||||||
|
for (const [group, selectedName] of Object.entries(getTabSettings())) {
|
||||||
|
const selectors = selectorsToSync[group];
|
||||||
|
// it's possible that stale state gives us empty selections, so we explicitly check here.
|
||||||
|
if (selectors) {
|
||||||
|
toggleAll(selectedName, selectors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user