Vendor reveal.js 5.2.1 (from 5.1.0)

Contains the upstream 5.2.x feature set, most notably the lightbox
(data-preview-image/data-preview-video opens media full-size in an
overlay), controls: "speaker-only", search API extensions and
speaker-view fixes. The package's local additions are carried over
unchanged: IDS theme (ids.css/ids.scss), extra theme fonts,
chalkboard/customcontrols/menu plugins, and the 1280x720 default
slide size (patched in js/config.js and the dist bundles).

Also fixes a pre-existing fork bug (unrelated to the upgrade): the
slidechanged Highcharts resize hook in default.html now checks that
Highcharts exists, no longer throwing in decks without highcharter.

Docs: README (Rmd + rendered md) gained a short Lightbox section,
NEWS.md notes the library bump.

Verified: examples/ids.html and examples/simple.html re-render and run
error-free through all 13/5 slides (Reveal.VERSION = 5.2.1); lightbox
opens on click and closes with Esc in a dedicated test deck.

Change-Id: I0751129dfb0c9d20b56241377905876314a26011
diff --git a/inst/reveal.js-5.2.1/js/controllers/jumptoslide.js b/inst/reveal.js-5.2.1/js/controllers/jumptoslide.js
new file mode 100644
index 0000000..0aaa2b1
--- /dev/null
+++ b/inst/reveal.js-5.2.1/js/controllers/jumptoslide.js
@@ -0,0 +1,197 @@
+import {
+	SLIDE_NUMBER_FORMAT_CURRENT,
+	SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL
+} from "../utils/constants";
+
+/**
+ * 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;
+
+		let query = this.jumpInput.value.trim( '' );
+		let indices;
+
+		// When slide numbers are formatted to be a single linear number
+		// (instead of showing a separate horizontal/vertical index) we
+		// use the same format for slide jumps
+		if( /^\d+$/.test( query ) ) {
+			const slideNumberFormat = this.Reveal.getConfig().slideNumber;
+			if( slideNumberFormat === SLIDE_NUMBER_FORMAT_CURRENT || slideNumberFormat === SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL ) {
+				const slide = this.Reveal.getSlides()[ parseInt( query, 10 ) - 1 ];
+				if( slide ) {
+					indices = this.Reveal.getIndices( slide );
+				}
+			}
+		}
+
+		if( !indices ) {
+			// If the query uses "horizontal.vertical" format, convert to
+			// "horizontal/vertical" so that our URL parser can understand
+			if( /^\d+\.\d+$/.test( query ) ) {
+				query = query.replace( '.', '/' );
+			}
+
+			indices = this.Reveal.location.getIndicesFromHash( query, { oneBasedIndex: true } );
+		}
+
+		// Still no valid index? Fall back on a text 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 );
+
+	}
+
+}
\ No newline at end of file