Преглед изворни кода

revamped reader mode sticky logic, add option for fullscreen pages

Hakim El Hattab пре 1 година
родитељ
комит
0861b07618
9 измењених фајлова са 101 додато и 62 уклоњено
  1. 24 21
      css/reveal.scss
  2. 0 0
      dist/reveal.css
  3. 0 0
      dist/reveal.esm.js
  4. 0 0
      dist/reveal.esm.js.map
  5. 0 0
      dist/reveal.js
  6. 0 0
      dist/reveal.js.map
  7. 11 0
      js/config.js
  8. 61 28
      js/controllers/reader.js
  9. 5 13
      js/reveal.js

+ 24 - 21
css/reveal.scss

@@ -1875,6 +1875,7 @@ $notesWidthPercent: 25%;
 	& {
 		margin: 0 auto !important;
 		overflow: auto;
+		z-index: 1;
 	}
 
 	.reveal .controls,
@@ -1884,20 +1885,16 @@ $notesWidthPercent: 25%;
 	}
 
 	.reveal {
-		display: flex;
-		justify-content: center;
-		width: auto !important;
-		height: auto !important;
-		overflow: visible !important;
+		overflow: visible;
 		touch-action: manipulation;
 	}
 	.reveal .slides {
 		position: static;
 		pointer-events: initial;
-		transform-origin: 50% 0;
 
 		left: auto;
 		top: auto;
+		width: 100% !important;
 		margin: 0 !important;
 		padding: 0 !important;
 
@@ -1909,34 +1906,40 @@ $notesWidthPercent: 25%;
 	}
 
 	.reveal .slides .reader-page {
-		display: grid;
-		place-items: center;
 		position: relative;
-		overflow: hidden;
+		width: 100%;
+		height: calc(var(--page-height) + var(--page-scroll-padding));
 		z-index: 1;
+		overflow: visible;
+	}
+
+	.reveal .slides .reader-page-sticky {
+		position: sticky;
+		height: var(--page-height);
+		top: 0px;
+	}
+
+	.reveal .slides .reader-page-content {
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
 	}
 
 	.reveal .slides .reader-page section {
 		visibility: visible !important;
 		display: block !important;
-		position: relative !important;
-		top: auto !important;
-
-		margin: 0 !important;
-		padding: 0 !important;
-		box-sizing: border-box !important;
-		min-height: 1px;
-
+		position: absolute !important;
+		top: 50% !important;
+		left: 50% !important;
 		opacity: 1 !important;
-
 		transform-style: flat !important;
-		transform: none !important;
+		transform-origin: 0 0 !important;
 	}
 
 	.reveal section.stack {
 		position: relative !important;
-		margin: 0 !important;
-		padding: 0 !important;
 		page-break-after: avoid !important;
 		height: auto !important;
 		min-height: auto !important;

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/reveal.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/reveal.esm.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/reveal.esm.js.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/reveal.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
dist/reveal.js.map


+ 11 - 0
js/config.js

@@ -256,6 +256,17 @@ export default {
 	parallaxBackgroundHorizontal: null,
 	parallaxBackgroundVertical: null,
 
+	// Can be used to initialize reveal.js in one of the following modes:
+	// - print:   Render the presentation so that it can be printed to PDF
+	// - reader:  Show the presentation as a tall scrollable page with scroll
+	//            triggered animations
+	mode: null,
+
+	// When the presentation is in reader mode, this controls whether each
+	// page should be as tall as the presentation viewport. Set this to false
+	// for a more compact layout with multiple slides visible at a time.
+	readerFullPageHeight: true,
+
 	// The maximum number of pages a single slide can expand onto when printing
 	// to PDF, unlimited by default
 	pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY,

+ 61 - 28
js/controllers/reader.js

@@ -47,7 +47,7 @@ export default class Reader {
 		await new Promise( requestAnimationFrame );
 		this.Reveal.layoutSlideContents( slideWidth, slideHeight );
 
-		const pages = [];
+		const pageElements = [];
 		const pageContainer = slides[0].parentNode;
 
 		// Slide and slide background layout
@@ -59,13 +59,11 @@ export default class Reader {
 				// Wrap the slide in a page element and hide its overflow
 				// so that no page ever flows onto another
 				const page = document.createElement( 'div' );
-				pages.push( page );
-
 				page.className = 'reader-page';
-				page.style.width = slideWidth + 'px';
-				page.style.height = slideHeight + 'px';
+				pageElements.push( page );
 
 				slide.style.width = slideWidth + 'px';
+				// slide.style.height = slideHeight + 'px';
 
 				// Copy the presentation-wide background to each individual
 				// page when printing
@@ -73,10 +71,18 @@ export default class Reader {
 					page.style.background = presentationBackground;
 				}
 
-				page.appendChild( slide );
+				const stickyContainer = document.createElement( 'div' );
+				stickyContainer.className = 'reader-page-sticky';
+				page.appendChild( stickyContainer );
+
+				const contentContainer = document.createElement( 'div' );
+				contentContainer.className = 'reader-page-content';
+				stickyContainer.appendChild( contentContainer );
+
+				contentContainer.appendChild( slide );
 
 				if( slide.slideBackgroundElement ) {
-					page.insertBefore( slide.slideBackgroundElement, slide );
+					contentContainer.insertBefore( slide.slideBackgroundElement, slide );
 				}
 
 			}
@@ -88,7 +94,7 @@ export default class Reader {
 
 		await new Promise( requestAnimationFrame );
 
-		pages.forEach( page => pageContainer.appendChild( page ) );
+		pageElements.forEach( page => pageContainer.appendChild( page ) );
 
 		// Re-run JS-based content layout after the slide is added to page DOM
 		this.Reveal.slideContent.layout( this.Reveal.getSlidesElement() );
@@ -144,41 +150,53 @@ export default class Reader {
 
 		const slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );
 		const scale = this.Reveal.getScale();
+		const fullPageHeight = this.Reveal.getConfig().readerFullPageHeight;
+
+		const pageHeight = fullPageHeight === true ? viewportHeight : slideSize.height * scale;
 
 		// The height that needs to be scrolled between scroll triggers
-		const scrollTriggerHeight = slideSize.height * scale / 2;
+		const scrollTriggerHeight = viewportHeight / 2;
 
-		this.pageElements = Array.from( this.Reveal.getRevealElement().querySelectorAll( '.reader-page' ) );
+		viewportElement.style.setProperty( '--page-height', pageHeight + 'px' );
 
-		this.pageMap = this.pageElements.map( pageElement => {
-			// pageElement.style.width = ( viewportElement.offsetWidth / scale ) + 'px';
-			// pageElement.style.height = ( viewportElement.offsetHeight / scale ) + 'px';
+		const pageElements = Array.from( this.Reveal.getRevealElement().querySelectorAll( '.reader-page' ) );
 
+		this.pages = pageElements.map( pageElement => {
 			const page = {
 				pageElement: pageElement,
+				stickyElement: pageElement.querySelector( '.reader-page-sticky' ),
 				slideElement: pageElement.querySelector( 'section' ),
-				top: pageElement.offsetTop * scale,
-				pageHeight: pageElement.offsetHeight * scale,
+				backgroundElement: pageElement.querySelector( '.slide-background' ),
+				top: pageElement.offsetTop,
+				pageHeight: pageHeight,
 				scrollTriggers: []
 			};
 
-			page.fragments = this.Reveal.fragments.sort( pageElement.querySelectorAll( '.fragment:not(.disabled)' ) );
-
 			// Each fragment 'group' is an array containing one or more
 			// fragments. Multiple fragments that appear at the same time
 			// are part of the same group.
+			page.fragments = this.Reveal.fragments.sort( pageElement.querySelectorAll( '.fragment:not(.disabled)' ) );
 			page.fragmentGroups = this.Reveal.fragments.sort( pageElement.querySelectorAll( '.fragment' ), true );
 
 			// The amount of empty scrollable space that has been append
-			page.scrollHeight = scrollTriggerHeight * Math.max( page.fragmentGroups.length - 1, 0 );
+			page.scrollPadding = scrollTriggerHeight * Math.max( page.fragmentGroups.length - 1, 0 );
+
+			// This variable is used to pad the height of our page in CSS
+			page.pageElement.style.setProperty( '--page-scroll-padding', page.scrollPadding + 'px' );
 
 			// The total height including scrollable space
-			page.totalHeight = page.pageHeight + page.scrollHeight;
+			page.totalHeight = page.pageHeight + page.scrollPadding;
 
 			page.bottom = page.top + page.totalHeight;
 
-			// Pad the page height to reserve scrollable height
-			page.pageElement.style.marginBottom = page.scrollHeight / scale + 'px';
+			// If this is a sticky page, stick it to the vertical center
+			if( page.scrollPadding > 0 ) {
+				page.stickyElement.style.position = 'sticky';
+				page.stickyElement.style.top = Math.max( ( viewportHeight - page.pageHeight ) / 2, 0 ) + 'px';
+			}
+			else {
+				page.stickyElement.style.position = 'relative';
+			}
 
 			// Create scroll triggers that show/hide fragments
 			if( page.fragmentGroups.length ) {
@@ -206,6 +224,14 @@ export default class Reader {
 	layout() {
 
 		this.generatePageMap();
+
+		const scale = this.Reveal.getScale();
+
+		this.pages.forEach( ( page ) => {
+			page.slideElement.style.transform = `scale(${scale}) translate(-50%, -50%)`;
+		} );
+
+
 		this.onScroll();
 
 	}
@@ -227,9 +253,8 @@ export default class Reader {
 		const viewportHeight = viewportElement.offsetHeight;
 
 		const scrollTop = viewportElement.scrollTop;
-		const scale = this.Reveal.getScale();
 
-		this.pageMap.forEach( ( page, i ) => {
+		this.pages.forEach( ( page ) => {
 			const isWithinPreloadRange = scrollTop + viewportHeight >= page.top - viewportHeight && scrollTop < page.top + page.bottom + viewportHeight;
 			const isPartiallyVisible = scrollTop + viewportHeight >= page.top && scrollTop < page.top + page.bottom;
 
@@ -249,23 +274,31 @@ export default class Reader {
 			if( isPartiallyVisible ) {
 				if( !page.playing ) {
 					page.playing = true;
+					page.pageElement.classList.add( 'present' );
+					page.slideElement.classList.add( 'present' );
 					this.Reveal.slideContent.startEmbeddedContent( page.slideElement );
+
+					if( page.backgroundElement ) {
+						this.Reveal.slideContent.startEmbeddedContent( page.backgroundElement );
+					}
 				}
 			}
 			else if( page.playing ) {
 				page.playing = false;
+				page.pageElement.classList.remove( 'present' );
+				page.slideElement.classList.remove( 'present' );
 				this.Reveal.slideContent.stopEmbeddedContent( page.slideElement );
+
+				if( page.backgroundElement ) {
+					this.Reveal.slideContent.stopEmbeddedContent( page.backgroundElement );
+				}
 			}
 
 			// Handle scroll freezing and triggers for slides in view
 			if( isPartiallyVisible && page.totalHeight > page.pageHeight ) {
-				let scrollProgress = ( scrollTop - page.top ) / page.scrollHeight;
+				let scrollProgress = ( scrollTop - page.top ) / page.scrollPadding;
 				scrollProgress = Math.max( Math.min( scrollProgress, 1 ), 0 );
 
-				// Fix the slide to the top of the viewport while we're in its
-				// scrollable region
-				page.pageElement.style.transform = `translateY( ${ scrollProgress * page.scrollHeight / scale }px )`;
-
 				page.scrollTriggers.forEach( trigger => {
 					if( scrollProgress >= trigger.range[0] && scrollProgress < trigger.range[1] ) {
 						if( !trigger.active ) {

+ 5 - 13
js/reveal.js

@@ -901,7 +901,7 @@ export default function( revealElement, options ) {
 
 				const size = reader.isActive() ?
 							 getComputedSlideSize( dom.viewport.offsetWidth, dom.viewport.offsetHeight ) :
-							 getComputedSlideSize();;
+							 getComputedSlideSize();
 
 				const oldScale = scale;
 
@@ -918,8 +918,9 @@ export default function( revealElement, options ) {
 				scale = Math.max( scale, config.minScale );
 				scale = Math.min( scale, config.maxScale );
 
-				// Don't apply any scaling styles if scale is 1
-				if( scale === 1 ) {
+				// Don't apply any scaling styles if scale is 1 or we're
+				// in reader mode
+				if( scale === 1 || reader.isActive() ) {
 					dom.slides.style.zoom = '';
 					dom.slides.style.left = '';
 					dom.slides.style.top = '';
@@ -927,15 +928,6 @@ export default function( revealElement, options ) {
 					dom.slides.style.right = '';
 					transformSlides( { layout: '' } );
 				}
-				else if( reader.isActive() ) {
-					dom.slides.style.zoom = '';
-					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 +')' } );
-				}
 				else {
 					dom.slides.style.zoom = '';
 					dom.slides.style.left = '50%';
@@ -956,7 +948,7 @@ export default function( revealElement, options ) {
 						continue;
 					}
 
-					if( ( config.center || slide.classList.contains( 'center' ) ) && !reader.isActive() ) {
+					if( ( config.center || slide.classList.contains( 'center' ) ) ) {
 						// Vertical stacks are not centred since their section
 						// children will be
 						if( slide.classList.contains( 'stack' ) ) {

Неке датотеке нису приказане због велике количине промена