mirror of
https://github.com/hakimel/reveal.js.git
synced 2025-09-13 16:12:03 +02:00
Compare commits
41 Commits
5.0.3
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
|
27e1dfbc1e | ||
|
6410c756ea | ||
|
62297e6259 | ||
|
ade53094b9 | ||
|
164254655b | ||
|
e2344787c4 | ||
|
334abff10f | ||
|
19c1bca1e4 | ||
|
0799c8f674 | ||
|
924bdb6305 | ||
|
d4e5c39fe4 | ||
|
2fb4b46307 | ||
|
488c5c8f94 | ||
|
421da63750 | ||
|
62b1ea302c | ||
|
76ec60a137 | ||
|
1748a55ece | ||
|
a29a9c71ae | ||
|
6ef138b61f | ||
|
63e0a37a88 | ||
|
2927be34d8 | ||
|
9d4b4362e9 | ||
|
8efd7af37c | ||
|
66fa4350e1 | ||
|
f149d1f7ca | ||
|
0951ce2b4f | ||
|
18ec38a6b1 | ||
|
67b5ec1773 | ||
|
50580c37c2 | ||
|
ec4eeab478 | ||
|
4e353b207d | ||
|
608e0eefcd | ||
|
aa31cab9e3 | ||
|
28aee42e8e | ||
|
ebca26e1f9 | ||
|
d61b375bf8 | ||
|
dcc21516dd | ||
|
16f6633014 | ||
|
5d131cea20 | ||
|
52480157a1 | ||
|
5ee1f729bd |
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (C) 2011-2023 Hakim El Hattab, http://hakim.se, and reveal.js contributors
|
||||
Copyright (C) 2011-2024 Hakim El Hattab, http://hakim.se, and reveal.js contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@@ -46,5 +46,5 @@ Hakim's open source work is supported by <a href="https://github.com/sponsors/ha
|
||||
|
||||
---
|
||||
<div align="center">
|
||||
MIT licensed | Copyright © 2011-2023 Hakim El Hattab, https://hakim.se
|
||||
MIT licensed | Copyright © 2011-2024 Hakim El Hattab, https://hakim.se
|
||||
</div>
|
||||
|
@@ -25,6 +25,7 @@
|
||||
// Stack multiple elements on top of each other
|
||||
.reveal .r-stack {
|
||||
display: grid;
|
||||
grid-template-rows: 100%;
|
||||
}
|
||||
|
||||
.reveal .r-stack > * {
|
||||
|
@@ -631,11 +631,16 @@ $controlsArrowAngleActive: 36deg;
|
||||
touch-action: pinch-zoom;
|
||||
}
|
||||
|
||||
// Swiping on an embedded deck should not block page scrolling
|
||||
// Swiping on an embedded deck should not block page scrolling...
|
||||
.reveal.embedded {
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
// ... unless we're on a vertical slide
|
||||
.reveal.embedded.is-vertical-slide {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.reveal .slides {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
@@ -165,9 +165,9 @@
|
||||
</section>
|
||||
<section data-auto-animate data-auto-animate-easing="cubic-bezier(0.770, 0.000, 0.175, 1.000)">
|
||||
<div class="r-stack">
|
||||
<div data-id="box1" style="background: cyan; width: 300px; height: 300px; border-radius: 200px;"></div>
|
||||
<div data-id="box2" style="background: magenta; width: 200px; height: 200px; border-radius: 200px;"></div>
|
||||
<div data-id="box3" style="background: yellow; width: 100px; height: 100px; border-radius: 200px;"></div>
|
||||
<div data-id="box1" style="background: cyan; width: 300px; height: 300px;"></div>
|
||||
<div data-id="box2" style="background: magenta; width: 200px; height: 200px;"></div>
|
||||
<div data-id="box3" style="background: yellow; width: 100px; height: 100px;"></div>
|
||||
</div>
|
||||
<h2 style="margin-top: 20px;">Auto-Animate</h2>
|
||||
</section>
|
||||
|
6
dist/reveal.css
vendored
6
dist/reveal.css
vendored
File diff suppressed because one or more lines are too long
6
dist/reveal.esm.js
vendored
6
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
6
dist/reveal.js
vendored
6
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
@@ -106,13 +106,13 @@
|
||||
<script src="../plugin/markdown/markdown.js"></script>
|
||||
<script src="../plugin/highlight/highlight.js"></script>
|
||||
<script>
|
||||
Reveal.initialize({
|
||||
view: 'scroll',
|
||||
hash: true,
|
||||
Reveal.initialize({
|
||||
view: 'scroll',
|
||||
hash: true,
|
||||
|
||||
plugins: [ RevealMarkdown, RevealHighlight, RevealNotes ]
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -29,7 +29,7 @@ const banner = `/*!
|
||||
* ${pkg.homepage}
|
||||
* MIT licensed
|
||||
*
|
||||
* Copyright (C) 2011-2023 Hakim El Hattab, https://hakim.se
|
||||
* Copyright (C) 2011-2024 Hakim El Hattab, https://hakim.se
|
||||
*/\n`
|
||||
|
||||
// Prevents warnings from opening too many test pages
|
||||
|
@@ -31,10 +31,13 @@ export default class AutoAnimate {
|
||||
let toSlideIndex = allSlides.indexOf( toSlide );
|
||||
let fromSlideIndex = allSlides.indexOf( fromSlide );
|
||||
|
||||
// Ensure that both slides are auto-animate targets with the same data-auto-animate-id value
|
||||
// (including null if absent on both) and that data-auto-animate-restart isn't set on the
|
||||
// physically latter slide (independent of slide direction)
|
||||
if( fromSlide.hasAttribute( 'data-auto-animate' ) && toSlide.hasAttribute( 'data-auto-animate' )
|
||||
// Ensure that;
|
||||
// 1. Both slides exist.
|
||||
// 2. Both slides are auto-animate targets with the same
|
||||
// data-auto-animate-id value (including null if absent on both).
|
||||
// 3. data-auto-animate-restart isn't set on the physically latter
|
||||
// slide (independent of slide direction).
|
||||
if( fromSlide && toSlide && fromSlide.hasAttribute( 'data-auto-animate' ) && toSlide.hasAttribute( 'data-auto-animate' )
|
||||
&& fromSlide.getAttribute( 'data-auto-animate-id' ) === toSlide.getAttribute( 'data-auto-animate-id' )
|
||||
&& !( toSlideIndex > fromSlideIndex ? toSlide : fromSlide ).hasAttribute( 'data-auto-animate-restart' ) ) {
|
||||
|
||||
|
@@ -268,14 +268,15 @@ export default class Backgrounds {
|
||||
*/
|
||||
update( includeAll = false ) {
|
||||
|
||||
let config = this.Reveal.getConfig();
|
||||
let currentSlide = this.Reveal.getCurrentSlide();
|
||||
let indices = this.Reveal.getIndices();
|
||||
|
||||
let currentBackground = null;
|
||||
|
||||
// Reverse past/future classes when in RTL mode
|
||||
let horizontalPast = this.Reveal.getConfig().rtl ? 'future' : 'past',
|
||||
horizontalFuture = this.Reveal.getConfig().rtl ? 'past' : 'future';
|
||||
let horizontalPast = config.rtl ? 'future' : 'past',
|
||||
horizontalFuture = config.rtl ? 'past' : 'future';
|
||||
|
||||
// Update the classes of all backgrounds to match the
|
||||
// states of their slides (past/present/future)
|
||||
@@ -321,6 +322,42 @@ export default class Backgrounds {
|
||||
|
||||
} );
|
||||
|
||||
// The previous background may refer to a DOM element that has
|
||||
// been removed after a presentation is synced & bgs are recreated
|
||||
if( this.previousBackground && !this.previousBackground.closest( 'body' ) ) {
|
||||
this.previousBackground = null;
|
||||
}
|
||||
|
||||
if( currentBackground && this.previousBackground ) {
|
||||
|
||||
// Don't transition between identical backgrounds. This
|
||||
// prevents unwanted flicker.
|
||||
let previousBackgroundHash = this.previousBackground.getAttribute( 'data-background-hash' );
|
||||
let currentBackgroundHash = currentBackground.getAttribute( 'data-background-hash' );
|
||||
|
||||
if( currentBackgroundHash && currentBackgroundHash === previousBackgroundHash && currentBackground !== this.previousBackground ) {
|
||||
this.element.classList.add( 'no-transition' );
|
||||
|
||||
// If multiple slides have the same background video, carry
|
||||
// the <video> element forward so that it plays continuously
|
||||
// across multiple slides
|
||||
const currentVideo = currentBackground.querySelector( 'video' );
|
||||
const previousVideo = this.previousBackground.querySelector( 'video' );
|
||||
|
||||
if( currentVideo && previousVideo ) {
|
||||
|
||||
const currentVideoParent = currentVideo.parentNode;
|
||||
const previousVideoParent = previousVideo.parentNode;
|
||||
|
||||
// Swap the two videos
|
||||
previousVideoParent.appendChild( currentVideo );
|
||||
currentVideoParent.appendChild( previousVideo );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Stop content inside of previous backgrounds
|
||||
if( this.previousBackground ) {
|
||||
|
||||
@@ -347,14 +384,6 @@ export default class Backgrounds {
|
||||
|
||||
}
|
||||
|
||||
// Don't transition between identical backgrounds. This
|
||||
// prevents unwanted flicker.
|
||||
let previousBackgroundHash = this.previousBackground ? this.previousBackground.getAttribute( 'data-background-hash' ) : null;
|
||||
let currentBackgroundHash = currentBackground.getAttribute( 'data-background-hash' );
|
||||
if( currentBackgroundHash && currentBackgroundHash === previousBackgroundHash && currentBackground !== this.previousBackground ) {
|
||||
this.element.classList.add( 'no-transition' );
|
||||
}
|
||||
|
||||
this.previousBackground = currentBackground;
|
||||
|
||||
}
|
||||
@@ -368,7 +397,7 @@ export default class Backgrounds {
|
||||
// Allow the first background to apply without transition
|
||||
setTimeout( () => {
|
||||
this.element.classList.remove( 'no-transition' );
|
||||
}, 1 );
|
||||
}, 10 );
|
||||
|
||||
}
|
||||
|
||||
|
15
js/controllers/controls.js
vendored
15
js/controllers/controls.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { queryAll } from '../utils/util.js'
|
||||
import { queryAll, enterFullscreen } from '../utils/util.js'
|
||||
import { isAndroid } from '../utils/device.js'
|
||||
|
||||
/**
|
||||
@@ -12,6 +12,7 @@ import { isAndroid } from '../utils/device.js'
|
||||
* - .navigate-left
|
||||
* - .navigate-next
|
||||
* - .navigate-prev
|
||||
* - .enter-fullscreen
|
||||
*/
|
||||
export default class Controls {
|
||||
|
||||
@@ -25,6 +26,7 @@ export default class Controls {
|
||||
this.onNavigateDownClicked = this.onNavigateDownClicked.bind( this );
|
||||
this.onNavigatePrevClicked = this.onNavigatePrevClicked.bind( this );
|
||||
this.onNavigateNextClicked = this.onNavigateNextClicked.bind( this );
|
||||
this.onEnterFullscreen = this.onEnterFullscreen.bind( this );
|
||||
|
||||
}
|
||||
|
||||
@@ -50,6 +52,7 @@ export default class Controls {
|
||||
this.controlsDown = queryAll( revealElement, '.navigate-down' );
|
||||
this.controlsPrev = queryAll( revealElement, '.navigate-prev' );
|
||||
this.controlsNext = queryAll( revealElement, '.navigate-next' );
|
||||
this.controlsFullscreen = queryAll( revealElement, '.enter-fullscreen' );
|
||||
|
||||
// The left, right and down arrows in the standard reveal.js controls
|
||||
this.controlsRightArrow = this.element.querySelector( '.navigate-right' );
|
||||
@@ -89,6 +92,7 @@ export default class Controls {
|
||||
this.controlsDown.forEach( el => el.addEventListener( eventName, this.onNavigateDownClicked, false ) );
|
||||
this.controlsPrev.forEach( el => el.addEventListener( eventName, this.onNavigatePrevClicked, false ) );
|
||||
this.controlsNext.forEach( el => el.addEventListener( eventName, this.onNavigateNextClicked, false ) );
|
||||
this.controlsFullscreen.forEach( el => el.addEventListener( eventName, this.onEnterFullscreen, false ) );
|
||||
} );
|
||||
|
||||
}
|
||||
@@ -102,6 +106,7 @@ export default class Controls {
|
||||
this.controlsDown.forEach( el => el.removeEventListener( eventName, this.onNavigateDownClicked, false ) );
|
||||
this.controlsPrev.forEach( el => el.removeEventListener( eventName, this.onNavigatePrevClicked, false ) );
|
||||
this.controlsNext.forEach( el => el.removeEventListener( eventName, this.onNavigateNextClicked, false ) );
|
||||
this.controlsFullscreen.forEach( el => el.removeEventListener( eventName, this.onEnterFullscreen, false ) );
|
||||
} );
|
||||
|
||||
}
|
||||
@@ -262,5 +267,13 @@ export default class Controls {
|
||||
|
||||
}
|
||||
|
||||
onEnterFullscreen( event ) {
|
||||
|
||||
const config = this.Reveal.getConfig();
|
||||
const viewport = this.Reveal.getViewportElement();
|
||||
|
||||
enterFullscreen( config.embedded ? viewport : viewport.parentElement );
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -257,6 +257,26 @@ export default class Fragments {
|
||||
|
||||
}
|
||||
|
||||
if( changedFragments.hidden.length ) {
|
||||
this.Reveal.dispatchEvent({
|
||||
type: 'fragmenthidden',
|
||||
data: {
|
||||
fragment: changedFragments.hidden[0],
|
||||
fragments: changedFragments.hidden
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if( changedFragments.shown.length ) {
|
||||
this.Reveal.dispatchEvent({
|
||||
type: 'fragmentshown',
|
||||
data: {
|
||||
fragment: changedFragments.shown[0],
|
||||
fragments: changedFragments.shown
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return changedFragments;
|
||||
|
||||
}
|
||||
@@ -311,26 +331,6 @@ export default class Fragments {
|
||||
|
||||
let changedFragments = this.update( index, fragments );
|
||||
|
||||
if( changedFragments.hidden.length ) {
|
||||
this.Reveal.dispatchEvent({
|
||||
type: 'fragmenthidden',
|
||||
data: {
|
||||
fragment: changedFragments.hidden[0],
|
||||
fragments: changedFragments.hidden
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if( changedFragments.shown.length ) {
|
||||
this.Reveal.dispatchEvent({
|
||||
type: 'fragmentshown',
|
||||
data: {
|
||||
fragment: changedFragments.shown[0],
|
||||
fragments: changedFragments.shown
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.Reveal.controls.update();
|
||||
this.Reveal.progress.update();
|
||||
|
||||
|
@@ -178,7 +178,7 @@ export default class Keyboard {
|
||||
if( activeElementIsCE || activeElementIsInput || activeElementIsNotes || unusedModifier ) return;
|
||||
|
||||
// While paused only allow resume keyboard events; 'b', 'v', '.'
|
||||
let resumeKeyCodes = [66,86,190,191];
|
||||
let resumeKeyCodes = [66,86,190,191,112];
|
||||
let key;
|
||||
|
||||
// Custom key bindings for togglePause should be able to resume
|
||||
@@ -271,7 +271,12 @@ export default class Keyboard {
|
||||
this.Reveal.slide( 0 );
|
||||
}
|
||||
else if( !this.Reveal.overview.isActive() && useLinearMode ) {
|
||||
this.Reveal.prev({skipFragments: event.altKey});
|
||||
if( config.rtl ) {
|
||||
this.Reveal.next({skipFragments: event.altKey});
|
||||
}
|
||||
else {
|
||||
this.Reveal.prev({skipFragments: event.altKey});
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.Reveal.left({skipFragments: event.altKey});
|
||||
@@ -283,7 +288,12 @@ export default class Keyboard {
|
||||
this.Reveal.slide( this.Reveal.getHorizontalSlides().length - 1 );
|
||||
}
|
||||
else if( !this.Reveal.overview.isActive() && useLinearMode ) {
|
||||
this.Reveal.next({skipFragments: event.altKey});
|
||||
if( config.rtl ) {
|
||||
this.Reveal.prev({skipFragments: event.altKey});
|
||||
}
|
||||
else {
|
||||
this.Reveal.next({skipFragments: event.altKey});
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.Reveal.right({skipFragments: event.altKey});
|
||||
@@ -357,6 +367,10 @@ export default class Keyboard {
|
||||
else if( keyCode === 191 && event.shiftKey ) {
|
||||
this.Reveal.toggleHelp();
|
||||
}
|
||||
// F1
|
||||
else if( keyCode === 112 ) {
|
||||
this.Reveal.toggleHelp();
|
||||
}
|
||||
else {
|
||||
triggered = false;
|
||||
}
|
||||
@@ -383,4 +397,4 @@ export default class Keyboard {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { HORIZONTAL_SLIDES_SELECTOR } from '../utils/constants.js'
|
||||
import { HORIZONTAL_SLIDES_SELECTOR, HORIZONTAL_BACKGROUNDS_SELECTOR } from '../utils/constants.js'
|
||||
import { queryAll } from '../utils/util.js'
|
||||
|
||||
const HIDE_SCROLLBAR_TIMEOUT = 500;
|
||||
@@ -40,6 +40,7 @@ export default class ScrollView {
|
||||
this.slideHTMLBeforeActivation = this.Reveal.getSlidesElement().innerHTML;
|
||||
|
||||
const horizontalSlides = queryAll( this.Reveal.getRevealElement(), HORIZONTAL_SLIDES_SELECTOR );
|
||||
const horizontalBackgrounds = queryAll( this.Reveal.getRevealElement(), HORIZONTAL_BACKGROUNDS_SELECTOR );
|
||||
|
||||
this.viewportElement.classList.add( 'loading-scroll-mode', 'reveal-scroll' );
|
||||
|
||||
@@ -57,7 +58,7 @@ export default class ScrollView {
|
||||
|
||||
// Creates a new page element and appends the given slide/bg
|
||||
// to it.
|
||||
const createPageElement = ( slide, h, v ) => {
|
||||
const createPageElement = ( slide, h, v, isVertical ) => {
|
||||
|
||||
let contentContainer;
|
||||
|
||||
@@ -76,8 +77,20 @@ export default class ScrollView {
|
||||
page.className = 'scroll-page';
|
||||
pageElements.push( page );
|
||||
|
||||
// Copy the presentation-wide background to each page
|
||||
if( presentationBackground ) {
|
||||
// This transfers over the background of the vertical stack containing
|
||||
// the slide if it exists. Otherwise, it uses the presentation-wide
|
||||
// background.
|
||||
if( isVertical && horizontalBackgrounds.length > h ) {
|
||||
const slideBackground = horizontalBackgrounds[h];
|
||||
const pageBackground = window.getComputedStyle( slideBackground );
|
||||
|
||||
if( pageBackground && pageBackground.background ) {
|
||||
page.style.background = pageBackground.background;
|
||||
}
|
||||
else if( presentationBackground ) {
|
||||
page.style.background = presentationBackground;
|
||||
}
|
||||
} else if( presentationBackground ) {
|
||||
page.style.background = presentationBackground;
|
||||
}
|
||||
|
||||
@@ -110,7 +123,7 @@ export default class ScrollView {
|
||||
|
||||
if( this.Reveal.isVerticalStack( horizontalSlide ) ) {
|
||||
horizontalSlide.querySelectorAll( 'section' ).forEach( ( verticalSlide, v ) => {
|
||||
createPageElement( verticalSlide, h, v );
|
||||
createPageElement( verticalSlide, h, v, true );
|
||||
});
|
||||
}
|
||||
else {
|
||||
@@ -277,7 +290,7 @@ export default class ScrollView {
|
||||
const pageHeight = useCompactLayout ? compactHeight : viewportHeight;
|
||||
|
||||
// The height that needs to be scrolled between scroll triggers
|
||||
const scrollTriggerHeight = useCompactLayout ? compactHeight : viewportHeight;
|
||||
this.scrollTriggerHeight = useCompactLayout ? compactHeight : viewportHeight;
|
||||
|
||||
this.viewportElement.style.setProperty( '--page-height', pageHeight + 'px' );
|
||||
this.viewportElement.style.scrollSnapType = typeof config.scrollSnap === 'string' ? `y ${config.scrollSnap}` : '';
|
||||
@@ -333,12 +346,12 @@ export default class ScrollView {
|
||||
for( let i = 0; i < totalScrollTriggerCount + 1; i++ ) {
|
||||
const triggerStick = document.createElement( 'div' );
|
||||
triggerStick.className = 'scroll-snap-point';
|
||||
triggerStick.style.height = scrollTriggerHeight + 'px';
|
||||
triggerStick.style.height = this.scrollTriggerHeight + 'px';
|
||||
triggerStick.style.scrollSnapAlign = useCompactLayout ? 'center' : 'start';
|
||||
page.pageElement.appendChild( triggerStick );
|
||||
|
||||
if( i === 0 ) {
|
||||
triggerStick.style.marginTop = -scrollTriggerHeight + 'px';
|
||||
triggerStick.style.marginTop = -this.scrollTriggerHeight + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +368,7 @@ export default class ScrollView {
|
||||
}
|
||||
|
||||
// Add scroll padding based on how many scroll triggers we have
|
||||
page.scrollPadding = scrollTriggerHeight * totalScrollTriggerCount;
|
||||
page.scrollPadding = this.scrollTriggerHeight * totalScrollTriggerCount;
|
||||
|
||||
// The total height including scrollable space
|
||||
page.totalHeight = page.pageHeight + page.scrollPadding;
|
||||
@@ -699,6 +712,24 @@ export default class ScrollView {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the previous page.
|
||||
*/
|
||||
prev() {
|
||||
|
||||
this.viewportElement.scrollTop -= this.scrollTriggerHeight;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the next page.
|
||||
*/
|
||||
next() {
|
||||
|
||||
this.viewportElement.scrollTop += this.scrollTriggerHeight;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the given slide element into view.
|
||||
*
|
||||
|
@@ -375,8 +375,11 @@ export default class SlideContent {
|
||||
isVisible = !!closest( event.target, '.present' );
|
||||
|
||||
if( isAttachedToDOM && isVisible ) {
|
||||
event.target.currentTime = 0;
|
||||
event.target.play();
|
||||
// Don't restart if media is already playing
|
||||
if( event.target.paused || event.target.ended ) {
|
||||
event.target.currentTime = 0;
|
||||
event.target.play();
|
||||
}
|
||||
}
|
||||
|
||||
event.target.removeEventListener( 'loadeddata', this.startEmbeddedMedia );
|
||||
|
@@ -84,7 +84,7 @@ export default class Touch {
|
||||
isSwipePrevented( target ) {
|
||||
|
||||
// Prevent accidental swipes when scrubbing timelines
|
||||
if( matches( target, 'video, audio' ) ) return true;
|
||||
if( matches( target, 'video[controls], audio[controls]' ) ) return true;
|
||||
|
||||
while( target && typeof target.hasAttribute === 'function' ) {
|
||||
if( target.hasAttribute( 'data-prevent-swipe' ) ) return true;
|
||||
@@ -103,6 +103,8 @@ export default class Touch {
|
||||
*/
|
||||
onTouchStart( event ) {
|
||||
|
||||
this.touchCaptured = false;
|
||||
|
||||
if( this.isSwipePrevented( event.target ) ) return true;
|
||||
|
||||
this.touchStartX = event.touches[0].clientX;
|
||||
|
90
js/reveal.js
90
js/reveal.js
@@ -28,7 +28,7 @@ import {
|
||||
} from './utils/constants.js'
|
||||
|
||||
// The reveal.js version
|
||||
export const VERSION = '5.0.1';
|
||||
export const VERSION = '5.0.5';
|
||||
|
||||
/**
|
||||
* reveal.js
|
||||
@@ -51,6 +51,9 @@ export default function( revealElement, options ) {
|
||||
// Configuration defaults, can be overridden at initialization time
|
||||
let config = {},
|
||||
|
||||
// Flags if initialize() has been invoked for this reveal instance
|
||||
initialized = false,
|
||||
|
||||
// Flags if reveal.js is loaded (has dispatched the 'ready' event)
|
||||
ready = false,
|
||||
|
||||
@@ -127,6 +130,8 @@ export default function( revealElement, options ) {
|
||||
|
||||
if( !revealElement ) throw 'Unable to find presentation root (<div class="reveal">).';
|
||||
|
||||
initialized = true;
|
||||
|
||||
// Cache references to key DOM elements
|
||||
dom.wrapper = revealElement;
|
||||
dom.slides = revealElement.querySelector( '.slides' );
|
||||
@@ -604,6 +609,10 @@ export default function( revealElement, options ) {
|
||||
*/
|
||||
function destroy() {
|
||||
|
||||
// There's nothing to destroy if this instance hasn't been
|
||||
// initialized yet
|
||||
if( initialized === false ) return;
|
||||
|
||||
removeEventListeners();
|
||||
cancelAutoSlide();
|
||||
disablePreviewLinks();
|
||||
@@ -1016,20 +1025,10 @@ export default function( revealElement, options ) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Responsively turn on the scroll mode if there is an activation
|
||||
// width configured. Ignore if we're configured to always be in
|
||||
// scroll mode.
|
||||
if( typeof config.scrollActivationWidth === 'number' && config.view !== 'scroll' ) {
|
||||
if( size.presentationWidth > 0 && size.presentationWidth <= config.scrollActivationWidth ) {
|
||||
if( !scrollView.isActive() ) scrollView.activate();
|
||||
}
|
||||
else {
|
||||
if( scrollView.isActive() ) scrollView.deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkResponsiveScrollView();
|
||||
|
||||
dom.viewport.style.setProperty( '--slide-scale', scale );
|
||||
dom.viewport.style.setProperty( '--viewport-width', viewportWidth + 'px' );
|
||||
dom.viewport.style.setProperty( '--viewport-height', viewportHeight + 'px' );
|
||||
@@ -1081,6 +1080,40 @@ export default function( revealElement, options ) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsively activates the scroll mode when we reach the configured
|
||||
* activation width.
|
||||
*/
|
||||
function checkResponsiveScrollView() {
|
||||
|
||||
// Only proceed if...
|
||||
// 1. The DOM is ready
|
||||
// 2. Layouts aren't disabled via config
|
||||
// 3. We're not currently printing
|
||||
// 4. There is a scrollActivationWidth set
|
||||
// 5. The deck isn't configured to always use the scroll view
|
||||
if(
|
||||
dom.wrapper &&
|
||||
!config.disableLayout &&
|
||||
!printView.isActive() &&
|
||||
typeof config.scrollActivationWidth === 'number' &&
|
||||
config.view !== 'scroll'
|
||||
) {
|
||||
const size = getComputedSlideSize();
|
||||
|
||||
if( size.presentationWidth > 0 && size.presentationWidth <= config.scrollActivationWidth ) {
|
||||
if( !scrollView.isActive() ) {
|
||||
backgrounds.create();
|
||||
scrollView.activate()
|
||||
};
|
||||
}
|
||||
else {
|
||||
if( scrollView.isActive() ) scrollView.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the computed pixel size of our slides. These
|
||||
* values are based on the width and height configuration
|
||||
@@ -1356,6 +1389,8 @@ export default function( revealElement, options ) {
|
||||
*/
|
||||
function slide( h, v, f, origin ) {
|
||||
|
||||
if( Reveal.isReady() === false ) return;
|
||||
|
||||
// Dispatch an event before the slide
|
||||
const slidechange = dispatchEvent({
|
||||
type: 'beforeslidechange',
|
||||
@@ -1422,6 +1457,9 @@ export default function( revealElement, options ) {
|
||||
let currentHorizontalSlide = horizontalSlides[ indexh ],
|
||||
currentVerticalSlides = currentHorizontalSlide.querySelectorAll( 'section' );
|
||||
|
||||
// Indicate when we're on a vertical slide
|
||||
revealElement.classList.toggle( 'is-vertical-slide', currentVerticalSlides.length > 1 );
|
||||
|
||||
// Store references to the previous and current slides
|
||||
currentSlide = currentVerticalSlides[ indexv ] || currentHorizontalSlide;
|
||||
|
||||
@@ -1617,6 +1655,8 @@ export default function( revealElement, options ) {
|
||||
*/
|
||||
function sync() {
|
||||
|
||||
if( Reveal.isReady() === false ) return;
|
||||
|
||||
// Subscribe to input
|
||||
removeEventListeners();
|
||||
addEventListeners();
|
||||
@@ -2475,6 +2515,9 @@ export default function( revealElement, options ) {
|
||||
|
||||
navigationHistory.hasNavigatedHorizontally = true;
|
||||
|
||||
// Scroll view navigation is handled independently
|
||||
if( scrollView.isActive() ) return scrollView.prev();
|
||||
|
||||
// Reverse for RTL
|
||||
if( config.rtl ) {
|
||||
if( ( overview.isActive() || skipFragments || fragments.next() === false ) && availableRoutes().left ) {
|
||||
@@ -2492,6 +2535,9 @@ export default function( revealElement, options ) {
|
||||
|
||||
navigationHistory.hasNavigatedHorizontally = true;
|
||||
|
||||
// Scroll view navigation is handled independently
|
||||
if( scrollView.isActive() ) return scrollView.next();
|
||||
|
||||
// Reverse for RTL
|
||||
if( config.rtl ) {
|
||||
if( ( overview.isActive() || skipFragments || fragments.prev() === false ) && availableRoutes().right ) {
|
||||
@@ -2507,6 +2553,9 @@ export default function( revealElement, options ) {
|
||||
|
||||
function navigateUp({skipFragments=false}={}) {
|
||||
|
||||
// Scroll view navigation is handled independently
|
||||
if( scrollView.isActive() ) return scrollView.prev();
|
||||
|
||||
// Prioritize hiding fragments
|
||||
if( ( overview.isActive() || skipFragments || fragments.prev() === false ) && availableRoutes().up ) {
|
||||
slide( indexh, indexv - 1 );
|
||||
@@ -2518,6 +2567,9 @@ export default function( revealElement, options ) {
|
||||
|
||||
navigationHistory.hasNavigatedVertically = true;
|
||||
|
||||
// Scroll view navigation is handled independently
|
||||
if( scrollView.isActive() ) return scrollView.next();
|
||||
|
||||
// Prioritize revealing fragments
|
||||
if( ( overview.isActive() || skipFragments || fragments.next() === false ) && availableRoutes().down ) {
|
||||
slide( indexh, indexv + 1 );
|
||||
@@ -2533,6 +2585,9 @@ export default function( revealElement, options ) {
|
||||
*/
|
||||
function navigatePrev({skipFragments=false}={}) {
|
||||
|
||||
// Scroll view navigation is handled independently
|
||||
if( scrollView.isActive() ) return scrollView.prev();
|
||||
|
||||
// Prioritize revealing fragments
|
||||
if( skipFragments || fragments.prev() === false ) {
|
||||
if( availableRoutes().up ) {
|
||||
@@ -2556,6 +2611,9 @@ export default function( revealElement, options ) {
|
||||
let h = indexh - 1;
|
||||
slide( h, v );
|
||||
}
|
||||
else if( config.rtl ) {
|
||||
navigateRight({skipFragments});
|
||||
}
|
||||
else {
|
||||
navigateLeft({skipFragments});
|
||||
}
|
||||
@@ -2572,6 +2630,9 @@ export default function( revealElement, options ) {
|
||||
navigationHistory.hasNavigatedHorizontally = true;
|
||||
navigationHistory.hasNavigatedVertically = true;
|
||||
|
||||
// Scroll view navigation is handled independently
|
||||
if( scrollView.isActive() ) return scrollView.next();
|
||||
|
||||
// Prioritize revealing fragments
|
||||
if( skipFragments || fragments.next() === false ) {
|
||||
|
||||
@@ -2700,7 +2761,6 @@ export default function( revealElement, options ) {
|
||||
function onWindowResize( event ) {
|
||||
|
||||
layout();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2879,7 +2939,7 @@ export default function( revealElement, options ) {
|
||||
loadSlide: slideContent.load.bind( slideContent ),
|
||||
unloadSlide: slideContent.unload.bind( slideContent ),
|
||||
|
||||
// Media playback
|
||||
// Start/stop all media inside of the current slide
|
||||
startEmbeddedContent: () => slideContent.startEmbeddedContent( currentSlide ),
|
||||
stopEmbeddedContent: () => slideContent.stopEmbeddedContent( currentSlide, { unloadIframes: false } ),
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
export const SLIDES_SELECTOR = '.slides section';
|
||||
export const HORIZONTAL_SLIDES_SELECTOR = '.slides>section';
|
||||
export const VERTICAL_SLIDES_SELECTOR = '.slides>section.present>section';
|
||||
export const HORIZONTAL_BACKGROUNDS_SELECTOR = '.backgrounds>.slide-background';
|
||||
|
||||
// Methods that may not be invoked via the postMessage API
|
||||
export const POST_MESSAGE_METHOD_BLACKLIST = /registerPlugin|registerKeyboardShortcut|addKeyBinding|addEventListener|showPreview/;
|
||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "reveal.js",
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "reveal.js",
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.5",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "reveal.js",
|
||||
"version": "5.0.3",
|
||||
"version": "5.0.5",
|
||||
"description": "The HTML Presentation Framework",
|
||||
"homepage": "https://revealjs.com",
|
||||
"subdomain": "revealjs",
|
||||
@@ -10,7 +10,8 @@
|
||||
"scripts": {
|
||||
"test": "gulp test",
|
||||
"start": "gulp serve",
|
||||
"build": "gulp build"
|
||||
"build": "gulp build",
|
||||
"dev:react": "npm --prefix ./react run dev"
|
||||
},
|
||||
"author": {
|
||||
"name": "Hakim El Hattab",
|
||||
|
@@ -21,7 +21,7 @@ export const MathJax3 = () => {
|
||||
ready: () => {
|
||||
MathJax.startup.defaultReady();
|
||||
MathJax.startup.promise.then(() => {
|
||||
Reveal.layout();
|
||||
deck.layout();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export const MathJax3 = () => {
|
||||
|
||||
loadScript( url, function() {
|
||||
// Reprocess equations in slides when they turn visible
|
||||
Reveal.addEventListener( 'slidechanged', function( event ) {
|
||||
deck.addEventListener( 'slidechanged', function( event ) {
|
||||
MathJax.typeset();
|
||||
} );
|
||||
} );
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -180,14 +180,16 @@ const Plugin = () => {
|
||||
// (added 12/5/22 as a XSS safeguard)
|
||||
if( isSameOriginEvent( event ) ) {
|
||||
|
||||
let data = JSON.parse( event.data );
|
||||
if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) {
|
||||
clearInterval( connectInterval );
|
||||
onConnected();
|
||||
}
|
||||
else if( data && data.namespace === 'reveal-notes' && data.type === 'call' ) {
|
||||
callRevealApi( data.methodName, data.arguments, data.callId );
|
||||
}
|
||||
try {
|
||||
let data = JSON.parse( event.data );
|
||||
if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) {
|
||||
clearInterval( connectInterval );
|
||||
onConnected();
|
||||
}
|
||||
else if( data && data.namespace === 'reveal-notes' && data.type === 'call' ) {
|
||||
callRevealApi( data.methodName, data.arguments, data.callId );
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -383,6 +383,13 @@
|
||||
|
||||
window.addEventListener( 'message', function( event ) {
|
||||
|
||||
// Validate the origin of all messages to avoid parsing messages
|
||||
// that aren't meant for us. Ignore when running off file:// so
|
||||
// that the speaker view continues to work without a web server.
|
||||
if( window.location.origin !== event.origin && window.location.origin !== 'file://' ) {
|
||||
return
|
||||
}
|
||||
|
||||
clearTimeout( connectionTimeout );
|
||||
connectionStatus.style.display = 'none';
|
||||
|
||||
|
18
react/.eslintrc.cjs
Normal file
18
react/.eslintrc.cjs
Normal file
@@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
24
react/.gitignore
vendored
Normal file
24
react/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
12
react/index.html
Normal file
12
react/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>reveal.js/react</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/demo.tsx"></script>
|
||||
</body>
|
||||
</html>
|
2737
react/package-lock.json
generated
Normal file
2737
react/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
react/package.json
Normal file
28
react/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "reveal-js-react",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.66",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.2.0"
|
||||
}
|
||||
}
|
44
react/src/Reveal.tsx
Normal file
44
react/src/Reveal.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import '../../dist/reveal.css'
|
||||
import '../../dist/theme/black.css'
|
||||
import _Reveal from '../../dist/reveal.esm.js';
|
||||
import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
|
||||
|
||||
|
||||
const Reveal = forwardRef((props: {children: React.ReactNode, [key: string]: any}, ref) => {
|
||||
const {children, ...revealProps} = props;
|
||||
const deckDivRef = useRef<HTMLDivElement>(null);
|
||||
const deckRef = useRef<any>(null);
|
||||
|
||||
useImperativeHandle(ref, () => deckRef.current);
|
||||
|
||||
useEffect(() => {
|
||||
// Prevents double initialization in strict mode
|
||||
if (deckRef.current) return;
|
||||
|
||||
deckRef.current = new _Reveal(deckDivRef.current!, revealProps);
|
||||
deckRef.current.initialize();
|
||||
|
||||
return () => {
|
||||
try {
|
||||
if (deckRef.current) {
|
||||
deckRef.current.destroy();
|
||||
deckRef.current = null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Reveal.js destroy call failed.");
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
// The presentation is sized based on the width and height of
|
||||
// our parent element. Make sure the parent is not 0-height.
|
||||
<div className="reveal" ref={deckDivRef}>
|
||||
<div className="slides">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Reveal;
|
58
react/src/demo.tsx
Normal file
58
react/src/demo.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import Reveal from './Reveal.tsx'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<Demo2 />
|
||||
</React.StrictMode>,
|
||||
)
|
||||
|
||||
function Demo1() {
|
||||
return (
|
||||
<div style={{width: 600, height: 600}}>
|
||||
<Reveal embedded={true}>
|
||||
<section>slide 1</section>
|
||||
<section>slide 2</section>
|
||||
</Reveal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Demo2() {
|
||||
const revealApiRef = React.useRef<any>(null);
|
||||
const [slides, setSlides] = useState<string[]>([
|
||||
'slide 1',
|
||||
'slide 2',
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (revealApiRef.current) {
|
||||
revealApiRef.current.sync();
|
||||
|
||||
// This should not be necessary, the sync() method needs to
|
||||
// be revised to call updateSlides() internally.
|
||||
revealApiRef.current.slide();
|
||||
}
|
||||
}, [slides]);
|
||||
|
||||
return (
|
||||
<div style={{width: 600, height: 600}}>
|
||||
<Reveal embedded={true} ref={revealApiRef}>
|
||||
{slides.map((slide, i) => (
|
||||
<section key={i}>
|
||||
{slide}
|
||||
</section>
|
||||
))}
|
||||
</Reveal>
|
||||
|
||||
<button onClick={() => {
|
||||
setSlides([...slides, `slide ${slides.length + 1}`]);
|
||||
}}>Append slide</button>
|
||||
|
||||
<button onClick={() => {
|
||||
revealApiRef.current.next();
|
||||
}}>Next slide</button>
|
||||
</div>
|
||||
);
|
||||
}
|
1
react/src/vite-env.d.ts
vendored
Normal file
1
react/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
25
react/tsconfig.json
Normal file
25
react/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
11
react/tsconfig.node.json
Normal file
11
react/tsconfig.node.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
7
react/vite.config.ts
Normal file
7
react/vite.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react-swc'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
@@ -97,14 +97,61 @@
|
||||
|
||||
return new Promise( resolve => {
|
||||
let callback = ( event ) => {
|
||||
Reveal.off( 'slidechanged', callback );
|
||||
assert.ok( true, 'slidechanged event fired' );
|
||||
assert.ok( event.currentSlide.classList.contains( 'present' ), 'slidechanged provides reference to currentSlide' );
|
||||
resolve();
|
||||
}
|
||||
Reveal.off( 'slidechanged', callback );
|
||||
assert.ok( true, 'slidechanged event fired' );
|
||||
assert.ok( event.currentSlide.classList.contains( 'present' ), 'slidechanged provides reference to currentSlide' );
|
||||
resolve();
|
||||
}
|
||||
|
||||
Reveal.on( 'slidechanged', callback );
|
||||
Reveal.getViewportElement().scrollTop = getViewportHeight() * 2;
|
||||
Reveal.on( 'slidechanged', callback );
|
||||
Reveal.getViewportElement().scrollTop = getViewportHeight() * 2;
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test( 'Fires fragmentshown event when scrolling', assert => {
|
||||
assert.timeout( 200 );
|
||||
assert.expect( 2 );
|
||||
|
||||
const slides = document.querySelectorAll( '.reveal .slides section' );
|
||||
|
||||
return new Promise( resolve => {
|
||||
let callback = ( event ) => {
|
||||
Reveal.off( 'fragmentshown', callback );
|
||||
assert.ok( true, 'fragmentshown event fired' );
|
||||
assert.ok( event.fragments.length > 0, 'fragmentshown provides reference to fragment nodes' );
|
||||
resolve();
|
||||
}
|
||||
|
||||
Reveal.on( 'fragmentshown', callback );
|
||||
|
||||
Reveal.getViewportElement().scrollTop = 0;
|
||||
Reveal.next();
|
||||
Reveal.next();
|
||||
Reveal.getViewportElement().scrollTop += getViewportHeight();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test( 'Fires fragmenthidden event when scrolling', assert => {
|
||||
assert.timeout( 200 );
|
||||
assert.expect( 2 );
|
||||
|
||||
const slides = document.querySelectorAll( '.reveal .slides section' );
|
||||
|
||||
return new Promise( resolve => {
|
||||
let callback = ( event ) => {
|
||||
Reveal.off( 'fragmenthidden', callback );
|
||||
assert.ok( true, 'fragmenthidden event fired' );
|
||||
assert.ok( event.fragments.length > 0, 'fragmenthidden provides reference to fragment nodes' );
|
||||
resolve();
|
||||
}
|
||||
|
||||
Reveal.on( 'fragmenthidden', callback );
|
||||
|
||||
Reveal.getViewportElement().scrollTop = 0;
|
||||
Reveal.next();
|
||||
Reveal.next();
|
||||
Reveal.next();
|
||||
Reveal.getViewportElement().scrollTop -= getViewportHeight();
|
||||
});
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user