Эх сурвалжийг харах

Merge branch 'feature/print' into dev

Hakim El Hattab 11 жил өмнө
parent
commit
b019604531
4 өөрчлөгдсөн 135 нэмэгдсэн , 73 устгасан
  1. 1 1
      README.md
  2. 13 41
      css/print/pdf.css
  3. 2 0
      css/reveal.css
  4. 119 31
      js/reveal.js

+ 1 - 1
README.md

@@ -585,7 +585,7 @@ Limitations:
 Presentations can be exported to PDF via a special print stylesheet. This feature requires that you use [Google Chrome](http://google.com/chrome).
 Here's an example of an exported presentation that's been uploaded to SlideShare: http://www.slideshare.net/hakimel/revealjs-13872948.
 
-1. Open your presentation with [css/print/pdf.css](https://github.com/hakimel/reveal.js/blob/master/css/print/pdf.css) included on the page. The default index HTML lets you add *print-pdf* anywhere in the query to include the stylesheet, for example: [lab.hakim.se/reveal-js?print-pdf](http://lab.hakim.se/reveal-js?print-pdf).
+1. Open your presentation with `print-pdf` included anywhere in the query string. This triggers the default index HTML to load the PDF print stylesheet ([css/print/pdf.css](https://github.com/hakimel/reveal.js/blob/master/css/print/pdf.css)). You can test this with [lab.hakim.se/reveal-js?print-pdf](http://lab.hakim.se/reveal-js?print-pdf).
 2. Open the in-browser print dialog (CMD+P).
 3. Change the **Destination** setting to **Save as PDF**.
 4. Change the **Layout** to **Landscape**.

+ 13 - 41
css/print/pdf.css

@@ -17,8 +17,6 @@
 
 body {
 	font-size: 18pt;
-	width: 297mm;
-	height: 229mm;
 	margin: 0 auto !important;
 	border: 0;
 	padding: 0;
@@ -105,8 +103,6 @@ ul, ol, div, p {
 	overflow: visible;
 	display: block;
 
-	text-align: center;
-
 	-webkit-perspective: none;
 	   -moz-perspective: none;
 	    -ms-perspective: none;
@@ -118,21 +114,15 @@ ul, ol, div, p {
 	        perspective-origin: 50% 50%;
 }
 .reveal .slides section {
-
 	page-break-after: always !important;
 
 	visibility: visible !important;
 	position: relative !important;
-	width: 100% !important;
-	height: 229mm !important;
-	min-height: 229mm !important;
 	display: block !important;
-	overflow: hidden !important;
+	position: relative !important;
 
-	left: 0 !important;
-	top: 0 !important;
 	margin: 0 !important;
-	padding: 2cm 2cm 0 2cm !important;
+	padding: 0 !important;
 	box-sizing: border-box !important;
 
 	opacity: 1 !important;
@@ -154,19 +144,18 @@ ul, ol, div, p {
 	height: auto !important;
 	min-height: auto !important;
 }
-.reveal .absolute-element {
-	margin-left: 2.2cm;
-	margin-top: 1.8cm;
+.reveal img {
+	box-shadow: none;
 }
-.reveal section .fragment {
-	opacity: 1 !important;
-	visibility: visible !important;
-
-	-webkit-transform: none !important;
-	   -moz-transform: none !important;
-	    -ms-transform: none !important;
-	        transform: none !important;
+.reveal .roll {
+	overflow: visible;
+	line-height: 1em;
+}
+.reveal small a {
+	font-size: 16pt !important;
 }
+
+/* Slide backgrounds are placed inside of their slide when exporting to PDF */
 .reveal section .slide-background {
 	position: absolute;
 	top: 0;
@@ -174,26 +163,9 @@ ul, ol, div, p {
 	width: 100%;
 	z-index: 0;
 }
+/* All elements should be above the slide-background */
 .reveal section>* {
 	position: relative;
 	z-index: 1;
 }
-.reveal img {
-	box-shadow: none;
-}
-.reveal .roll {
-	overflow: visible;
-	line-height: 1em;
-}
-.reveal small a {
-	font-size: 16pt !important;
-}
 
-.reveal.center .slides section:not(.stack) {
-	display: flex !important;
-	flex-direction: column;
-	align-items: center;
-	justify-content: center;
-	padding-top: 2em !important;
-	padding-bottom: 2em !important;
-}

+ 2 - 0
css/reveal.css

@@ -1328,6 +1328,8 @@ body {
 	position: absolute;
 	width: 100%;
 	height: 100%;
+	top: 0;
+	left: 0;
 
 	-webkit-perspective: 600px;
 	   -moz-perspective: 600px;

+ 119 - 31
js/reveal.js

@@ -333,6 +333,12 @@ var Reveal = (function(){
 		// Update all backgrounds
 		updateBackground( true );
 
+		// Special setup and config is required when printing to PDF
+		if( isPrintingPDF() ) {
+			removeEventListeners();
+			setupPDF();
+		}
+
 		// Notify listeners that the presentation is ready but use a 1ms
 		// timeout to ensure it's not fired synchronously after #initialize()
 		setTimeout( function() {
@@ -401,6 +407,74 @@ var Reveal = (function(){
 
 	}
 
+	/**
+	 * Configures the presentation for printing to a static
+	 * PDF.
+	 */
+	function setupPDF() {
+
+		// The aspect ratio of pages when saving to PDF in Chrome,
+		// we need to abide by this ratio when determining the pixel
+		// size of our pages
+		var pageAspectRatio = 1.295;
+
+		var slideSize = getComputedSlideSize( window.innerWidth, window.innerHeight );
+
+		// Dimensions of the PDF pages
+		var pageWidth = Math.round( slideSize.width * ( 1 + config.margin ) ),
+			pageHeight = Math.round( pageWidth / pageAspectRatio );
+
+		// Dimensions of slides within the pages
+		var slideWidth = slideSize.width,
+			slideHeight = slideSize.height;
+
+		document.body.classList.add( 'print-pdf' );
+		document.body.style.width = pageWidth + 'px';
+		document.body.style.height = pageHeight + 'px';
+
+		// Slide and slide background layout
+		toArray( document.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) {
+
+			// 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
+				var left = ( pageWidth - slideWidth ) / 2,
+					top = ( pageHeight - slideHeight ) / 2;
+
+				var contentHeight = getAbsoluteHeight( slide );
+				var numberOfPages = Math.ceil( contentHeight / pageHeight );
+
+				// Center slides vertically
+				if( numberOfPages === 1 && config.center || slide.classList.contains( 'center' ) ) {
+					top = Math.max( ( pageHeight - contentHeight ) / 2, 0 );
+				}
+
+				// Position the slide inside of the page
+				slide.style.left = left + 'px';
+				slide.style.top = top + 'px';
+				slide.style.width = slideWidth + 'px';
+
+				// TODO Backgrounds need to be multiplied when the slide
+				// stretches over multiple pages
+				var background = slide.querySelector( '.slide-background' );
+				if( background ) {
+					background.style.width = pageWidth + 'px';
+					background.style.height = ( pageHeight * numberOfPages ) + 'px';
+					background.style.top = -top + 'px';
+					background.style.left = -left + 'px';
+				}
+			}
+
+		} );
+
+		// Show all fragments
+		toArray( document.querySelectorAll( SLIDES_SELECTOR + ' .fragment' ) ).forEach( function( fragment ) {
+			fragment.classList.add( 'visible' );
+		} );
+
+	}
+
 	/**
 	 * Creates an HTML element and returns a reference to it.
 	 * If the element already exists the existing instance will
@@ -428,9 +502,7 @@ var Reveal = (function(){
 	 */
 	function createBackgrounds() {
 
-		if( isPrintingPDF() ) {
-			document.body.classList.add( 'print-pdf' );
-		}
+		var printMode = isPrintingPDF();
 
 		// Clear prior backgrounds
 		dom.background.innerHTML = '';
@@ -441,7 +513,7 @@ var Reveal = (function(){
 
 			var backgroundStack;
 
-			if( isPrintingPDF() ) {
+			if( printMode ) {
 				backgroundStack = createBackground( slideh, slideh );
 			}
 			else {
@@ -451,7 +523,7 @@ var Reveal = (function(){
 			// Iterate over all vertical slides
 			toArray( slideh.querySelectorAll( 'section' ) ).forEach( function( slidev ) {
 
-				if( isPrintingPDF() ) {
+				if( printMode ) {
 					createBackground( slidev, slidev );
 				}
 				else {
@@ -887,7 +959,7 @@ var Reveal = (function(){
 
 				if( typeof child.offsetTop === 'number' && child.style ) {
 					// Count # of abs children
-					if( child.style.position === 'absolute' ) {
+					if( window.getComputedStyle( child ).position === 'absolute' ) {
 						absoluteChildren += 1;
 					}
 
@@ -1124,37 +1196,18 @@ var Reveal = (function(){
 
 		if( dom.wrapper && !isPrintingPDF() ) {
 
-			// Available space to scale within
-			var availableWidth = dom.wrapper.offsetWidth,
-				availableHeight = dom.wrapper.offsetHeight;
-
-			// Reduce available space by margin
-			availableWidth -= ( availableHeight * config.margin );
-			availableHeight -= ( availableHeight * config.margin );
+			var size = getComputedSlideSize();
 
-			// Dimensions of the content
-			var slideWidth = config.width,
-				slideHeight = config.height,
-				slidePadding = 20; // TODO Dig this out of DOM
+			var slidePadding = 20; // TODO Dig this out of DOM
 
 			// Layout the contents of the slides
 			layoutSlideContents( config.width, config.height, slidePadding );
 
-			// Slide width may be a percentage of available width
-			if( typeof slideWidth === 'string' && /%$/.test( slideWidth ) ) {
-				slideWidth = parseInt( slideWidth, 10 ) / 100 * availableWidth;
-			}
-
-			// Slide height may be a percentage of available height
-			if( typeof slideHeight === 'string' && /%$/.test( slideHeight ) ) {
-				slideHeight = parseInt( slideHeight, 10 ) / 100 * availableHeight;
-			}
-
-			dom.slides.style.width = slideWidth + 'px';
-			dom.slides.style.height = slideHeight + 'px';
+			dom.slides.style.width = size.width + 'px';
+			dom.slides.style.height = size.height + 'px';
 
 			// Determine scale of content to fit within available space
-			scale = Math.min( availableWidth / slideWidth, availableHeight / slideHeight );
+			scale = Math.min( size.presentationWidth / size.width, size.presentationHeight / size.height );
 
 			// Respect max/min scale settings
 			scale = Math.max( scale, config.minScale );
@@ -1191,7 +1244,7 @@ var Reveal = (function(){
 						slide.style.top = 0;
 					}
 					else {
-						slide.style.top = Math.max( ( ( slideHeight - getAbsoluteHeight( slide ) ) / 2 ) - slidePadding, 0 ) + 'px';
+						slide.style.top = Math.max( ( ( size.height - getAbsoluteHeight( slide ) ) / 2 ) - slidePadding, 0 ) + 'px';
 					}
 				}
 				else {
@@ -1239,6 +1292,41 @@ var Reveal = (function(){
 
 	}
 
+	/**
+	 * Calculates the computed pixel size of our slides. These
+	 * values are based on the width and height configuration
+	 * options.
+	 */
+	function getComputedSlideSize( presentationWidth, presentationHeight ) {
+
+		var size = {
+			// Slide size
+			width: config.width,
+			height: config.height,
+
+			// Presentation size
+			presentationWidth: presentationWidth || dom.wrapper.offsetWidth,
+			presentationHeight: presentationHeight || dom.wrapper.offsetHeight
+		};
+
+		// Reduce available space by margin
+		size.presentationWidth -= ( size.presentationHeight * config.margin );
+		size.presentationHeight -= ( size.presentationHeight * config.margin );
+
+		// Slide width may be a percentage of available width
+		if( typeof size.width === 'string' && /%$/.test( size.width ) ) {
+			size.width = parseInt( size.width, 10 ) / 100 * size.presentationWidth;
+		}
+
+		// Slide height may be a percentage of available height
+		if( typeof size.height === 'string' && /%$/.test( size.height ) ) {
+			size.height = parseInt( size.height, 10 ) / 100 * size.presentationHeight;
+		}
+
+		return size;
+
+	}
+
 	/**
 	 * Stores the vertical index of a stack so that the same
 	 * vertical slide can be selected when navigating to and