mirror of
https://github.com/hakimel/reveal.js.git
synced 2025-08-06 14:47:04 +02:00
reader mode; named deeplink support, stay on same slide when reader mode is turned on/off
This commit is contained in:
2
dist/reveal.esm.js
vendored
2
dist/reveal.esm.js
vendored
File diff suppressed because one or more lines are too long
2
dist/reveal.esm.js.map
vendored
2
dist/reveal.esm.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/reveal.js
vendored
2
dist/reveal.js
vendored
File diff suppressed because one or more lines are too long
2
dist/reveal.js.map
vendored
2
dist/reveal.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -54,7 +54,7 @@
|
|||||||
<li class="fragment">Fragment three</li>
|
<li class="fragment">Fragment three</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section data-background-gradient="linear-gradient(to bottom, #283b95, #17b2c3)">
|
<section data-background-gradient="linear-gradient(to bottom, #283b95, #17b2c3)" id="gradient-bg">
|
||||||
<h2>Gradient Backgrounds</h2>
|
<h2>Gradient Backgrounds</h2>
|
||||||
</section>
|
</section>
|
||||||
<section data-auto-animate>
|
<section data-auto-animate>
|
||||||
@@ -89,13 +89,15 @@
|
|||||||
}
|
}
|
||||||
</script></code></pre>
|
</script></code></pre>
|
||||||
</section>
|
</section>
|
||||||
<section data-background="https://static.slid.es/reveal/image-placeholder.png">
|
<section class="stack">
|
||||||
<h2>Image Backgrounds</h2>
|
<section data-background="https://static.slid.es/reveal/image-placeholder.png" id="image-bg">
|
||||||
<pre><code class="hljs html"><section data-background="image.png"></code></pre>
|
<h2>Image Backgrounds</h2>
|
||||||
</section>
|
<pre><code class="hljs html"><section data-background="image.png"></code></pre>
|
||||||
<section data-background-video="https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.webm">
|
</section>
|
||||||
<h2>Video background</h2>
|
<section data-background-video="https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.webm">
|
||||||
</section>
|
<h2>Video background</h2>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
<section><h2>The end</h2></section>
|
<section><h2>The end</h2></section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -109,6 +111,7 @@
|
|||||||
<script>
|
<script>
|
||||||
Reveal.initialize({
|
Reveal.initialize({
|
||||||
view: 'reader',
|
view: 'reader',
|
||||||
|
hash: true,
|
||||||
|
|
||||||
plugins: [ RevealMarkdown, RevealHighlight, RevealNotes ]
|
plugins: [ RevealMarkdown, RevealHighlight, RevealNotes ]
|
||||||
});
|
});
|
||||||
|
@@ -278,7 +278,7 @@ export default {
|
|||||||
|
|
||||||
// Responsively activate the reader mode when we reach the specified
|
// Responsively activate the reader mode when we reach the specified
|
||||||
// width (in pixels)
|
// width (in pixels)
|
||||||
readerActivationWidth: null,
|
readerActivationWidth: 800,
|
||||||
|
|
||||||
// The maximum number of pages a single slide can expand onto when printing
|
// The maximum number of pages a single slide can expand onto when printing
|
||||||
// to PDF, unlimited by default
|
// to PDF, unlimited by default
|
||||||
|
@@ -64,7 +64,7 @@ export default class Location {
|
|||||||
try {
|
try {
|
||||||
slide = document
|
slide = document
|
||||||
.getElementById( decodeURIComponent( name ) )
|
.getElementById( decodeURIComponent( name ) )
|
||||||
.closest('.slides>section, .slides>section>section');
|
.closest('.slides section');
|
||||||
}
|
}
|
||||||
catch ( error ) { }
|
catch ( error ) { }
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { SLIDES_SELECTOR } from '../utils/constants.js'
|
import { HORIZONTAL_SLIDES_SELECTOR, SLIDES_SELECTOR } from '../utils/constants.js'
|
||||||
import { queryAll, createStyleSheet } from '../utils/util.js'
|
import { queryAll, createStyleSheet } from '../utils/util.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,12 +26,14 @@ export default class Reader {
|
|||||||
|
|
||||||
if( this.active ) return;
|
if( this.active ) return;
|
||||||
|
|
||||||
|
const state = this.Reveal.getState();
|
||||||
|
|
||||||
this.active = true;
|
this.active = true;
|
||||||
|
|
||||||
this.slideHTMLBeforeActivation = this.Reveal.getSlidesElement().innerHTML;
|
this.slideHTMLBeforeActivation = this.Reveal.getSlidesElement().innerHTML;
|
||||||
|
|
||||||
const viewportElement = this.Reveal.getViewportElement();
|
const viewportElement = this.Reveal.getViewportElement();
|
||||||
const slides = queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR );
|
const horizontalSlides = queryAll( this.Reveal.getRevealElement(), HORIZONTAL_SLIDES_SELECTOR );
|
||||||
|
|
||||||
viewportElement.classList.add( 'loading-scroll-mode', 'reveal-reader' );
|
viewportElement.classList.add( 'loading-scroll-mode', 'reveal-reader' );
|
||||||
viewportElement.addEventListener( 'scroll', this.onScroll );
|
viewportElement.addEventListener( 'scroll', this.onScroll );
|
||||||
@@ -44,42 +46,53 @@ export default class Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pageElements = [];
|
const pageElements = [];
|
||||||
const pageContainer = slides[0].parentNode;
|
const pageContainer = horizontalSlides[0].parentNode;
|
||||||
|
|
||||||
|
function createPage( slide, h, v ) {
|
||||||
|
|
||||||
|
// Wrap the slide in a page element and hide its overflow
|
||||||
|
// so that no page ever flows onto another
|
||||||
|
const page = document.createElement( 'div' );
|
||||||
|
page.className = 'reader-page';
|
||||||
|
pageElements.push( page );
|
||||||
|
|
||||||
|
// Copy the presentation-wide background to each page
|
||||||
|
if( presentationBackground ) {
|
||||||
|
page.style.background = presentationBackground;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
slide.classList.remove( 'past', 'future' );
|
||||||
|
|
||||||
|
if( typeof h === 'number' ) slide.setAttribute( 'data-index-h', h );
|
||||||
|
if( typeof v === 'number' ) slide.setAttribute( 'data-index-v', v );
|
||||||
|
|
||||||
|
if( slide.slideBackgroundElement ) {
|
||||||
|
slide.slideBackgroundElement.remove( 'past', 'future' );
|
||||||
|
contentContainer.insertBefore( slide.slideBackgroundElement, slide );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Slide and slide background layout
|
// Slide and slide background layout
|
||||||
slides.forEach( function( slide ) {
|
horizontalSlides.forEach( ( horizontalSlide, h ) => {
|
||||||
|
|
||||||
// Vertical stacks are not centred since their section
|
|
||||||
// children will be
|
|
||||||
if( slide.classList.contains( 'stack' ) === false ) {
|
|
||||||
// Wrap the slide in a page element and hide its overflow
|
|
||||||
// so that no page ever flows onto another
|
|
||||||
const page = document.createElement( 'div' );
|
|
||||||
page.className = 'reader-page';
|
|
||||||
pageElements.push( page );
|
|
||||||
|
|
||||||
// Copy the presentation-wide background to each page
|
|
||||||
if( presentationBackground ) {
|
|
||||||
page.style.background = presentationBackground;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
slide.classList.remove( 'past', 'future' );
|
|
||||||
|
|
||||||
if( slide.slideBackgroundElement ) {
|
|
||||||
slide.slideBackgroundElement.remove( 'past', 'future' );
|
|
||||||
contentContainer.insertBefore( slide.slideBackgroundElement, slide );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if( this.Reveal.isVerticalStack( horizontalSlide ) ) {
|
||||||
|
horizontalSlide.querySelectorAll( 'section' ).forEach( ( verticalSlide, v ) => {
|
||||||
|
createPage( verticalSlide, h, v );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
createPage( horizontalSlide, h, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
}, this );
|
}, this );
|
||||||
@@ -93,6 +106,7 @@ export default class Reader {
|
|||||||
this.Reveal.slideContent.layout( this.Reveal.getSlidesElement() );
|
this.Reveal.slideContent.layout( this.Reveal.getSlidesElement() );
|
||||||
|
|
||||||
this.Reveal.layout();
|
this.Reveal.layout();
|
||||||
|
this.Reveal.setState( state );
|
||||||
|
|
||||||
viewportElement.classList.remove( 'loading-scroll-mode' );
|
viewportElement.classList.remove( 'loading-scroll-mode' );
|
||||||
|
|
||||||
@@ -109,6 +123,8 @@ export default class Reader {
|
|||||||
|
|
||||||
if( !this.active ) return;
|
if( !this.active ) return;
|
||||||
|
|
||||||
|
const state = this.Reveal.getState();
|
||||||
|
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
|
||||||
const viewportElement = this.Reveal.getViewportElement();
|
const viewportElement = this.Reveal.getViewportElement();
|
||||||
@@ -119,8 +135,7 @@ export default class Reader {
|
|||||||
this.Reveal.getSlidesElement().innerHTML = this.slideHTMLBeforeActivation;
|
this.Reveal.getSlidesElement().innerHTML = this.slideHTMLBeforeActivation;
|
||||||
this.Reveal.sync();
|
this.Reveal.sync();
|
||||||
|
|
||||||
// TODO Navigate to the slide that is currently scrolled into view
|
this.Reveal.setState( state );
|
||||||
this.Reveal.slide( 0 );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +159,14 @@ export default class Reader {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSlideByIndices( h, v ) {
|
||||||
|
|
||||||
|
const page = this.pages.find( page => page.indexh === h && page.indexv === v );
|
||||||
|
|
||||||
|
return page ? page.slideElement : null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates our reader pages to match the latest configuration and
|
* Updates our reader pages to match the latest configuration and
|
||||||
* presentation size.
|
* presentation size.
|
||||||
@@ -177,9 +200,12 @@ export default class Reader {
|
|||||||
slideElement: pageElement.querySelector( 'section' ),
|
slideElement: pageElement.querySelector( 'section' ),
|
||||||
backgroundElement: pageElement.querySelector( '.slide-background' ),
|
backgroundElement: pageElement.querySelector( '.slide-background' ),
|
||||||
top: pageElement.offsetTop,
|
top: pageElement.offsetTop,
|
||||||
scrollTriggers: []
|
scrollTriggers: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
page.indexh = parseInt( page.slideElement.getAttribute( 'data-index-h' ), 10 );
|
||||||
|
page.indexv = parseInt( page.slideElement.getAttribute( 'data-index-v' ), 10 );
|
||||||
|
|
||||||
page.slideElement.style.width = slideSize.width + 'px';
|
page.slideElement.style.width = slideSize.width + 'px';
|
||||||
page.slideElement.style.height = config.center === true ? '' : slideSize.height + 'px';
|
page.slideElement.style.height = config.center === true ? '' : slideSize.height + 'px';
|
||||||
|
|
||||||
@@ -302,7 +328,7 @@ export default class Reader {
|
|||||||
page.pageElement.classList.add( 'present' );
|
page.pageElement.classList.add( 'present' );
|
||||||
page.slideElement.classList.add( 'present' );
|
page.slideElement.classList.add( 'present' );
|
||||||
|
|
||||||
this.Reveal.setCurrentReaderPage( pageIndex, page.pageElement );
|
this.Reveal.setCurrentReaderPage( page.pageElement, page.indexh, page.indexv );
|
||||||
this.Reveal.slideContent.startEmbeddedContent( page.slideElement );
|
this.Reveal.slideContent.startEmbeddedContent( page.slideElement );
|
||||||
|
|
||||||
if( page.backgroundElement ) {
|
if( page.backgroundElement ) {
|
||||||
|
60
js/reveal.js
60
js/reveal.js
@@ -208,14 +208,15 @@ export default function( revealElement, options ) {
|
|||||||
// Updates the presentation to match the current configuration values
|
// Updates the presentation to match the current configuration values
|
||||||
configure();
|
configure();
|
||||||
|
|
||||||
// Read the initial hash
|
|
||||||
location.readURL();
|
|
||||||
|
|
||||||
// Create slide backgrounds
|
// Create slide backgrounds
|
||||||
backgrounds.update( true );
|
backgrounds.update( true );
|
||||||
|
|
||||||
|
// Activate the print/reader mode if configured
|
||||||
activateInitialView();
|
activateInitialView();
|
||||||
|
|
||||||
|
// Read the initial hash
|
||||||
|
location.readURL();
|
||||||
|
|
||||||
// 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( () => {
|
setTimeout( () => {
|
||||||
@@ -1160,6 +1161,19 @@ export default function( revealElement, options ) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current or specified slide is a stack containing
|
||||||
|
* vertical slides.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} [slide=currentSlide]
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
function isVerticalStack( slide = currentSlide ) {
|
||||||
|
|
||||||
|
return slide.classList.contains( '.stack' ) || slide.querySelector( 'section' ) !== null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if we're on the last slide in the current
|
* Returns true if we're on the last slide in the current
|
||||||
* vertical stack.
|
* vertical stack.
|
||||||
@@ -1348,7 +1362,7 @@ export default function( revealElement, options ) {
|
|||||||
// If we're in reader mode we scroll the target slide into view
|
// If we're in reader mode we scroll the target slide into view
|
||||||
// instead of running our standard slide transition
|
// instead of running our standard slide transition
|
||||||
if( reader.isActive() ) {
|
if( reader.isActive() ) {
|
||||||
const scrollToSlide = dom.wrapper.querySelectorAll( SLIDES_SELECTOR )[ h ];
|
const scrollToSlide = reader.getSlideByIndices( h, v );
|
||||||
if( scrollToSlide ) reader.scrollToSlide( scrollToSlide );
|
if( scrollToSlide ) reader.scrollToSlide( scrollToSlide );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1541,12 +1555,12 @@ export default function( revealElement, options ) {
|
|||||||
* @param {number} pageIndex
|
* @param {number} pageIndex
|
||||||
* @param {HTMLElement} pageElement
|
* @param {HTMLElement} pageElement
|
||||||
*/
|
*/
|
||||||
function setCurrentReaderPage( pageIndex, pageElement ) {
|
function setCurrentReaderPage( pageElement, h, v ) {
|
||||||
|
|
||||||
let indexhBefore = indexh || 0;
|
let indexhBefore = indexh || 0;
|
||||||
|
|
||||||
indexh = pageIndex;
|
indexh = h;
|
||||||
indexv = 0;
|
indexv = v;
|
||||||
|
|
||||||
previousSlide = currentSlide;
|
previousSlide = currentSlide;
|
||||||
currentSlide = pageElement.querySelector( 'section' );
|
currentSlide = pageElement.querySelector( 'section' );
|
||||||
@@ -2098,21 +2112,30 @@ export default function( revealElement, options ) {
|
|||||||
|
|
||||||
// If a slide is specified, return the indices of that slide
|
// If a slide is specified, return the indices of that slide
|
||||||
if( slide ) {
|
if( slide ) {
|
||||||
let isVertical = isVerticalSlide( slide );
|
if( reader.isActive() ) {
|
||||||
let slideh = isVertical ? slide.parentNode : slide;
|
h = parseInt( slide.getAttribute( 'data-index-h' ), 10 );
|
||||||
|
|
||||||
// Select all horizontal slides
|
if( slide.getAttribute( 'data-index-v' ) ) {
|
||||||
let horizontalSlides = getHorizontalSlides();
|
v = parseInt( slide.getAttribute( 'data-index-v' ), 10 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let isVertical = isVerticalSlide( slide );
|
||||||
|
let slideh = isVertical ? slide.parentNode : slide;
|
||||||
|
|
||||||
// Now that we know which the horizontal slide is, get its index
|
// Select all horizontal slides
|
||||||
h = Math.max( horizontalSlides.indexOf( slideh ), 0 );
|
let horizontalSlides = getHorizontalSlides();
|
||||||
|
|
||||||
// Assume we're not vertical
|
// Now that we know which the horizontal slide is, get its index
|
||||||
v = undefined;
|
h = Math.max( horizontalSlides.indexOf( slideh ), 0 );
|
||||||
|
|
||||||
// If this is a vertical slide, grab the vertical index
|
// Assume we're not vertical
|
||||||
if( isVertical ) {
|
v = undefined;
|
||||||
v = Math.max( Util.queryAll( slide.parentNode, 'section' ).indexOf( slide ), 0 );
|
|
||||||
|
// If this is a vertical slide, grab the vertical index
|
||||||
|
if( isVertical ) {
|
||||||
|
v = Math.max( Util.queryAll( slide.parentNode, 'section' ).indexOf( slide ), 0 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2802,6 +2825,7 @@ export default function( revealElement, options ) {
|
|||||||
isLastSlide,
|
isLastSlide,
|
||||||
isLastVerticalSlide,
|
isLastVerticalSlide,
|
||||||
isVerticalSlide,
|
isVerticalSlide,
|
||||||
|
isVerticalStack,
|
||||||
|
|
||||||
// State checks
|
// State checks
|
||||||
isPaused,
|
isPaused,
|
||||||
|
Reference in New Issue
Block a user