浏览代码

reader mode; deeplink support, presentation scaling, scroll trigger fixes

Hakim El Hattab 1 年之前
父节点
当前提交
eaf5f61318
共有 4 个文件被更改,包括 66 次插入18 次删除
  1. 1 0
      css/reveal.scss
  2. 5 6
      js/controllers/fragments.js
  3. 36 3
      js/controllers/reader.js
  4. 24 9
      js/reveal.js

+ 1 - 0
css/reveal.scss

@@ -1885,6 +1885,7 @@ $notesWidthPercent: 25%;
 		width: auto !important;
 		width: auto !important;
 		height: auto !important;
 		height: auto !important;
 		overflow: visible !important;
 		overflow: visible !important;
+		touch-action: manipulation;
 	}
 	}
 	.reveal .slides {
 	.reveal .slides {
 		position: static;
 		position: static;

+ 5 - 6
js/controllers/fragments.js

@@ -174,24 +174,23 @@ export default class Fragments {
 	 *
 	 *
 	 * @return {{shown: array, hidden: array}}
 	 * @return {{shown: array, hidden: array}}
 	 */
 	 */
-	update( index, fragments ) {
+	update( index, fragments, slide = this.Reveal.getCurrentSlide() ) {
 
 
 		let changedFragments = {
 		let changedFragments = {
 			shown: [],
 			shown: [],
 			hidden: []
 			hidden: []
 		};
 		};
 
 
-		let currentSlide = this.Reveal.getCurrentSlide();
-		if( currentSlide && this.Reveal.getConfig().fragments ) {
+		if( slide && this.Reveal.getConfig().fragments ) {
 
 
-			fragments = fragments || this.sort( currentSlide.querySelectorAll( '.fragment' ) );
+			fragments = fragments || this.sort( slide.querySelectorAll( '.fragment' ) );
 
 
 			if( fragments.length ) {
 			if( fragments.length ) {
 
 
 				let maxIndex = 0;
 				let maxIndex = 0;
 
 
 				if( typeof index !== 'number' ) {
 				if( typeof index !== 'number' ) {
-					let currentFragment = this.sort( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop();
+					let currentFragment = this.sort( slide.querySelectorAll( '.fragment.visible' ) ).pop();
 					if( currentFragment ) {
 					if( currentFragment ) {
 						index = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );
 						index = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );
 					}
 					}
@@ -252,7 +251,7 @@ export default class Fragments {
 				// the current fragment index.
 				// the current fragment index.
 				index = typeof index === 'number' ? index : -1;
 				index = typeof index === 'number' ? index : -1;
 				index = Math.max( Math.min( index, maxIndex ), -1 );
 				index = Math.max( Math.min( index, maxIndex ), -1 );
-				currentSlide.setAttribute( 'data-fragment', index );
+				slide.setAttribute( 'data-fragment', index );
 
 
 			}
 			}
 
 

+ 36 - 3
js/controllers/reader.js

@@ -11,6 +11,9 @@ export default class Reader {
 
 
 		this.Reveal = Reveal;
 		this.Reveal = Reveal;
 
 
+		this.activated = false;
+		this.activatedCallbacks = [];
+
 	}
 	}
 
 
 	async activate() {
 	async activate() {
@@ -90,6 +93,10 @@ export default class Reader {
 
 
 		this.Reveal.layout();
 		this.Reveal.layout();
 
 
+		this.activated = true;
+		this.activatedCallbacks.forEach( callback => callback() );
+		this.activatedCallbacks = [];
+
 	}
 	}
 
 
 	/**
 	/**
@@ -107,6 +114,9 @@ export default class Reader {
 
 
 	generatePageMap() {
 	generatePageMap() {
 
 
+		const viewportElement = this.Reveal.getViewportElement();
+		const viewportHeight = viewportElement.offsetHeight;
+
 		const slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );
 		const slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );
 		const scale = this.Reveal.getScale();
 		const scale = this.Reveal.getScale();
 
 
@@ -116,6 +126,9 @@ export default class Reader {
 		this.pageElements = Array.from( this.Reveal.getRevealElement().querySelectorAll( '.reader-page' ) );
 		this.pageElements = Array.from( this.Reveal.getRevealElement().querySelectorAll( '.reader-page' ) );
 
 
 		this.pageMap = this.pageElements.map( pageElement => {
 		this.pageMap = this.pageElements.map( pageElement => {
+			// pageElement.style.width = ( viewportElement.offsetWidth / scale ) + 'px';
+			// pageElement.style.height = ( viewportElement.offsetHeight / scale ) + 'px';
+
 			const page = {
 			const page = {
 				pageElement: pageElement,
 				pageElement: pageElement,
 				slideElement: pageElement.querySelector( 'section' ),
 				slideElement: pageElement.querySelector( 'section' ),
@@ -140,7 +153,7 @@ export default class Reader {
 			page.bottom = page.top + page.totalHeight;
 			page.bottom = page.top + page.totalHeight;
 
 
 			// Pad the page height to reserve scrollable height
 			// Pad the page height to reserve scrollable height
-			page.pageElement.style.marginBottom = page.scrollHeight + 'px';
+			page.pageElement.style.marginBottom = page.scrollHeight / scale + 'px';
 
 
 			// Create scroll triggers that show/hide fragments
 			// Create scroll triggers that show/hide fragments
 			if( page.fragmentGroups.length ) {
 			if( page.fragmentGroups.length ) {
@@ -155,6 +168,9 @@ export default class Reader {
 						fragmentIndex: i
 						fragmentIndex: i
 					}))
 					}))
 				);
 				);
+
+				// Make this page freeze at the vertical center of the viewport
+				page.top -= ( viewportHeight - page.pageHeight ) / 2;
 			}
 			}
 
 
 			return page;
 			return page;
@@ -162,13 +178,24 @@ export default class Reader {
 
 
 	}
 	}
 
 
-	update() {
+	layout() {
 
 
 		this.generatePageMap();
 		this.generatePageMap();
 		this.onScroll();
 		this.onScroll();
 
 
 	}
 	}
 
 
+	scrollToSlide( slideElement ) {
+
+		if( !this.activated ) {
+			this.activatedCallbacks.push( () => this.scrollToSlide( slideElement ) );
+		}
+		else {
+			slideElement.parentNode.scrollIntoView();
+		}
+
+	}
+
 	onScroll() {
 	onScroll() {
 
 
 		const viewportElement = this.Reveal.getViewportElement();
 		const viewportElement = this.Reveal.getViewportElement();
@@ -196,7 +223,13 @@ export default class Reader {
 
 
 					page.scrollTriggers.forEach( trigger => {
 					page.scrollTriggers.forEach( trigger => {
 						if( scrollProgress >= trigger.range[0] && scrollProgress < trigger.range[1] ) {
 						if( scrollProgress >= trigger.range[0] && scrollProgress < trigger.range[1] ) {
-							this.Reveal.fragments.update( trigger.fragmentIndex, page.fragments );
+							if( !trigger.active ) {
+								trigger.active = true;
+								this.Reveal.fragments.update( trigger.fragmentIndex, page.fragments, page.slideElement );
+							}
+						}
+						else {
+							trigger.active = false;
 						}
 						}
 					} );
 					} );
 				}
 				}

+ 24 - 9
js/reveal.js

@@ -234,9 +234,13 @@ export default function( revealElement, options ) {
 		// to be read or printed linearly
 		// to be read or printed linearly
 		if( isPrintMode || isReaderMode ) {
 		if( isPrintMode || isReaderMode ) {
 
 
-			removeEventListeners();
-
-			window.addEventListener( 'resize', onWindowResize, false );
+			if( isPrintMode ) {
+				removeEventListeners();
+			}
+			else {
+				keyboard.unbind();
+				touch.unbind();
+			}
 
 
 			// Avoid content flickering during layout
 			// Avoid content flickering during layout
 			revealElement.style.visibility = 'hidden';
 			revealElement.style.visibility = 'hidden';
@@ -896,7 +900,9 @@ export default function( revealElement, options ) {
 					document.documentElement.style.setProperty( '--vh', ( window.innerHeight * 0.01 ) + 'px' );
 					document.documentElement.style.setProperty( '--vh', ( window.innerHeight * 0.01 ) + 'px' );
 				}
 				}
 
 
-				const size = getComputedSlideSize();
+				const size = reader.isActive() ?
+							 getComputedSlideSize( dom.viewport.offsetWidth, dom.viewport.offsetHeight ) :
+							 getComputedSlideSize();;
 
 
 				const oldScale = scale;
 				const oldScale = scale;
 
 
@@ -924,10 +930,10 @@ export default function( revealElement, options ) {
 				}
 				}
 				else if( reader.isActive() ) {
 				else if( reader.isActive() ) {
 					dom.slides.style.zoom = '';
 					dom.slides.style.zoom = '';
-					dom.slides.style.left = 'auto';
-					dom.slides.style.top = 'auto';
-					dom.slides.style.bottom = 'auto';
-					dom.slides.style.right = 'auto';
+					dom.slides.style.left = '';
+					dom.slides.style.top = '';
+					dom.slides.style.bottom = '';
+					dom.slides.style.right = '';
 					dom.slides.style.height = 'auto';
 					dom.slides.style.height = 'auto';
 					transformSlides( { layout: 'scale('+ scale +')' } );
 					transformSlides( { layout: 'scale('+ scale +')' } );
 				}
 				}
@@ -981,9 +987,10 @@ export default function( revealElement, options ) {
 
 
 			dom.viewport.style.setProperty( '--slide-scale', scale );
 			dom.viewport.style.setProperty( '--slide-scale', scale );
 
 
+			reader.layout();
+
 			progress.update();
 			progress.update();
 			backgrounds.updateParallax();
 			backgrounds.updateParallax();
-			reader.update();
 
 
 			if( overview.isActive() ) {
 			if( overview.isActive() ) {
 				overview.update();
 				overview.update();
@@ -1309,6 +1316,14 @@ export default function( revealElement, options ) {
 		// Query all horizontal slides in the deck
 		// Query all horizontal slides in the deck
 		const horizontalSlides = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
 		const horizontalSlides = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
 
 
+		// If we're in reader mode we scroll the target slide into view
+		// instead of running our standard slide transition
+		if( reader.isActive() ) {
+			const scrollToSlide = dom.wrapper.querySelectorAll( SLIDES_SELECTOR )[ h ];
+			if( scrollToSlide ) reader.scrollToSlide( scrollToSlide );
+			return;
+		}
+
 		// Abort if there are no slides
 		// Abort if there are no slides
 		if( horizontalSlides.length === 0 ) return;
 		if( horizontalSlides.length === 0 ) return;