148 lines
3.3 KiB
JavaScript
148 lines
3.3 KiB
JavaScript
/**
|
|
* Makes it possible to jump to a slide by entering its
|
|
* slide number or id.
|
|
*/
|
|
export default class JumpToSlide {
|
|
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);
|
|
}
|
|
}
|