瀏覽代碼

merge #2843 with minor tweaks

Hakim El Hattab 4 年之前
父節點
當前提交
892c752a4b
共有 6 個文件被更改,包括 74 次插入54 次删除
  1. 3 0
      demo.html
  2. 0 0
      dist/reveal.esm.js
  3. 0 0
      dist/reveal.js
  4. 19 19
      js/controllers/backgrounds.js
  5. 46 33
      js/controllers/print.js
  6. 6 2
      js/reveal.js

+ 3 - 0
demo.html

@@ -458,6 +458,9 @@ Reveal.on( 'customevent', function() {
 		<script src="plugin/highlight/highlight.js"></script>
 		<script>
 
+			console.time( 'print' )
+			Reveal.addEventListener( 'pdf-ready', () => console.timeEnd( 'print' ) );
+
 			// Also available as an ES module, see:
 			// https://revealjs.com/initialization/
 			Reveal.initialize({

文件差異過大導致無法顯示
+ 0 - 0
dist/reveal.esm.js


文件差異過大導致無法顯示
+ 0 - 0
dist/reveal.js


+ 19 - 19
js/controllers/backgrounds.js

@@ -27,8 +27,6 @@ export default class Backgrounds {
 	 */
 	create() {
 
-		let printMode = this.Reveal.isPrintingPDF();
-
 		// Clear prior backgrounds
 		this.element.innerHTML = '';
 		this.element.classList.add( 'no-transition' );
@@ -114,9 +112,24 @@ export default class Backgrounds {
 	 */
 	sync( slide ) {
 
-		let element = slide.slideBackgroundElement,
+		const element = slide.slideBackgroundElement,
 			contentElement = slide.slideBackgroundContentElement;
 
+		const data = {
+			background: slide.getAttribute( 'data-background' ),
+			backgroundSize: slide.getAttribute( 'data-background-size' ),
+			backgroundImage: slide.getAttribute( 'data-background-image' ),
+			backgroundVideo: slide.getAttribute( 'data-background-video' ),
+			backgroundIframe: slide.getAttribute( 'data-background-iframe' ),
+			backgroundColor: slide.getAttribute( 'data-background-color' ),
+			backgroundRepeat: slide.getAttribute( 'data-background-repeat' ),
+			backgroundPosition: slide.getAttribute( 'data-background-position' ),
+			backgroundTransition: slide.getAttribute( 'data-background-transition' ),
+			backgroundOpacity: slide.getAttribute( 'data-background-opacity' ),
+		};
+
+		const dataPreload = slide.hasAttribute( 'data-preload' );
+
 		// Reset the prior background state in case this is not the
 		// initial sync
 		slide.classList.remove( 'has-dark-background' );
@@ -135,19 +148,6 @@ export default class Backgrounds {
 		contentElement.style.opacity = '';
 		contentElement.innerHTML = '';
 
-		let data = {
-			background: slide.getAttribute( 'data-background' ),
-			backgroundSize: slide.getAttribute( 'data-background-size' ),
-			backgroundImage: slide.getAttribute( 'data-background-image' ),
-			backgroundVideo: slide.getAttribute( 'data-background-video' ),
-			backgroundIframe: slide.getAttribute( 'data-background-iframe' ),
-			backgroundColor: slide.getAttribute( 'data-background-color' ),
-			backgroundRepeat: slide.getAttribute( 'data-background-repeat' ),
-			backgroundPosition: slide.getAttribute( 'data-background-position' ),
-			backgroundTransition: slide.getAttribute( 'data-background-transition' ),
-			backgroundOpacity: slide.getAttribute( 'data-background-opacity' )
-		};
-
 		if( data.background ) {
 			// Auto-wrap image urls in url(...)
 			if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)([?#\s]|$)/gi.test( data.background ) ) {
@@ -179,7 +179,7 @@ export default class Backgrounds {
 		if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor;
 		if( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition );
 
-		if( slide.hasAttribute( 'data-preload' ) ) element.setAttribute( 'data-preload', '' );
+		if( dataPreload ) element.setAttribute( 'data-preload', '' );
 
 		// Background image options are set on the content wrapper
 		if( data.backgroundSize ) contentElement.style.backgroundSize = data.backgroundSize;
@@ -201,7 +201,7 @@ export default class Backgrounds {
 		}
 
 		if( contrastColor ) {
-			let rgb = colorToRgb( contrastColor );
+			const rgb = colorToRgb( contrastColor );
 
 			// Ignore fully transparent backgrounds. Some browsers return
 			// rgba(0,0,0,0) when reading the computed background color of
@@ -394,4 +394,4 @@ export default class Backgrounds {
 
 	}
 
-}
+}

+ 46 - 33
js/controllers/print.js

@@ -16,20 +16,26 @@ export default class Print {
 	 * Configures the presentation for printing to a static
 	 * PDF.
 	 */
-	setupPDF() {
+	async setupPDF() {
 
-		let config = this.Reveal.getConfig();
+		const config = this.Reveal.getConfig();
+		const slides = queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR )
 
-		let slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );
+		// Compute slide numbers now, before we start duplicating slides
+		const doingSlideNumbers = config.slideNumber && /all|print/i.test( config.showSlideNumber );
+
+		const slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );
 
 		// Dimensions of the PDF pages
-		let pageWidth = Math.floor( slideSize.width * ( 1 + config.margin ) ),
+		const pageWidth = Math.floor( slideSize.width * ( 1 + config.margin ) ),
 			pageHeight = Math.floor( slideSize.height * ( 1 + config.margin ) );
 
 		// Dimensions of slides within the pages
-		let slideWidth = slideSize.width,
+		const slideWidth = slideSize.width,
 			slideHeight = slideSize.height;
 
+		await new Promise( requestAnimationFrame );
+
 		// Let the browser know what page size we want to print
 		createStyleSheet( '@page{size:'+ pageWidth +'px '+ pageHeight +'px; margin: 0px;}' );
 
@@ -41,29 +47,32 @@ export default class Print {
 		document.body.style.height = pageHeight + 'px';
 
 		// Make sure stretch elements fit on slide
+		await new Promise( requestAnimationFrame );
 		this.Reveal.layoutSlideContents( slideWidth, slideHeight );
 
-		// Compute slide numbers now, before we start duplicating slides
-		let doingSlideNumbers = config.slideNumber && /all|print/i.test( config.showSlideNumber );
-		queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( function( slide ) {
-			slide.setAttribute( 'data-slide-number', this.Reveal.slideNumber.getSlideNumber( slide ) );
-		}, this );
+		// Re-run the slide layout so that r-fit-text is applied based on
+		// the printed slide size
+		slides.forEach( slide => this.Reveal.slideContent.layout( slide ) );
+
+		// Batch scrollHeight access to prevent layout thrashing
+		await new Promise( requestAnimationFrame );
+
+		const slideScrollHeights = slides.map( slide => slide.scrollHeight );
+
+		const pages = [];
+		const pageContainer = slides[0].parentNode;
 
 		// Slide and slide background layout
-		queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( function( slide ) {
+		slides.forEach( function( slide, index ) {
 
 			// Vertical stacks are not centred since their section
 			// children will be
 			if( slide.classList.contains( 'stack' ) === false ) {
 				// Center the slide inside of the page, giving the slide some margin
-				let left = ( pageWidth - slideWidth ) / 2,
-					top = ( pageHeight - slideHeight ) / 2;
-
-				// Re-run the slide layout so that r-fit-text is applied based on
-				// the printed slide size
-				this.Reveal.slideContent.layout( slide );
+				let left = ( pageWidth - slideWidth ) / 2;
+				let top = ( pageHeight - slideHeight ) / 2;
 
-				let contentHeight = slide.scrollHeight;
+				const contentHeight = slideScrollHeights[ index ];
 				let numberOfPages = Math.max( Math.ceil( contentHeight / pageHeight ), 1 );
 
 				// Adhere to configured pages per slide limit
@@ -76,10 +85,11 @@ export default class Print {
 
 				// Wrap the slide in a page element and hide its overflow
 				// so that no page ever flows onto another
-				let page = document.createElement( 'div' );
+				const page = document.createElement( 'div' );
+				pages.push( page );
+
 				page.className = 'pdf-page';
 				page.style.height = ( ( pageHeight + config.pdfPageHeightOffset ) * numberOfPages ) + 'px';
-				slide.parentNode.insertBefore( page, slide );
 				page.appendChild( slide );
 
 				// Position the slide inside of the page
@@ -95,19 +105,19 @@ export default class Print {
 				if( config.showNotes ) {
 
 					// Are there notes for this slide?
-					let notes = this.Reveal.getSlideNotes( slide );
+					const notes = this.Reveal.getSlideNotes( slide );
 					if( notes ) {
 
-						let notesSpacing = 8;
-						let notesLayout = typeof config.showNotes === 'string' ? config.showNotes : 'inline';
-						let notesElement = document.createElement( 'div' );
+						const notesSpacing = 8;
+						const notesLayout = typeof config.showNotes === 'string' ? config.showNotes : 'inline';
+						const notesElement = document.createElement( 'div' );
 						notesElement.classList.add( 'speaker-notes' );
 						notesElement.classList.add( 'speaker-notes-pdf' );
 						notesElement.setAttribute( 'data-layout', notesLayout );
 						notesElement.innerHTML = notes;
 
 						if( notesLayout === 'separate-page' ) {
-							page.parentNode.insertBefore( notesElement, page.nextSibling );
+							pages.push( notesElement );
 						}
 						else {
 							notesElement.style.left = notesSpacing + 'px';
@@ -122,10 +132,11 @@ export default class Print {
 
 				// Inject slide numbers if `slideNumbers` are enabled
 				if( doingSlideNumbers ) {
-					let numberElement = document.createElement( 'div' );
+					const slideNumber = index + 1;
+					const numberElement = document.createElement( 'div' );
 					numberElement.classList.add( 'slide-number' );
 					numberElement.classList.add( 'slide-number-pdf' );
-					numberElement.innerHTML = slide.getAttribute( 'data-slide-number' );
+					numberElement.innerHTML = slideNumber;
 					page.appendChild( numberElement );
 				}
 
@@ -135,10 +146,9 @@ export default class Print {
 					// 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.
-					let fragmentGroups = this.Reveal.fragments.sort( page.querySelectorAll( '.fragment' ), true );
+					const fragmentGroups = this.Reveal.fragments.sort( page.querySelectorAll( '.fragment' ), true );
 
 					let previousFragmentStep;
-					let previousPage;
 
 					fragmentGroups.forEach( function( fragments ) {
 
@@ -155,11 +165,10 @@ export default class Print {
 						}, this );
 
 						// Create a separate page for the current fragment state
-						let clonedPage = page.cloneNode( true );
-						page.parentNode.insertBefore( clonedPage, ( previousPage || page ).nextSibling );
+						const clonedPage = page.cloneNode( true );
+						pages.push( clonedPage );
 
 						previousFragmentStep = fragments;
-						previousPage = clonedPage;
 
 					}, this );
 
@@ -182,6 +191,10 @@ export default class Print {
 
 		}, this );
 
+		await new Promise( requestAnimationFrame );
+
+		pages.forEach( page => pageContainer.appendChild( page ) );
+
 		// Notify subscribers that the PDF layout is good to go
 		this.Reveal.dispatchEvent({ type: 'pdf-ready' });
 
@@ -196,4 +209,4 @@ export default class Print {
 
 	}
 
-}
+}

+ 6 - 2
js/reveal.js

@@ -1335,7 +1335,11 @@ export default function( revealElement, options ) {
 		}
 
 		// Announce the current slide contents to screen readers
-		announceStatus( getStatusText( currentSlide ) );
+		// Use animation frame to prevent getComputedStyle in getStatusText
+		// from triggering layout mid-frame
+		requestAnimationFrame( () => {
+			announceStatus( getStatusText( currentSlide ) );
+		});
 
 		progress.update();
 		controls.update();
@@ -2290,7 +2294,7 @@ export default function( revealElement, options ) {
 			// When looping is enabled `routes.down` is always available
 			// so we need a separate check for when we've reached the
 			// end of a stack and should move horizontally
-			if( routes.down && routes.right && config.loop && isLastVerticalSlide( currentSlide ) ) {
+			if( routes.down && routes.right && config.loop && isLastVerticalSlide() ) {
 				routes.down = false;
 			}
 

部分文件因文件數量過多而無法顯示