diff --git a/css/reveal.scss b/css/reveal.scss index 6dd30979..c061c8f9 100644 --- a/css/reveal.scss +++ b/css/reveal.scss @@ -1885,6 +1885,7 @@ $notesWidthPercent: 25%; width: auto !important; height: auto !important; overflow: visible !important; + touch-action: manipulation; } .reveal .slides { position: static; diff --git a/js/controllers/fragments.js b/js/controllers/fragments.js index 796c1684..8aa597b7 100644 --- a/js/controllers/fragments.js +++ b/js/controllers/fragments.js @@ -174,24 +174,23 @@ export default class Fragments { * * @return {{shown: array, hidden: array}} */ - update( index, fragments ) { + update( index, fragments, slide = this.Reveal.getCurrentSlide() ) { let changedFragments = { shown: [], 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 ) { let maxIndex = 0; if( typeof index !== 'number' ) { - let currentFragment = this.sort( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop(); + let currentFragment = this.sort( slide.querySelectorAll( '.fragment.visible' ) ).pop(); if( currentFragment ) { index = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 ); } @@ -252,7 +251,7 @@ export default class Fragments { // the current fragment index. index = typeof index === 'number' ? index : -1; index = Math.max( Math.min( index, maxIndex ), -1 ); - currentSlide.setAttribute( 'data-fragment', index ); + slide.setAttribute( 'data-fragment', index ); } diff --git a/js/controllers/reader.js b/js/controllers/reader.js index 3b06b989..99615e75 100644 --- a/js/controllers/reader.js +++ b/js/controllers/reader.js @@ -11,6 +11,9 @@ export default class Reader { this.Reveal = Reveal; + this.activated = false; + this.activatedCallbacks = []; + } async activate() { @@ -90,6 +93,10 @@ export default class Reader { this.Reveal.layout(); + this.activated = true; + this.activatedCallbacks.forEach( callback => callback() ); + this.activatedCallbacks = []; + } /** @@ -107,6 +114,9 @@ export default class Reader { generatePageMap() { + const viewportElement = this.Reveal.getViewportElement(); + const viewportHeight = viewportElement.offsetHeight; + const slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight ); const scale = this.Reveal.getScale(); @@ -116,6 +126,9 @@ export default class Reader { this.pageElements = Array.from( this.Reveal.getRevealElement().querySelectorAll( '.reader-page' ) ); this.pageMap = this.pageElements.map( pageElement => { + // pageElement.style.width = ( viewportElement.offsetWidth / scale ) + 'px'; + // pageElement.style.height = ( viewportElement.offsetHeight / scale ) + 'px'; + const page = { pageElement: pageElement, slideElement: pageElement.querySelector( 'section' ), @@ -140,7 +153,7 @@ export default class Reader { page.bottom = page.top + page.totalHeight; // 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 if( page.fragmentGroups.length ) { @@ -155,6 +168,9 @@ export default class Reader { fragmentIndex: i })) ); + + // Make this page freeze at the vertical center of the viewport + page.top -= ( viewportHeight - page.pageHeight ) / 2; } return page; @@ -162,13 +178,24 @@ export default class Reader { } - update() { + layout() { this.generatePageMap(); this.onScroll(); } + scrollToSlide( slideElement ) { + + if( !this.activated ) { + this.activatedCallbacks.push( () => this.scrollToSlide( slideElement ) ); + } + else { + slideElement.parentNode.scrollIntoView(); + } + + } + onScroll() { const viewportElement = this.Reveal.getViewportElement(); @@ -196,7 +223,13 @@ export default class Reader { page.scrollTriggers.forEach( trigger => { 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; } } ); } diff --git a/js/reveal.js b/js/reveal.js index ea8bbdf1..801074a4 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -234,9 +234,13 @@ export default function( revealElement, options ) { // to be read or printed linearly if( isPrintMode || isReaderMode ) { - removeEventListeners(); - - window.addEventListener( 'resize', onWindowResize, false ); + if( isPrintMode ) { + removeEventListeners(); + } + else { + keyboard.unbind(); + touch.unbind(); + } // Avoid content flickering during layout revealElement.style.visibility = 'hidden'; @@ -896,7 +900,9 @@ export default function( revealElement, options ) { 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; @@ -924,10 +930,10 @@ export default function( revealElement, options ) { } else if( reader.isActive() ) { 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'; transformSlides( { layout: 'scale('+ scale +')' } ); } @@ -981,9 +987,10 @@ export default function( revealElement, options ) { dom.viewport.style.setProperty( '--slide-scale', scale ); + reader.layout(); + progress.update(); backgrounds.updateParallax(); - reader.update(); if( overview.isActive() ) { overview.update(); @@ -1309,6 +1316,14 @@ export default function( revealElement, options ) { // Query all horizontal slides in the deck 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 if( horizontalSlides.length === 0 ) return;