准备第7次课
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
title: Simplemenu
|
||||
author: Martijn De Jongh (Martino)
|
||||
version: 2.0.0
|
||||
quarto-required: ">=1.2.198"
|
||||
contributes:
|
||||
revealjs-plugins:
|
||||
-
|
||||
name: Simplemenu
|
||||
script: simplemenu.js
|
||||
stylesheet: simplemenu.css
|
||||
config:
|
||||
simplemenu:
|
||||
menubarclass: "menubar"
|
||||
menuclass: "menu"
|
||||
activeclass: "active"
|
||||
activeelement: "li"
|
||||
flat: false
|
||||
barhtml:
|
||||
header: ""
|
||||
footer: ""
|
||||
scale: 0.67
|
||||
@@ -0,0 +1,190 @@
|
||||
.menubar {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-transition: -webkit-transform 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
transition: -webkit-transform 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
-o-transition: transform 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
transition: transform 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
transition: transform 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985), -webkit-transform 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
-webkit-transform: translateY(-100%);
|
||||
-ms-transform: translateY(-100%);
|
||||
transform: translateY(-100%);
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
font-size: clamp(16px, var(--r-main-font-size) * var(--simplemenu-scale, 0.75), 80px);
|
||||
line-height: 1;
|
||||
}
|
||||
.menubar * {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html:not(.print-pdf) body:not(.hide-menubar) .reveal.ready:not(.hide-menubar) .menubar {
|
||||
-webkit-transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
body.hide-menubar .reveal.ready .menubar a {
|
||||
-webkit-transition: opacity 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
-o-transition: opacity 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
transition: opacity 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
}
|
||||
.menubar.bottom {
|
||||
-webkit-transform: translateY(100%);
|
||||
-ms-transform: translateY(100%);
|
||||
transform: translateY(100%);
|
||||
}
|
||||
.menubar:before, .menubar:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-bottom: 1px solid currentColor;
|
||||
opacity: 0.3;
|
||||
}
|
||||
.menubar:before {
|
||||
top: 0;
|
||||
}
|
||||
.menubar:after {
|
||||
bottom: 0;
|
||||
}
|
||||
.menubar:before {
|
||||
opacity: 0;
|
||||
}
|
||||
.menubar.bottom:after {
|
||||
opacity: 0;
|
||||
}
|
||||
.menubar.bottom:before {
|
||||
opacity: 0.3;
|
||||
}
|
||||
.print-pdf .pdf-page:not(.hide-menubar) .menubar {
|
||||
-webkit-transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
.menubar a {
|
||||
-webkit-transition: opacity 0.2s ease-in-out;
|
||||
-o-transition: opacity 0.2s ease-in-out;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
padding: 0.4em 0;
|
||||
}
|
||||
.menubar > ul {
|
||||
-webkit-transition: opacity 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
-o-transition: opacity 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
transition: opacity 0.8s cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
gap: 1.5em;
|
||||
}
|
||||
.menubar > ul li {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.menubar > ul li:before {
|
||||
display: none;
|
||||
}
|
||||
.menubar > ul li + li {
|
||||
margin: 0;
|
||||
}
|
||||
.menubar > ul a {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0;
|
||||
flex: 0;
|
||||
white-space: nowrap;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
opacity: 0.33;
|
||||
padding: 0.5em;
|
||||
color: currentColor;
|
||||
}
|
||||
.menubar > ul a:hover {
|
||||
color: currentColor;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.menubar > ul li a.active, .menubar > ul li.active a {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hide-menu .menu, .hide-menu .menu, [data-state=hide-menu] .menu {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.reveal .slide-number, .menubar .slide-number {
|
||||
background: none;
|
||||
font-family: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
.reveal .slide-number a, .menubar .slide-number a {
|
||||
padding: 0;
|
||||
opacity: 0.33;
|
||||
color: currentColor;
|
||||
}
|
||||
.reveal .slide-number a:hover, .menubar .slide-number a:hover {
|
||||
color: currentColor;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.menubar .slide-number {
|
||||
display: -webkit-box !important;
|
||||
display: -ms-flexbox !important;
|
||||
display: flex !important;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
font-size: 0.75em;
|
||||
height: 100%;
|
||||
right: 0;
|
||||
bottom: auto;
|
||||
z-index: 0;
|
||||
padding: 0;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.slides ~ .menubar, .menubar.bottom {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.slides ~ .menubar ~ .controls {
|
||||
margin-bottom: clamp(16px, 2.5 * var(--r-main-font-size) * var(--simplemenu-scale, 0.75), 100px);
|
||||
}
|
||||
@@ -0,0 +1,644 @@
|
||||
|
||||
/*****************************************************************
|
||||
* @author: Martijn De Jongh (Martino), martijn.de.jongh@gmail.com
|
||||
* https://github.com/Martinomagnifico
|
||||
*
|
||||
* Simplemenu.js for Reveal.js
|
||||
* Version 2.0.1
|
||||
*
|
||||
* @license
|
||||
* MIT licensed
|
||||
*
|
||||
* Thanks to:
|
||||
* - Hakim El Hattab, Reveal.js
|
||||
******************************************************************/
|
||||
|
||||
|
||||
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Simplemenu = factory());
|
||||
})(this, (function () { 'use strict';
|
||||
|
||||
const Plugin = () => {
|
||||
let options = {};
|
||||
const vars = {};
|
||||
const sections = {};
|
||||
const mainArray = [];
|
||||
let autoListItems = [];
|
||||
let manualListItems = [];
|
||||
|
||||
const debugLog = text => {
|
||||
if (options.debug) console.log(text);
|
||||
};
|
||||
|
||||
const isObject = item => {
|
||||
return item && typeof item === 'object' && !Array.isArray(item);
|
||||
};
|
||||
|
||||
const mergeDeep = function (target) {
|
||||
for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
sources[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
if (!sources.length) return target;
|
||||
const source = sources.shift();
|
||||
|
||||
if (isObject(target) && isObject(source)) {
|
||||
for (const key in source) {
|
||||
if (isObject(source[key])) {
|
||||
if (!target[key]) Object.assign(target, {
|
||||
[key]: {}
|
||||
});
|
||||
mergeDeep(target[key], source[key]);
|
||||
} else {
|
||||
Object.assign(target, {
|
||||
[key]: source[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mergeDeep(target, ...sources);
|
||||
};
|
||||
|
||||
const selectionArray = (container, selectors) => {
|
||||
let selections = container.querySelectorAll(selectors);
|
||||
let selectionarray = Array.prototype.slice.call(selections);
|
||||
return selectionarray;
|
||||
};
|
||||
|
||||
const pluginPath = filename => {
|
||||
let path;
|
||||
let pluginScript = document.querySelector(`script[src$="${filename}"]`);
|
||||
|
||||
if (pluginScript) {
|
||||
path = pluginScript.getAttribute("src").slice(0, -1 * filename.length);
|
||||
} else {
|
||||
path = (typeof document === 'undefined' && typeof location === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : typeof document === 'undefined' ? location.href : (document.currentScript && document.currentScript.src || new URL('simplemenu.js', document.baseURI).href)).slice(0, (typeof document === 'undefined' && typeof location === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : typeof document === 'undefined' ? location.href : (document.currentScript && document.currentScript.src || new URL('simplemenu.js', document.baseURI).href)).lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
const isBefore = (a, b) => {
|
||||
var all = document.getElementsByTagName('*');
|
||||
|
||||
for (var i = 0; i < all.length; ++i) {
|
||||
if (all[i] === a) return true;else if (all[i] === b) return false;
|
||||
}
|
||||
};
|
||||
|
||||
const isStack = section => {
|
||||
let isStack = false;
|
||||
|
||||
for (let i = 0; i < section.childNodes.length; i++) {
|
||||
if (section.childNodes[i].tagName == "SECTION") {
|
||||
isStack = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isStack;
|
||||
};
|
||||
|
||||
const createNode = thehtml => {
|
||||
const fragment = document.createRange().createContextualFragment(thehtml);
|
||||
return fragment.firstElementChild;
|
||||
};
|
||||
|
||||
const loadStyle = (url, type, callback) => {
|
||||
let head = document.querySelector('head');
|
||||
let style = document.createElement('link');
|
||||
style.rel = 'stylesheet';
|
||||
style.href = url;
|
||||
|
||||
let finish = () => {
|
||||
if (typeof callback === 'function') {
|
||||
callback.call();
|
||||
callback = null;
|
||||
}
|
||||
};
|
||||
|
||||
style.onload = finish;
|
||||
|
||||
style.onreadystatechange = function () {
|
||||
if (this.readyState === 'loaded') {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
head.appendChild(style);
|
||||
};
|
||||
|
||||
const checkOccurrence = (array, element) => {
|
||||
let counter = 0;
|
||||
|
||||
for (let i = 0; i <= array.length; i++) {
|
||||
if (array[i] == element) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
};
|
||||
|
||||
const menuArray = () => {
|
||||
const matchString = vars.matchString;
|
||||
let menulist = selectionArray(vars.viewport, `.${options.menuclass}`) ? selectionArray(vars.viewport, `.${options.menuclass}`) : [];
|
||||
let automenus = [];
|
||||
let manualmenus = [];
|
||||
|
||||
if (menulist.length) {
|
||||
menulist.forEach(menu => {
|
||||
if (menu.getElementsByTagName('li').length < 1) {
|
||||
menu.setAttribute('data-simplemenu-auto', '');
|
||||
automenus.push(menu);
|
||||
} else {
|
||||
if (options.selectby == "data-name" || options.selectby == "name") {
|
||||
let existingListItems = selectionArray(menu, `.${options.menuclass} ${options.activeelement}`);
|
||||
existingListItems.forEach(listItem => {
|
||||
if (!listItem.dataset[matchString]) {
|
||||
let content = listItem.textContent || listItem.querySelector('a').textContent;
|
||||
listItem.setAttribute(`data-${matchString}`, content);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
manualmenus.push(menu);
|
||||
}
|
||||
});
|
||||
return {
|
||||
automenus: automenus,
|
||||
manualmenus: manualmenus
|
||||
};
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const setScale = revealScale => {
|
||||
let totalScale = revealScale * vars.userScale;
|
||||
vars.viewport.style.setProperty('--simplemenu-scale', totalScale.toFixed(3));
|
||||
};
|
||||
|
||||
const moveRevealUI = (curUiEl, newUiEl) => {
|
||||
let newUiElClassList = newUiEl.classList;
|
||||
newUiEl.parentNode.replaceChild(curUiEl, newUiEl);
|
||||
curUiEl.classList = newUiElClassList;
|
||||
};
|
||||
|
||||
const getRevealUI = () => {
|
||||
let revealUIs = ['controls', 'slide-number'];
|
||||
revealUIs.forEach(uielement => {
|
||||
let curUiEl = vars.deck.getRevealElement().querySelector(`.reveal > .${uielement}`);
|
||||
let newUiEl = vars.deck.getRevealElement().querySelector(`.reveal > * .${uielement}`);
|
||||
|
||||
if (curUiEl && newUiEl) {
|
||||
moveRevealUI(curUiEl, newUiEl);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function copyDataAttributes(source, target) {
|
||||
[...source.attributes].filter(attr => attr.nodeName.indexOf('data') > -1).forEach(attr => {
|
||||
target.setAttribute(attr.nodeName, attr.nodeValue);
|
||||
});
|
||||
}
|
||||
|
||||
const prepareSlides = () => {
|
||||
debugLog("Preparing slides");
|
||||
sections.all = selectionArray(vars.viewport, "section");
|
||||
sections.all.forEach(section => {
|
||||
// In Markdown environments, setting a data-name of a stack is not directly possible.
|
||||
// Satting a data-stack-name on the first child solves this.
|
||||
if (!section.parentNode.dataset.name && section.dataset && section.dataset.stackName) {
|
||||
section.parentNode.dataset.name = section.dataset.stackName;
|
||||
} // If a section has a data-sm='none', it will also remove the data-name.
|
||||
|
||||
|
||||
if (section.dataset && section.dataset[vars.matchString] && section.dataset[vars.matchString] == "false" && section.dataset.name) {
|
||||
delete section.dataset.name;
|
||||
}
|
||||
}); // Get all of the kinds of sections
|
||||
|
||||
sections.top = sections.all.filter(section => section.parentNode.classList.contains('slides') && !(section.dataset[vars.matchString] && section.dataset[vars.matchString] == "false"));
|
||||
sections.named = sections.top.filter(section => section.dataset.name || section.getAttribute('name'));
|
||||
sections.namedvisible = sections.named.filter(section => section.dataset.visibility != "hidden"); // Go through all the named sections
|
||||
|
||||
let namedsectionMatches = [];
|
||||
sections.named.forEach(namedsection => {
|
||||
// The 'name' attribute is also allowed.
|
||||
let matchName = namedsection.dataset.name || namedsection.getAttribute('name'); // Named sections can have the same name, but should then be differentiated.
|
||||
|
||||
namedsectionMatches.push(matchName);
|
||||
let dupsBefore = matchName && checkOccurrence(namedsectionMatches, matchName) > 1 ? `-${checkOccurrence(namedsectionMatches, matchName)}` : null;
|
||||
let match = dupsBefore ? matchName + dupsBefore : matchName; // We set the name of the match as a data-attribute
|
||||
|
||||
namedsection.setAttribute(`data-${vars.matchString}`, match); // If the (named) section is not a stack and does not have an ID, we need to give it one.
|
||||
|
||||
if (!isStack(namedsection) && !namedsection.id) {
|
||||
// Note: Quarto will already have assigned an ID, but it may also have been done manually.
|
||||
namedsection.id = match.toLowerCase().replace(/\W/g, '');
|
||||
} else if (isStack(namedsection)) {
|
||||
// Find the first (visible) section inside a stack.
|
||||
let allsects = selectionArray(namedsection, `section`);
|
||||
let allVisibleSects = allsects.filter(section => section.dataset.visibility != "hidden");
|
||||
let firstChildSection = allVisibleSects[0];
|
||||
|
||||
if (firstChildSection && !firstChildSection.id) {
|
||||
firstChildSection.id = match.toLowerCase().replace(/\W/g, '');
|
||||
|
||||
if (namedsection.id == firstChildSection.id) {
|
||||
namedsection.removeAttribute('id');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let currentMatch = null;
|
||||
let currentid = null; // Get all the sections that are actually slides
|
||||
|
||||
sections.regular = sections.all.filter(section => !isStack(section) && section.dataset.visibility != "hidden"); // Go through all the sections
|
||||
|
||||
sections.regular.forEach((section, i) => {
|
||||
// Filling an array with the needed comparison information
|
||||
let isChildSection = isStack(section.parentNode) && section.parentNode.tagName == "SECTION";
|
||||
let theSection = isChildSection ? section.parentNode : section;
|
||||
let dataname = theSection.dataset.name;
|
||||
let name = theSection.getAttribute(`name`);
|
||||
let dataintl = theSection.getAttribute(vars.langattribute) ? theSection.getAttribute(vars.langattribute) : null;
|
||||
let parentid = section.parentNode.id ? section.parentNode.id : null;
|
||||
let id = section.id ? section.id : isChildSection ? parentid : null;
|
||||
let match = theSection.dataset[vars.matchString];
|
||||
|
||||
if (match) {
|
||||
currentMatch = match;
|
||||
}
|
||||
|
||||
if (id || match == "false") {
|
||||
currentid = i;
|
||||
}
|
||||
|
||||
if (options.flat) {
|
||||
if (match != "false") {
|
||||
match = currentMatch;
|
||||
}
|
||||
}
|
||||
|
||||
if (match == "false") {
|
||||
match = null;
|
||||
}
|
||||
|
||||
if (dataname == "false") {
|
||||
dataname = null;
|
||||
}
|
||||
|
||||
let sectionObject = {
|
||||
index: i,
|
||||
...(section && {
|
||||
section
|
||||
}),
|
||||
...(dataname && {
|
||||
dataname
|
||||
}),
|
||||
...(name && {
|
||||
name
|
||||
}),
|
||||
...(id && {
|
||||
id
|
||||
}),
|
||||
...(match && {
|
||||
match
|
||||
}),
|
||||
...(currentid && {
|
||||
currentid
|
||||
}),
|
||||
...(dataintl && {
|
||||
dataintl
|
||||
})
|
||||
};
|
||||
mainArray.push(sectionObject);
|
||||
});
|
||||
};
|
||||
|
||||
const prepareMenubars = () => {
|
||||
debugLog("Preparing menubars");
|
||||
let menubars = selectionArray(vars.viewport, `.${options.menubarclass}`) ? selectionArray(vars.viewport, `.${options.menubarclass}`) : [];
|
||||
|
||||
if (options.barhtml.header) {
|
||||
// Generate header menubar
|
||||
let bar = createNode(options.barhtml.header);
|
||||
menubars.push(bar);
|
||||
vars.slides.before(bar);
|
||||
}
|
||||
|
||||
if (options.barhtml.footer) {
|
||||
// Generate footer menubar
|
||||
let bar = createNode(options.barhtml.footer);
|
||||
menubars.push(bar);
|
||||
vars.slides.after(bar);
|
||||
}
|
||||
|
||||
if (menubars.length) {
|
||||
// If menubar (pre-existing or just added):
|
||||
setScale(vars.deck.getScale());
|
||||
menubars.forEach((menubar, i) => {
|
||||
let barLocation = isBefore(menubar, vars.slides) ? "top" : "bottom";
|
||||
menubar.classList.add(barLocation);
|
||||
|
||||
if (!menubar.id) {
|
||||
menubar.id = `${options.menubarclass}${barLocation}`;
|
||||
}
|
||||
|
||||
menubar.classList.add("ready");
|
||||
});
|
||||
vars.menubars = menubars;
|
||||
} else {
|
||||
console.log("There are no menubars. You can still use Simplemenu to populate empty menus like in an Agenda or Table Of Contents.");
|
||||
}
|
||||
};
|
||||
|
||||
const prepareMenus = () => {
|
||||
debugLog("Preparing menus");
|
||||
let menus = menuArray();
|
||||
|
||||
if (!menus || menus && !menus.automenus) {
|
||||
console.log("There are no menus. Please add one or more menus manually or through the 'barhtml' option.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (menus.automenus.length >= 1 && sections.namedvisible.length >= 1) {
|
||||
// There are empty menus. Autofill them.
|
||||
let idArray = [];
|
||||
const autoMenuLinks = sections.namedvisible.map(section => {
|
||||
let match = section.dataset[vars.matchString];
|
||||
let name = section.dataset.name || section.getAttribute(`name`) || section.id;
|
||||
let id = section.id || name.toLowerCase().replace(/\W/g, '');
|
||||
idArray.push(id);
|
||||
|
||||
if (vars.quarto) {
|
||||
id = mainArray.find(item => item.match === match).id;
|
||||
}
|
||||
|
||||
let duplicatesBefore = checkOccurrence(idArray, id) > 1 ? `-${checkOccurrence(idArray, id)}` : '';
|
||||
let href = vars.quarto ? id : id + duplicatesBefore;
|
||||
let smmatchString = ` data-${vars.matchString}="${match}"`;
|
||||
let nameString = section.getAttribute(`name`) ? ` name="${section.getAttribute(`name`)}"` : '';
|
||||
let intlString = section.getAttribute(vars.langattribute) ? ` ${vars.langattribute}="${section.getAttribute(vars.langattribute)}"` : '';
|
||||
return `<li><a href="#/${href}"${intlString}${nameString}${smmatchString}>${name}</a></li>`;
|
||||
}).reduce((combinedHTML, itemHTML) => {
|
||||
let orderedHTML = vars.rtl ? itemHTML + combinedHTML : combinedHTML + itemHTML;
|
||||
return orderedHTML;
|
||||
});
|
||||
menus.automenus.forEach(automenu => {
|
||||
automenu.innerHTML = autoMenuLinks;
|
||||
});
|
||||
autoListItems = menus.automenus.map(menu => Array.from(menu.querySelectorAll(options.activeelement))).flat();
|
||||
}
|
||||
|
||||
if (menus.manualmenus.length >= 1) {
|
||||
// There are pre-existing menus. Fix link to ID if needed.
|
||||
// Only get the listitems
|
||||
manualListItems = menus.manualmenus.map(menu => Array.from(menu.querySelectorAll(options.activeelement))).flat();
|
||||
manualListItems.forEach(listItem => {
|
||||
// Get the anchorlinks
|
||||
let linker = listItem.tagName == "a" ? listItem : listItem.querySelector('a');
|
||||
let linkhref = linker.getAttribute('href');
|
||||
|
||||
if (linkhref === "#") {
|
||||
let newLink = listItem.dataset[vars.matchString].toLowerCase().replace(/\W/g, '');
|
||||
linker.href = `#/${newLink}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const preparePrint = () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const hasPrintParam = urlParams.has('print-pdf');
|
||||
|
||||
if (hasPrintParam) {
|
||||
mainArray.forEach(item => {
|
||||
let printSection = item.section;
|
||||
let datainfo = document.createElement("div");
|
||||
datainfo.classList.add("datainfo");
|
||||
copyDataAttributes(printSection, datainfo);
|
||||
let moreData = ['match', 'name', 'dataname', 'currentid', 'id', 'dataintl'];
|
||||
moreData.forEach(moreDataItem => {
|
||||
if (item[moreDataItem]) {
|
||||
datainfo.dataset[moreDataItem] = item[moreDataItem];
|
||||
}
|
||||
});
|
||||
printSection.appendChild(datainfo);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const prepare = resolve => {
|
||||
prepareSlides();
|
||||
prepareMenubars();
|
||||
prepareMenus();
|
||||
preparePrint();
|
||||
return setTimeout(resolve, 0);
|
||||
};
|
||||
|
||||
const compare = (listItem, section) => {
|
||||
let menukind = listItem.parentNode.hasAttribute('data-simplemenu-auto') ? "auto" : "manual";
|
||||
let sectionmatch = section.match ? section.match : null;
|
||||
|
||||
if (menukind == "manual") {
|
||||
if (options.selectby == "id") {
|
||||
sectionmatch = section.id ? section.id : section.currentid ? mainArray[section.currentid].id : null;
|
||||
} else if (options.selectby == "name") {
|
||||
sectionmatch = section.name;
|
||||
} else {
|
||||
sectionmatch = section.dataname;
|
||||
}
|
||||
}
|
||||
|
||||
if (sectionmatch) {
|
||||
let menumatch = listItem.dataset[vars.matchString] || listItem.querySelector('a').dataset[vars.matchString];
|
||||
|
||||
if (options.selectby == "id" && menukind == "manual") {
|
||||
let href = listItem.href || listItem.querySelector('a').href;
|
||||
let lastHref = href ? href.substring(href.lastIndexOf("/") + 1) : '';
|
||||
menumatch = lastHref;
|
||||
}
|
||||
|
||||
if (options.selectby == "data-name" && menukind == "manual") {
|
||||
sectionmatch = section.dataname ? section.dataname : null;
|
||||
}
|
||||
|
||||
if (menumatch && menumatch == sectionmatch) {
|
||||
listItem.classList.add(options.activeclass);
|
||||
} else {
|
||||
listItem.classList.remove(options.activeclass);
|
||||
}
|
||||
} else {
|
||||
listItem.classList.remove(options.activeclass);
|
||||
}
|
||||
};
|
||||
|
||||
const checkSlidesNormal = event => {
|
||||
const index = sections.regular.indexOf(event.currentSlide);
|
||||
let section = mainArray[index];
|
||||
autoListItems.filter(listItem => {
|
||||
compare(listItem, section);
|
||||
});
|
||||
manualListItems.filter(listItem => {
|
||||
compare(listItem, section);
|
||||
});
|
||||
};
|
||||
|
||||
const checkSlidesPDF = event => {
|
||||
let pdfPages = selectionArray(vars.viewport, '.slides .pdf-page'); // Check if any menubar has a slide number
|
||||
|
||||
let anyMenubarHasSlidenumber = false;
|
||||
|
||||
if (vars.menubars) {
|
||||
vars.menubars.forEach(menubar => {
|
||||
anyMenubarHasSlidenumber = !!menubar.getElementsByClassName("slide-number");
|
||||
});
|
||||
}
|
||||
|
||||
pdfPages.forEach(pdfPage => {
|
||||
// The original section has gone, so we rebuild it with the saved data-attributes
|
||||
let datainfo = pdfPage.getElementsByClassName("datainfo")[0];
|
||||
let section = {};
|
||||
section.name = datainfo.dataset.name;
|
||||
section.dataname = datainfo.dataset.dataname;
|
||||
section.currentid = datainfo.dataset.currentid;
|
||||
section.match = datainfo.dataset.match;
|
||||
section.id = datainfo.dataset.id;
|
||||
|
||||
if (datainfo.dataset.state) {
|
||||
let newClasses = datainfo.dataset.state.split(" ");
|
||||
newClasses.forEach(newClass => {
|
||||
pdfPage.classList.add(newClass);
|
||||
let vp = vars.deck.getRevealElement().closest(".reveal-viewport");
|
||||
vp.classList.remove(newClass);
|
||||
});
|
||||
} // If any menubar has a slide number, turn the original one on this slide off
|
||||
|
||||
|
||||
if (anyMenubarHasSlidenumber && pdfPage.getElementsByClassName("slide-number").length > 0) {
|
||||
pdfPage.getElementsByClassName("slide-number")[0].style.display = "none";
|
||||
}
|
||||
|
||||
if (vars.menubars) {
|
||||
vars.menubars.forEach(menubar => {
|
||||
let bar = menubar.cloneNode(true);
|
||||
pdfPage.appendChild(bar);
|
||||
let listItems = selectionArray(bar, `.${options.menuclass} ${options.activeelement}`);
|
||||
listItems.forEach(listItem => {
|
||||
compare(listItem, section);
|
||||
}); // If there is a slidenumber in the menu,
|
||||
|
||||
let newSN = pdfPage.querySelector(`.${options.menubarclass} .slide-number`);
|
||||
let oldSN = pdfPage.querySelector(`:scope > .slide-number`);
|
||||
|
||||
if (newSN && oldSN) {
|
||||
// ...then fill it with the current (total) slidenumber.
|
||||
newSN.textContent = oldSN.textContent;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (vars.menubars) {
|
||||
vars.menubars.forEach(menubar => {
|
||||
menubar.parentNode.removeChild(menubar);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const chapterize = event => {
|
||||
if (event && event.type == "ready") {
|
||||
debugLog(mainArray);
|
||||
getRevealUI();
|
||||
}
|
||||
|
||||
if (event && (event.type == "ready" || event.type == "slidechanged")) {
|
||||
checkSlidesNormal(event);
|
||||
}
|
||||
|
||||
if (event && event.type == "pdf-ready") {
|
||||
checkSlidesPDF();
|
||||
}
|
||||
};
|
||||
|
||||
const simpleMenu = (deck, options, es5Filename) => {
|
||||
deck.configure({
|
||||
hash: true
|
||||
});
|
||||
vars.deck = deck;
|
||||
vars.viewport = deck.getRevealElement().tagName == "BODY" ? document : deck.getRevealElement();
|
||||
vars.slides = deck.getSlidesElement();
|
||||
vars.langattribute = deck.getConfig().internation ? deck.getConfig().internation.langattribute ? deck.getConfig().internation.langattribute : "data-i18n" : false;
|
||||
vars.rtl = deck.getConfig().rtl;
|
||||
vars.quarto = document.querySelector('[name=generator]') && document.querySelector('[name=generator]').content.includes("quarto") ? true : false;
|
||||
vars.matchString = "sm";
|
||||
vars.userScale = options.scale;
|
||||
deck.addEventListener('ready', chapterize, false);
|
||||
deck.addEventListener('slidechanged', chapterize, false);
|
||||
deck.addEventListener('pdf-ready', chapterize, false);
|
||||
deck.addEventListener('resize', _ref => {
|
||||
let {
|
||||
scale
|
||||
} = _ref;
|
||||
return setScale(scale);
|
||||
}, false);
|
||||
const SimplemenuStylePath = options.csspath ? options.csspath : `${pluginPath(es5Filename)}simplemenu.css` || 'plugin/simplemenu/simplemenu.css';
|
||||
return new Promise(resolve => {
|
||||
if (options.csspath === false) {
|
||||
return prepare(resolve);
|
||||
} else {
|
||||
loadStyle(SimplemenuStylePath, 'stylesheet', async () => prepare(resolve));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const init = deck => {
|
||||
let defaultOptions = {
|
||||
menubarclass: 'menubar',
|
||||
menuclass: 'menu',
|
||||
activeclass: 'active',
|
||||
activeelement: 'li',
|
||||
selectby: 'id',
|
||||
barhtml: {
|
||||
header: '',
|
||||
footer: ''
|
||||
},
|
||||
flat: false,
|
||||
scale: 0.67,
|
||||
csspath: ''
|
||||
};
|
||||
options = deck.getConfig().simplemenu || {};
|
||||
options = mergeDeep(defaultOptions, options);
|
||||
let wronginputs = false;
|
||||
let warning = '';
|
||||
|
||||
if (options.selectby !== "id" && options.selectby !== "data-name" && options.selectby !== "name") {
|
||||
wronginputs = true;
|
||||
warning = 'The selectby option can be only "id", "data-name" or "name".';
|
||||
}
|
||||
|
||||
if (wronginputs) {
|
||||
console.log('Simplemenu did not load:');
|
||||
console.log(warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
return simpleMenu(deck, options, "simplemenu.js");
|
||||
};
|
||||
|
||||
return {
|
||||
id: 'simplemenu',
|
||||
init: init
|
||||
};
|
||||
};
|
||||
|
||||
return Plugin;
|
||||
|
||||
}));
|
||||
Reference in New Issue
Block a user