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

148 lines
3.3 KiB
JavaScript
Raw Normal View History

/**
2023-01-25 14:13:31 +01:00
* Makes it possible to jump to a slide by entering its
* slide number or id.
*/
export default class JumpToSlide {
2023-05-23 19:50:14 +02:00
constructor(Reveal) {
this.Reveal = Reveal;
this.onInput = this.onInput.bind(this);
this.onBlur = this.onBlur.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
}
render() {
this.element = document.createElement("div");
this.element.className = "jump-to-slide";
this.jumpInput = document.createElement("input");
this.jumpInput.type = "text";
this.jumpInput.className = "jump-to-slide-input";
this.jumpInput.placeholder = "Jump to slide";
this.jumpInput.addEventListener("input", this.onInput);
this.jumpInput.addEventListener("keydown", this.onKeyDown);
this.jumpInput.addEventListener("blur", this.onBlur);
this.element.appendChild(this.jumpInput);
}
show() {
this.indicesOnShow = this.Reveal.getIndices();
this.Reveal.getRevealElement().appendChild(this.element);
this.jumpInput.focus();
}
hide() {
if (this.isVisible()) {
this.element.remove();
this.jumpInput.value = "";
clearTimeout(this.jumpTimeout);
delete this.jumpTimeout;
}
}
isVisible() {
return !!this.element.parentNode;
}
/**
* Parses the current input and jumps to the given slide.
*/
jump() {
clearTimeout(this.jumpTimeout);
delete this.jumpTimeout;
const query = this.jumpInput.value.trim("");
let indices = this.Reveal.location.getIndicesFromHash(query, {
oneBasedIndex: true,
});
// If no valid index was found and the input query is a
// string, fall back on a simple search
if (!indices && /\S+/i.test(query) && query.length > 1) {
indices = this.search(query);
}
if (indices && query !== "") {
this.Reveal.slide(indices.h, indices.v, indices.f);
return true;
} else {
this.Reveal.slide(
this.indicesOnShow.h,
this.indicesOnShow.v,
this.indicesOnShow.f
);
return false;
}
}
jumpAfter(delay) {
clearTimeout(this.jumpTimeout);
this.jumpTimeout = setTimeout(() => this.jump(), delay);
}
/**
* A lofi search that looks for the given query in all
* of our slides and returns the first match.
*/
search(query) {
const regex = new RegExp("\\b" + query.trim() + "\\b", "i");
const slide = this.Reveal.getSlides().find((slide) => {
return regex.test(slide.innerText);
});
if (slide) {
return this.Reveal.getIndices(slide);
} else {
return null;
}
}
/**
* Reverts back to the slide we were on when jump to slide was
* invoked.
*/
cancel() {
this.Reveal.slide(
this.indicesOnShow.h,
this.indicesOnShow.v,
this.indicesOnShow.f
);
this.hide();
}
confirm() {
this.jump();
this.hide();
}
destroy() {
this.jumpInput.removeEventListener("input", this.onInput);
this.jumpInput.removeEventListener("keydown", this.onKeyDown);
this.jumpInput.removeEventListener("blur", this.onBlur);
this.element.remove();
}
onKeyDown(event) {
if (event.keyCode === 13) {
this.confirm();
} else if (event.keyCode === 27) {
this.cancel();
event.stopImmediatePropagation();
}
}
onInput(event) {
this.jumpAfter(200);
}
onBlur() {
setTimeout(() => this.hide(), 1);
}
}