Update to reveal.js 4.1.2 (#136)

- New tools/ script to manually keep step for updates
- Plugins are all updated
- Template update following latest Pandoc version
- updated README for documentation
- Help page updated 
- See other change in NEWS file
diff --git a/inst/reveal.js-4.1.2/js/components/playback.js b/inst/reveal.js-4.1.2/js/components/playback.js
new file mode 100644
index 0000000..06fa7ba
--- /dev/null
+++ b/inst/reveal.js-4.1.2/js/components/playback.js
@@ -0,0 +1,165 @@
+/**
+ * UI component that lets the use control auto-slide
+ * playback via play/pause.
+ */
+export default class Playback {
+
+	/**
+	 * @param {HTMLElement} container The component will append
+	 * itself to this
+	 * @param {function} progressCheck A method which will be
+	 * called frequently to get the current playback progress on
+	 * a range of 0-1
+	 */
+	constructor( container, progressCheck ) {
+
+		// Cosmetics
+		this.diameter = 100;
+		this.diameter2 = this.diameter/2;
+		this.thickness = 6;
+
+		// Flags if we are currently playing
+		this.playing = false;
+
+		// Current progress on a 0-1 range
+		this.progress = 0;
+
+		// Used to loop the animation smoothly
+		this.progressOffset = 1;
+
+		this.container = container;
+		this.progressCheck = progressCheck;
+
+		this.canvas = document.createElement( 'canvas' );
+		this.canvas.className = 'playback';
+		this.canvas.width = this.diameter;
+		this.canvas.height = this.diameter;
+		this.canvas.style.width = this.diameter2 + 'px';
+		this.canvas.style.height = this.diameter2 + 'px';
+		this.context = this.canvas.getContext( '2d' );
+
+		this.container.appendChild( this.canvas );
+
+		this.render();
+
+	}
+
+	setPlaying( value ) {
+
+		const wasPlaying = this.playing;
+
+		this.playing = value;
+
+		// Start repainting if we weren't already
+		if( !wasPlaying && this.playing ) {
+			this.animate();
+		}
+		else {
+			this.render();
+		}
+
+	}
+
+	animate() {
+
+		const progressBefore = this.progress;
+
+		this.progress = this.progressCheck();
+
+		// When we loop, offset the progress so that it eases
+		// smoothly rather than immediately resetting
+		if( progressBefore > 0.8 && this.progress < 0.2 ) {
+			this.progressOffset = this.progress;
+		}
+
+		this.render();
+
+		if( this.playing ) {
+			requestAnimationFrame( this.animate.bind( this ) );
+		}
+
+	}
+
+	/**
+	 * Renders the current progress and playback state.
+	 */
+	render() {
+
+		let progress = this.playing ? this.progress : 0,
+			radius = ( this.diameter2 ) - this.thickness,
+			x = this.diameter2,
+			y = this.diameter2,
+			iconSize = 28;
+
+		// Ease towards 1
+		this.progressOffset += ( 1 - this.progressOffset ) * 0.1;
+
+		const endAngle = ( - Math.PI / 2 ) + ( progress * ( Math.PI * 2 ) );
+		const startAngle = ( - Math.PI / 2 ) + ( this.progressOffset * ( Math.PI * 2 ) );
+
+		this.context.save();
+		this.context.clearRect( 0, 0, this.diameter, this.diameter );
+
+		// Solid background color
+		this.context.beginPath();
+		this.context.arc( x, y, radius + 4, 0, Math.PI * 2, false );
+		this.context.fillStyle = 'rgba( 0, 0, 0, 0.4 )';
+		this.context.fill();
+
+		// Draw progress track
+		this.context.beginPath();
+		this.context.arc( x, y, radius, 0, Math.PI * 2, false );
+		this.context.lineWidth = this.thickness;
+		this.context.strokeStyle = 'rgba( 255, 255, 255, 0.2 )';
+		this.context.stroke();
+
+		if( this.playing ) {
+			// Draw progress on top of track
+			this.context.beginPath();
+			this.context.arc( x, y, radius, startAngle, endAngle, false );
+			this.context.lineWidth = this.thickness;
+			this.context.strokeStyle = '#fff';
+			this.context.stroke();
+		}
+
+		this.context.translate( x - ( iconSize / 2 ), y - ( iconSize / 2 ) );
+
+		// Draw play/pause icons
+		if( this.playing ) {
+			this.context.fillStyle = '#fff';
+			this.context.fillRect( 0, 0, iconSize / 2 - 4, iconSize );
+			this.context.fillRect( iconSize / 2 + 4, 0, iconSize / 2 - 4, iconSize );
+		}
+		else {
+			this.context.beginPath();
+			this.context.translate( 4, 0 );
+			this.context.moveTo( 0, 0 );
+			this.context.lineTo( iconSize - 4, iconSize / 2 );
+			this.context.lineTo( 0, iconSize );
+			this.context.fillStyle = '#fff';
+			this.context.fill();
+		}
+
+		this.context.restore();
+
+	}
+
+	on( type, listener ) {
+		this.canvas.addEventListener( type, listener, false );
+	}
+
+	off( type, listener ) {
+		this.canvas.removeEventListener( type, listener, false );
+	}
+
+	destroy() {
+
+		this.playing = false;
+
+		if( this.canvas.parentNode ) {
+			this.container.removeChild( this.canvas );
+		}
+
+	}
+
+}
\ No newline at end of file