summaryrefslogtreecommitdiff
path: root/2024-06-18-guix-social/reveal.js/js/controllers/jumptoslide.js
diff options
context:
space:
mode:
Diffstat (limited to '2024-06-18-guix-social/reveal.js/js/controllers/jumptoslide.js')
-rw-r--r--2024-06-18-guix-social/reveal.js/js/controllers/jumptoslide.js197
1 files changed, 197 insertions, 0 deletions
diff --git a/2024-06-18-guix-social/reveal.js/js/controllers/jumptoslide.js b/2024-06-18-guix-social/reveal.js/js/controllers/jumptoslide.js
new file mode 100644
index 0000000..5a63260
--- /dev/null
+++ b/2024-06-18-guix-social/reveal.js/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 mumber
+ // (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