Skip to content

Commit

Permalink
merge hakimel#2843 with minor tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
hakimel committed May 5, 2021
2 parents b1faa20 + 5121b2b commit c8b7796
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 56 deletions.
3 changes: 3 additions & 0 deletions demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ <h1>THE END</h1>
<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({
Expand Down
2 changes: 1 addition & 1 deletion dist/reveal.esm.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/reveal.js

Large diffs are not rendered by default.

38 changes: 19 additions & 19 deletions js/controllers/backgrounds.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
Expand Down Expand Up @@ -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' );
Expand All @@ -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 ) ) {
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -394,4 +394,4 @@ export default class Backgrounds {

}

}
}
79 changes: 46 additions & 33 deletions js/controllers/print.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;}' );

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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';
Expand All @@ -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 );
}

Expand All @@ -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 ) {

Expand All @@ -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 );

Expand All @@ -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' });

Expand All @@ -196,4 +209,4 @@ export default class Print {

}

}
}
8 changes: 6 additions & 2 deletions js/reveal.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit c8b7796

Please sign in to comment.