170 lines
3.2 KiB
JavaScript
170 lines
3.2 KiB
JavaScript
/**
|
|
* Makes it possble 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 );
|
|
|
|
}
|
|
|
|
} |