Browse Source

new shortcuts; alt+arrow key skips fragments, shift+arrow key jumps to last slide in the given direction #1105

Hakim El Hattab 3 years ago
parent
commit
90bbe8be4f
5 changed files with 82 additions and 45 deletions
  1. 0 0
      dist/reveal.esm.js
  2. 0 0
      dist/reveal.js
  3. 28 24
      js/controllers/keyboard.js
  4. 18 18
      js/reveal.js
  5. 36 3
      test/test.html

File diff suppressed because it is too large
+ 0 - 0
dist/reveal.esm.js


File diff suppressed because it is too large
+ 0 - 0
dist/reveal.js


+ 28 - 24
js/controllers/keyboard.js

@@ -32,15 +32,15 @@ export default class Keyboard {
 		}
 		else {
 			this.shortcuts['N  ,  SPACE']   = 'Next slide';
-			this.shortcuts['P']             = 'Previous slide';
+			this.shortcuts['P  ,  Shift SPACE']             = 'Previous slide';
 			this.shortcuts['←  ,  H'] = 'Navigate left';
 			this.shortcuts['→  ,  L'] = 'Navigate right';
 			this.shortcuts['↑  ,  K'] = 'Navigate up';
 			this.shortcuts['↓  ,  J'] = 'Navigate down';
 		}
 
-		this.shortcuts['Home  ,  Shift ←']        = 'First slide';
-		this.shortcuts['End  ,  Shift →']         = 'Last slide';
+		this.shortcuts['Alt + ←/&#8593/→/↓']        = 'Navigate without fragments';
+		this.shortcuts['Shift + ←/&#8593/→/↓']      = 'Jump to first/last slide';
 		this.shortcuts['B  ,  .']                       = 'Pause';
 		this.shortcuts['F']                             = 'Fullscreen';
 		this.shortcuts['ESC, O']                        = 'Slide overview';
