import { closest } from "../utils/util.js"; /** * Manages focus when a presentation is embedded. This * helps us only capture keyboard from the presentation * a user is currently interacting with in a page where * multiple presentations are embedded. */ const STATE_FOCUS = "focus"; const STATE_BLUR = "blur"; export default class Focus { constructor(Reveal) { this.Reveal = Reveal; this.onRevealPointerDown = this.onRevealPointerDown.bind(this); this.onDocumentPointerDown = this.onDocumentPointerDown.bind(this); } /** * Called when the reveal.js config is updated. */ configure(config, oldConfig) { if (config.embedded) { this.blur(); } else { this.focus(); this.unbind(); } } bind() { if (this.Reveal.getConfig().embedded) { this.Reveal.getRevealElement().addEventListener( "pointerdown", this.onRevealPointerDown, false ); } } unbind() { this.Reveal.getRevealElement().removeEventListener( "pointerdown", this.onRevealPointerDown, false ); document.removeEventListener( "pointerdown", this.onDocumentPointerDown, false ); } focus() { if (this.state !== STATE_FOCUS) { this.Reveal.getRevealElement().classList.add("focused"); document.addEventListener( "pointerdown", this.onDocumentPointerDown, false ); } this.state = STATE_FOCUS; } blur() { if (this.state !== STATE_BLUR) { this.Reveal.getRevealElement().classList.remove("focused"); document.removeEventListener( "pointerdown", this.onDocumentPointerDown, false ); } this.state = STATE_BLUR; } isFocused() { return this.state === STATE_FOCUS; } destroy() { this.Reveal.getRevealElement().classList.remove("focused"); } onRevealPointerDown(event) { this.focus(); } onDocumentPointerDown(event) { let revealElement = closest(event.target, ".reveal"); if (!revealElement || revealElement !== this.Reveal.getRevealElement()) { this.blur(); } } }