1
0
Fork 0
why-cant-we-deploy-today/js/controllers/overview.js

257 lines
6.9 KiB
JavaScript
Raw Permalink Normal View History

2023-05-23 19:50:14 +02:00
import { SLIDES_SELECTOR } from "../utils/constants.js";
import { extend, queryAll, transformElement } from "../utils/util.js";
2020-03-09 20:57:12 +01:00
/**
* Handles all logic related to the overview mode
* (birds-eye view of all slides).
*/
export default class Overview {
2023-05-23 19:50:14 +02:00
constructor(Reveal) {
this.Reveal = Reveal;
this.active = false;
this.onSlideClicked = this.onSlideClicked.bind(this);
}
/**
* Displays the overview of slides (quick nav) by scaling
* down and arranging all slide elements.
*/
activate() {
// Only proceed if enabled in config
if (this.Reveal.getConfig().overview && !this.isActive()) {
this.active = true;
this.Reveal.getRevealElement().classList.add("overview");
// Don't auto-slide while in overview mode
this.Reveal.cancelAutoSlide();
// Move the backgrounds element into the slide container to
// that the same scaling is applied
this.Reveal.getSlidesElement().appendChild(
this.Reveal.getBackgroundsElement()
);
// Clicking on an overview slide navigates to it
queryAll(this.Reveal.getRevealElement(), SLIDES_SELECTOR).forEach(
(slide) => {
if (!slide.classList.contains("stack")) {
slide.addEventListener("click", this.onSlideClicked, true);
}
}
);
// Calculate slide sizes
const margin = 70;
const slideSize = this.Reveal.getComputedSlideSize();
this.overviewSlideWidth = slideSize.width + margin;
this.overviewSlideHeight = slideSize.height + margin;
// Reverse in RTL mode
if (this.Reveal.getConfig().rtl) {
this.overviewSlideWidth = -this.overviewSlideWidth;
}
this.Reveal.updateSlidesVisibility();
this.layout();
this.update();
this.Reveal.layout();
const indices = this.Reveal.getIndices();
// Notify observers of the overview showing
this.Reveal.dispatchEvent({
type: "overviewshown",
data: {
indexh: indices.h,
indexv: indices.v,
currentSlide: this.Reveal.getCurrentSlide(),
},
});
}
}
/**
* Uses CSS transforms to position all slides in a grid for
* display inside of the overview mode.
*/
layout() {
// Layout slides
this.Reveal.getHorizontalSlides().forEach((hslide, h) => {
hslide.setAttribute("data-index-h", h);
transformElement(
hslide,
"translate3d(" + h * this.overviewSlideWidth + "px, 0, 0)"
);
if (hslide.classList.contains("stack")) {
queryAll(hslide, "section").forEach((vslide, v) => {
vslide.setAttribute("data-index-h", h);
vslide.setAttribute("data-index-v", v);
transformElement(
vslide,
"translate3d(0, " + v * this.overviewSlideHeight + "px, 0)"
);
});
}
});
// Layout slide backgrounds
Array.from(this.Reveal.getBackgroundsElement().childNodes).forEach(
(hbackground, h) => {
transformElement(
hbackground,
"translate3d(" + h * this.overviewSlideWidth + "px, 0, 0)"
);
queryAll(hbackground, ".slide-background").forEach((vbackground, v) => {
transformElement(
vbackground,
"translate3d(0, " + v * this.overviewSlideHeight + "px, 0)"
);
});
}
);
}
/**
* Moves the overview viewport to the current slides.
* Called each time the current slide changes.
*/
update() {
const vmin = Math.min(window.innerWidth, window.innerHeight);
const scale = Math.max(vmin / 5, 150) / vmin;
const indices = this.Reveal.getIndices();
this.Reveal.transformSlides({
overview: [
"scale(" + scale + ")",
"translateX(" + -indices.h * this.overviewSlideWidth + "px)",
"translateY(" + -indices.v * this.overviewSlideHeight + "px)",
].join(" "),
});
}
/**
* Exits the slide overview and enters the currently
* active slide.
*/
deactivate() {
// Only proceed if enabled in config
if (this.Reveal.getConfig().overview) {
this.active = false;
this.Reveal.getRevealElement().classList.remove("overview");
// Temporarily add a class so that transitions can do different things
// depending on whether they are exiting/entering overview, or just
// moving from slide to slide
this.Reveal.getRevealElement().classList.add("overview-deactivating");
setTimeout(() => {
this.Reveal.getRevealElement().classList.remove(
"overview-deactivating"
);
}, 1);
// Move the background element back out
this.Reveal.getRevealElement().appendChild(
this.Reveal.getBackgroundsElement()
);
// Clean up changes made to slides
queryAll(this.Reveal.getRevealElement(), SLIDES_SELECTOR).forEach(
(slide) => {
transformElement(slide, "");
slide.removeEventListener("click", this.onSlideClicked, true);
}
);
// Clean up changes made to backgrounds
queryAll(
this.Reveal.getBackgroundsElement(),
".slide-background"
).forEach((background) => {
transformElement(background, "");
});
this.Reveal.transformSlides({ overview: "" });
const indices = this.Reveal.getIndices();
this.Reveal.slide(indices.h, indices.v);
this.Reveal.layout();
this.Reveal.cueAutoSlide();
// Notify observers of the overview hiding
this.Reveal.dispatchEvent({
type: "overviewhidden",
data: {
indexh: indices.h,
indexv: indices.v,
currentSlide: this.Reveal.getCurrentSlide(),
},
});
}
}
/**
* Toggles the slide overview mode on and off.
*
* @param {Boolean} [override] Flag which overrides the
* toggle logic and forcibly sets the desired state. True means
* overview is open, false means it's closed.
*/
toggle(override) {
if (typeof override === "boolean") {
override ? this.activate() : this.deactivate();
} else {
this.isActive() ? this.deactivate() : this.activate();
}
}
/**
* Checks if the overview is currently active.
*
* @return {Boolean} true if the overview is active,
* false otherwise
*/
isActive() {
return this.active;
}
/**
* Invoked when a slide is and we're in the overview.
*
* @param {object} event
*/
onSlideClicked(event) {
if (this.isActive()) {
event.preventDefault();
let element = event.target;
while (element && !element.nodeName.match(/section/gi)) {
element = element.parentNode;
}
if (element && !element.classList.contains("disabled")) {
this.deactivate();
if (element.nodeName.match(/section/gi)) {
let h = parseInt(element.getAttribute("data-index-h"), 10),
v = parseInt(element.getAttribute("data-index-v"), 10);
this.Reveal.slide(h, v);
}
}
}
}
}