@@ -182,13 +182,11 @@ export default class Keyboard {
 		let activeElementIsInput = document.activeElement && document.activeElement.tagName && /input|textarea/i.test( document.activeElement.tagName );
 		let activeElementIsNotes = document.activeElement && document.activeElement.className && /speaker-notes/i.test( document.activeElement.className);
 
-		// Whitelist specific modified + keycode combinations
-		let prevSlideShortcut = event.shiftKey && event.keyCode === 32;
-		let firstSlideShortcut = event.shiftKey && keyCode === 37;
-		let lastSlideShortcut = event.shiftKey && keyCode === 39;
+		// Whitelist certain modifiers for slide navigation shortcuts
+		let isNavigationKey = [32, 37, 38, 39, 40, 78, 80].indexOf( event.keyCode ) !== -1;
 
 		// Prevent all other events when a modifier is pressed
-		let unusedModifier = 	!prevSlideShortcut && !firstSlideShortcut && !lastSlideShortcut &&
+		let unusedModifier = 	!( isNavigationKey && event.shiftKey || event.altKey ) &&
 								( event.shiftKey || event.altKey || event.ctrlKey || event.metaKey );
 
 		// Disregard the event if there's a focused element or a
@@ -277,52 +275,58 @@ export default class Keyboard {
 
 			// P, PAGE UP
 			if( keyCode === 80 || keyCode === 33 ) {
-				this.Reveal.prev();
+				this.Reveal.prev({skipFragments: event.altKey});
 			}
 			// N, PAGE DOWN
 			else if( keyCode === 78 || keyCode === 34 ) {
-				this.Reveal.next();
+				this.Reveal.next({skipFragments: event.altKey});
 			}
 			// H, LEFT
 			else if( keyCode === 72 || keyCode === 37 ) {
-				if( firstSlideShortcut ) {
+				if( event.shiftKey ) {
 					this.Reveal.slide( 0 );
 				}
 				else if( !this.Reveal.overview.isActive() && useLinearMode ) {
-					this.Reveal.prev();
+					this.Reveal.prev({skipFragments: event.altKey});
 				}
 				else {
-					this.Reveal.left();
+					this.Reveal.left({skipFragments: event.altKey});
 				}
 			}
 			// L, RIGHT
 			else if( keyCode === 76 || keyCode === 39 ) {
-				if( lastSlideShortcut ) {
+				if( event.shiftKey ) {
 					this.Reveal.slide( Number.MAX_VALUE );
 				}
 				else if( !this.Reveal.overview.isActive() && useLinearMode ) {
-					this.Reveal.next();
+					this.Reveal.next({skipFragments: event.altKey});
 				}
 				else {
-					this.Reveal.right();
+					this.Reveal.right({skipFragments: event.altKey});
 				}
 			}
 			// K, UP
 			else if( keyCode === 75 || keyCode === 38 ) {
-				if( !this.Reveal.overview.isActive() && useLinearMode ) {
-					this.Reveal.prev();
+				if( event.shiftKey ) {
+					this.Reveal.slide( undefined, 0 );
+				}
+				else if( !this.Reveal.overview.isActive() && useLinearMode ) {
+					this.Reveal.prev({skipFragments: event.altKey});
 				}
 				else {
-					this.Reveal.up();
+					this.Reveal.up({skipFragments: event.altKey});
 				}
 			}
 			// J, DOWN
 			else if( keyCode === 74 || keyCode === 40 ) {
-				if( !this.Reveal.overview.isActive() && useLinearMode ) {
-					this.Reveal.next();
+				if( event.shiftKey ) {
+					this.Reveal.slide( undefined, Number.MAX_VALUE );
+				}
+				else if( !this.Reveal.overview.isActive() && useLinearMode ) {
+					this.Reveal.next({skipFragments: event.altKey});
 				}
 				else {
-					this.Reveal.down();
+					this.Reveal.down({skipFragments: event.altKey});
 				}
 			}
 			// HOME
@@ -339,10 +343,10 @@ export default class Keyboard {
 					this.Reveal.overview.deactivate();
 				}
 				if( event.shiftKey ) {
-					this.Reveal.prev();
+					this.Reveal.prev({skipFragments: event.altKey});
 				}
 				else {
-					this.Reveal.next();
+					this.Reveal.next({skipFragments: event.altKey});
 				}
 			}
 			// TWO-SPOT, SEMICOLON, B, V, PERIOD, LOGITECH PRESENTER TOOLS "BLACK SCREEN" BUTTON

+ 18 - 18
js/reveal.js

@@ -2197,55 +2197,55 @@ export default function( revealElement, options ) {
 
 	}
 
-	function navigateLeft() {
+	function navigateLeft({skipFragments=false}={}) {
 
 		navigationHistory.hasNavigatedHorizontally = true;
 
 		// Reverse for RTL
 		if( config.rtl ) {
-			if( ( overview.isActive() || fragments.next() === false ) && availableRoutes().left ) {
+			if( ( overview.isActive() || skipFragments || fragments.next() === false ) && availableRoutes().left ) {
 				slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
 			}
 		}
 		// Normal navigation
-		else if( ( overview.isActive() || fragments.prev() === false ) && availableRoutes().left ) {
+		else if( ( overview.isActive() || skipFragments || fragments.prev() === false ) && availableRoutes().left ) {
 			slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
 		}
 
 	}
 
-	function navigateRight() {
+	function navigateRight({skipFragments=false}={}) {
 
 		navigationHistory.hasNavigatedHorizontally = true;
 
 		// Reverse for RTL
 		if( config.rtl ) {
-			if( ( overview.isActive() || fragments.prev() === false ) && availableRoutes().right ) {
+			if( ( overview.isActive() || skipFragments || fragments.prev() === false ) && availableRoutes().right ) {
 				slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
 			}
 		}
 		// Normal navigation
-		else if( ( overview.isActive() || fragments.next() === false ) && availableRoutes().right ) {
+		else if( ( overview.isActive() || skipFragments || fragments.next() === false ) && availableRoutes().right ) {
 			slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
 		}
 
 	}
 
-	function navigateUp() {
+	function navigateUp({skipFragments=false}={}) {
 
 		// Prioritize hiding fragments
-		if( ( overview.isActive() || fragments.prev() === false ) && availableRoutes().up ) {
+		if( ( overview.isActive() || skipFragments || fragments.prev() === false ) && availableRoutes().up ) {
 			slide( indexh, indexv - 1 );
 		}
 
 	}
 
-	function navigateDown() {
+	function navigateDown({skipFragments=false}={}) {
 
 		navigationHistory.hasNavigatedVertically = true;
 
 		// Prioritize revealing fragments
-		if( ( overview.isActive() || fragments.next() === false ) && availableRoutes().down ) {
+		if( ( overview.isActive() || skipFragments || fragments.next() === false ) && availableRoutes().down ) {
 			slide( indexh, indexv + 1 );
 		}
 
@@ -2257,12 +2257,12 @@ export default function( revealElement, options ) {
 	 * 2) Previous vertical slide
 	 * 3) Previous horizontal slide
 	 */
-	function navigatePrev() {
+	function navigatePrev({skipFragments=false}={}) {
 
 		// Prioritize revealing fragments
-		if( fragments.prev() === false ) {
+		if( skipFragments || fragments.prev() === false ) {
 			if( availableRoutes().up ) {
-				navigateUp();
+				navigateUp({skipFragments});
 			}
 			else {
 				// Fetch the previous horizontal slide, if there is one
@@ -2288,13 +2288,13 @@ export default function( revealElement, options ) {
 	/**
 	 * The reverse of #navigatePrev().
 	 */
-	function navigateNext() {
+	function navigateNext({skipFragments=false}={}) {
 
 		navigationHistory.hasNavigatedHorizontally = true;
 		navigationHistory.hasNavigatedVertically = true;
 
 		// Prioritize revealing fragments
-		if( fragments.next() === false ) {
+		if( skipFragments || fragments.next() === false ) {
 
 			let routes = availableRoutes();
 
@@ -2306,13 +2306,13 @@ export default function( revealElement, options ) {
 			}
 
 			if( routes.down ) {
-				navigateDown();
+				navigateDown({skipFragments});
 			}
 			else if( config.rtl ) {
-				navigateLeft();
+				navigateLeft({skipFragments});
 			}
 			else {
-				navigateRight();
+				navigateRight({skipFragments});
 			}
 		}
 

+ 36 - 3
test/test.html

@@ -97,6 +97,11 @@
 			// 4
 			Reveal.initialize().then( function() {
 
+				// Helper methods
+				function triggerKeyboardEvent(config) {
+					document.dispatchEvent( new KeyboardEvent( 'keydown', config ) );
+				}
+
 				// ---------------------------------------------------------------
 				// DOM TESTS
 
@@ -407,13 +412,41 @@
 					assert.ok( /X\-SHORTCUT\-X/.test( document.body.innerHTML ), 'binding is added to help overlay' );
 					Reveal.toggleHelp( false );
 
-					let event = new KeyboardEvent( 'keydown', { 'keyCode':88 } );
-					document.dispatchEvent( event );
+					triggerKeyboardEvent({ keyCode: 88 });
 
 					Reveal.removeKeyBinding( 88 );
 
 					// should do nothing
-					document.dispatchEvent( event );
+					triggerKeyboardEvent({ keyCode: 88 });
+				});
+
+				QUnit.test( 'Navigation bindings', function( assert ) {
+					Reveal.slide( 0 );
+
+					// right arrow
+					triggerKeyboardEvent({ keyCode: 39 });
+					assert.strictEqual( Reveal.getIndices().h, 1 );
+
+					// down arrow + shift
+					triggerKeyboardEvent({ keyCode: 40, shiftKey: true });
+					assert.strictEqual( Reveal.getIndices().v, 2, 'shift + down arrow goes to last vertical slide' );
+
+					// up arrow
+					triggerKeyboardEvent({ keyCode: 38 });
+					assert.strictEqual( Reveal.getIndices().v, 1 );
+
+					// right arrow + shift
+					triggerKeyboardEvent({ keyCode: 39, shiftKey: true });
+					assert.ok( Reveal.isLastSlide(), 'shift + right arrow goes to last horizontal slide' );
+
+
+					// right arrow on slide with fragments
+					Reveal.slide( 2, 0, -1 );
+					triggerKeyboardEvent({ keyCode: 39 });
+					assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 }, 'right arrow shows fragment' );
+
+					triggerKeyboardEvent({ keyCode: 39, altKey: true });
+					assert.strictEqual( Reveal.getIndices().h, 3, 'right arrow skips fragments when alt key is pressed' );
 				});
 
 				// ---------------------------------------------------------------

Some files were not shown because too many files changed in this diff