Merge branch 'feature/print' into dev
This commit is contained in:
		| @@ -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). | 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. | 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). | 2. Open the in-browser print dialog (CMD+P). | ||||||
| 3. Change the **Destination** setting to **Save as PDF**. | 3. Change the **Destination** setting to **Save as PDF**. | ||||||
| 4. Change the **Layout** to **Landscape**. | 4. Change the **Layout** to **Landscape**. | ||||||
|   | |||||||
| @@ -17,8 +17,6 @@ | |||||||
|  |  | ||||||
| body { | body { | ||||||
| 	font-size: 18pt; | 	font-size: 18pt; | ||||||
| 	width: 297mm; |  | ||||||
| 	height: 229mm; |  | ||||||
| 	margin: 0 auto !important; | 	margin: 0 auto !important; | ||||||
| 	border: 0; | 	border: 0; | ||||||
| 	padding: 0; | 	padding: 0; | ||||||
| @@ -105,8 +103,6 @@ ul, ol, div, p { | |||||||
| 	overflow: visible; | 	overflow: visible; | ||||||
| 	display: block; | 	display: block; | ||||||
|  |  | ||||||
| 	text-align: center; |  | ||||||
|  |  | ||||||
| 	-webkit-perspective: none; | 	-webkit-perspective: none; | ||||||
| 	   -moz-perspective: none; | 	   -moz-perspective: none; | ||||||
| 	    -ms-perspective: none; | 	    -ms-perspective: none; | ||||||
| @@ -118,21 +114,15 @@ ul, ol, div, p { | |||||||
| 	        perspective-origin: 50% 50%; | 	        perspective-origin: 50% 50%; | ||||||
| } | } | ||||||
| .reveal .slides section { | .reveal .slides section { | ||||||
|  |  | ||||||
| 	page-break-after: always !important; | 	page-break-after: always !important; | ||||||
|  |  | ||||||
| 	visibility: visible !important; | 	visibility: visible !important; | ||||||
| 	position: relative !important; | 	position: relative !important; | ||||||
| 	width: 100% !important; |  | ||||||
| 	height: 229mm !important; |  | ||||||
| 	min-height: 229mm !important; |  | ||||||
| 	display: block !important; | 	display: block !important; | ||||||
| 	overflow: hidden !important; | 	position: relative !important; | ||||||
|  |  | ||||||
| 	left: 0 !important; |  | ||||||
| 	top: 0 !important; |  | ||||||
| 	margin: 0 !important; | 	margin: 0 !important; | ||||||
| 	padding: 2cm 2cm 0 2cm !important; | 	padding: 0 !important; | ||||||
| 	box-sizing: border-box !important; | 	box-sizing: border-box !important; | ||||||
|  |  | ||||||
| 	opacity: 1 !important; | 	opacity: 1 !important; | ||||||
| @@ -154,30 +144,6 @@ ul, ol, div, p { | |||||||
| 	height: auto !important; | 	height: auto !important; | ||||||
| 	min-height: auto !important; | 	min-height: auto !important; | ||||||
| } | } | ||||||
| .reveal .absolute-element { |  | ||||||
| 	margin-left: 2.2cm; |  | ||||||
| 	margin-top: 1.8cm; |  | ||||||
| } |  | ||||||
| .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 section .slide-background { |  | ||||||
| 	position: absolute; |  | ||||||
| 	top: 0; |  | ||||||
| 	left: 0; |  | ||||||
| 	width: 100%; |  | ||||||
| 	z-index: 0; |  | ||||||
| } |  | ||||||
| .reveal section>* { |  | ||||||
| 	position: relative; |  | ||||||
| 	z-index: 1; |  | ||||||
| } |  | ||||||
| .reveal img { | .reveal img { | ||||||
| 	box-shadow: none; | 	box-shadow: none; | ||||||
| } | } | ||||||
| @@ -189,11 +155,17 @@ ul, ol, div, p { | |||||||
| 	font-size: 16pt !important; | 	font-size: 16pt !important; | ||||||
| } | } | ||||||
|  |  | ||||||
| .reveal.center .slides section:not(.stack) { | /* Slide backgrounds are placed inside of their slide when exporting to PDF */ | ||||||
| 	display: flex !important; | .reveal section .slide-background { | ||||||
| 	flex-direction: column; | 	position: absolute; | ||||||
| 	align-items: center; | 	top: 0; | ||||||
| 	justify-content: center; | 	left: 0; | ||||||
| 	padding-top: 2em !important; | 	width: 100%; | ||||||
| 	padding-bottom: 2em !important; | 	z-index: 0; | ||||||
| } | } | ||||||
|  | /* All elements should be above the slide-background */ | ||||||
|  | .reveal section>* { | ||||||
|  | 	position: relative; | ||||||
|  | 	z-index: 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1328,6 +1328,8 @@ body { | |||||||
| 	position: absolute; | 	position: absolute; | ||||||
| 	width: 100%; | 	width: 100%; | ||||||
| 	height: 100%; | 	height: 100%; | ||||||
|  | 	top: 0; | ||||||
|  | 	left: 0; | ||||||
|  |  | ||||||
| 	-webkit-perspective: 600px; | 	-webkit-perspective: 600px; | ||||||
| 	   -moz-perspective: 600px; | 	   -moz-perspective: 600px; | ||||||
|   | |||||||
							
								
								
									
										150
									
								
								js/reveal.js
									
									
									
									
									
								
							
							
						
						
									
										150
									
								
								js/reveal.js
									
									
									
									
									
								
							| @@ -333,6 +333,12 @@ var Reveal = (function(){ | |||||||
| 		// Update all backgrounds | 		// Update all backgrounds | ||||||
| 		updateBackground( true ); | 		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 | 		// Notify listeners that the presentation is ready but use a 1ms | ||||||
| 		// timeout to ensure it's not fired synchronously after #initialize() | 		// timeout to ensure it's not fired synchronously after #initialize() | ||||||
| 		setTimeout( function() { | 		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. | 	 * Creates an HTML element and returns a reference to it. | ||||||
| 	 * If the element already exists the existing instance will | 	 * If the element already exists the existing instance will | ||||||
| @@ -428,9 +502,7 @@ var Reveal = (function(){ | |||||||
| 	 */ | 	 */ | ||||||
| 	function createBackgrounds() { | 	function createBackgrounds() { | ||||||
|  |  | ||||||
| 		if( isPrintingPDF() ) { | 		var printMode = isPrintingPDF(); | ||||||
| 			document.body.classList.add( 'print-pdf' ); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Clear prior backgrounds | 		// Clear prior backgrounds | ||||||
| 		dom.background.innerHTML = ''; | 		dom.background.innerHTML = ''; | ||||||
| @@ -441,7 +513,7 @@ var Reveal = (function(){ | |||||||
|  |  | ||||||
| 			var backgroundStack; | 			var backgroundStack; | ||||||
|  |  | ||||||
| 			if( isPrintingPDF() ) { | 			if( printMode ) { | ||||||
| 				backgroundStack = createBackground( slideh, slideh ); | 				backgroundStack = createBackground( slideh, slideh ); | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
| @@ -451,7 +523,7 @@ var Reveal = (function(){ | |||||||
| 			// Iterate over all vertical slides | 			// Iterate over all vertical slides | ||||||
| 			toArray( slideh.querySelectorAll( 'section' ) ).forEach( function( slidev ) { | 			toArray( slideh.querySelectorAll( 'section' ) ).forEach( function( slidev ) { | ||||||
|  |  | ||||||
| 				if( isPrintingPDF() ) { | 				if( printMode ) { | ||||||
| 					createBackground( slidev, slidev ); | 					createBackground( slidev, slidev ); | ||||||
| 				} | 				} | ||||||
| 				else { | 				else { | ||||||
| @@ -887,7 +959,7 @@ var Reveal = (function(){ | |||||||
|  |  | ||||||
| 				if( typeof child.offsetTop === 'number' && child.style ) { | 				if( typeof child.offsetTop === 'number' && child.style ) { | ||||||
| 					// Count # of abs children | 					// Count # of abs children | ||||||
| 					if( child.style.position === 'absolute' ) { | 					if( window.getComputedStyle( child ).position === 'absolute' ) { | ||||||
| 						absoluteChildren += 1; | 						absoluteChildren += 1; | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| @@ -1124,37 +1196,18 @@ var Reveal = (function(){ | |||||||
|  |  | ||||||
| 		if( dom.wrapper && !isPrintingPDF() ) { | 		if( dom.wrapper && !isPrintingPDF() ) { | ||||||
|  |  | ||||||
| 			// Available space to scale within | 			var size = getComputedSlideSize(); | ||||||
| 			var availableWidth = dom.wrapper.offsetWidth, |  | ||||||
| 				availableHeight = dom.wrapper.offsetHeight; |  | ||||||
|  |  | ||||||
| 			// Reduce available space by margin | 			var slidePadding = 20; // TODO Dig this out of DOM | ||||||
| 			availableWidth -= ( availableHeight * config.margin ); |  | ||||||
| 			availableHeight -= ( availableHeight * config.margin ); |  | ||||||
|  |  | ||||||
| 			// Dimensions of the content |  | ||||||
| 			var slideWidth = config.width, |  | ||||||
| 				slideHeight = config.height, |  | ||||||
| 				slidePadding = 20; // TODO Dig this out of DOM |  | ||||||
|  |  | ||||||
| 			// Layout the contents of the slides | 			// Layout the contents of the slides | ||||||
| 			layoutSlideContents( config.width, config.height, slidePadding ); | 			layoutSlideContents( config.width, config.height, slidePadding ); | ||||||
|  |  | ||||||
| 			// Slide width may be a percentage of available width | 			dom.slides.style.width = size.width + 'px'; | ||||||
| 			if( typeof slideWidth === 'string' && /%$/.test( slideWidth ) ) { | 			dom.slides.style.height = size.height + 'px'; | ||||||
| 				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'; |  | ||||||
|  |  | ||||||
| 			// Determine scale of content to fit within available space | 			// 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 | 			// Respect max/min scale settings | ||||||
| 			scale = Math.max( scale, config.minScale ); | 			scale = Math.max( scale, config.minScale ); | ||||||
| @@ -1191,7 +1244,7 @@ var Reveal = (function(){ | |||||||
| 						slide.style.top = 0; | 						slide.style.top = 0; | ||||||
| 					} | 					} | ||||||
| 					else { | 					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 { | 				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 | 	 * Stores the vertical index of a stack so that the same | ||||||
| 	 * vertical slide can be selected when navigating to and | 	 * vertical slide can be selected when navigating to and | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user