add transitionend event and docs

This commit is contained in:
Hakim El Hattab 2020-04-21 10:54:00 +02:00
parent 91953207a5
commit 8c52b32a18
7 changed files with 83 additions and 25 deletions

View File

@ -28,7 +28,7 @@ This project was started and is maintained by [@hakimel](https://github.com/haki
- [Lazy Loading](#lazy-loading) - [Lazy Loading](#lazy-loading)
- [API](#api) - [API](#api)
- [Custom Key Bindings](#custom-key-bindings) - [Custom Key Bindings](#custom-key-bindings)
- [Slide Changed Event](#slide-changed-event) - [Slide Change Events](#slide-change-events)
- [Presentation State](#presentation-state) - [Presentation State](#presentation-state)
- [Slide States](#slide-states) - [Slide States](#slide-states)
- [Slide Backgrounds](#slide-backgrounds) - [Slide Backgrounds](#slide-backgrounds)
@ -458,8 +458,8 @@ Reveal.js doesn't _rely_ on any third party scripts to work but a few optional l
Reveal.initialize({ Reveal.initialize({
dependencies: [ dependencies: [
// Interpret Markdown in <section> elements // Interpret Markdown in <section> elements
{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, { src: 'plugin/markdown/marked.js', condition: () => { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, { src: 'plugin/markdown/markdown.js', condition: () => { return !!document.querySelector( '[data-markdown]' ); } },
// Syntax highlight for <code> elements // Syntax highlight for <code> elements
{ src: 'plugin/highlight/highlight.js', async: true }, { src: 'plugin/highlight/highlight.js', async: true },
@ -490,7 +490,7 @@ You can also include dependencies which are bundled/already present on the page.
A `ready` event is fired when reveal.js has loaded all non-async dependencies and is ready to start navigating. To check if reveal.js is already 'ready' you can call `Reveal.isReady()`. A `ready` event is fired when reveal.js has loaded all non-async dependencies and is ready to start navigating. To check if reveal.js is already 'ready' you can call `Reveal.isReady()`.
```javascript ```javascript
Reveal.on( 'ready', function( event ) { Reveal.on( 'ready', event => {
// event.currentSlide, event.indexh, event.indexv // event.currentSlide, event.indexh, event.indexv
} ); } );
``` ```
@ -532,7 +532,7 @@ If you're unhappy with any of the default keyboard bindings you can override the
Reveal.configure({ Reveal.configure({
keyboard: { keyboard: {
13: 'next', // go to the next slide when the ENTER key is pressed 13: 'next', // go to the next slide when the ENTER key is pressed
27: function() {}, // do something custom when ESC is pressed 27: () => { console.log('esc') }, // do something custom when ESC is pressed
32: null // don't do anything when SPACE is pressed (i.e. disable a reveal.js default binding) 32: null // don't do anything when SPACE is pressed (i.e. disable a reveal.js default binding)
} }
}); });
@ -598,7 +598,7 @@ Each individual element is decorated with a `data-auto-animate-target` attribute
Each time a presentation navigates between two auto-animated slides it dispatches the `autoanimate` event. Each time a presentation navigates between two auto-animated slides it dispatches the `autoanimate` event.
```javascript ```javascript
Reveal.on( 'autoanimate', function( event ) { Reveal.on( 'autoanimate', event => {
// event.fromSlide, event.toSlide // event.fromSlide, event.toSlide
} ); } );
``` ```
@ -749,12 +749,12 @@ For example
// keyCode: the keycode for binding to the callback // keyCode: the keycode for binding to the callback
// key: the key label to show in the help overlay // key: the key label to show in the help overlay
// description: the description of the action to show in the help overlay // description: the description of the action to show in the help overlay
Reveal.addKeyBinding( { keyCode: 84, key: 'T', description: 'Start timer' }, function() { Reveal.addKeyBinding( { keyCode: 84, key: 'T', description: 'Start timer' }, () => {
// start timer // start timer
} ) } )
// The binding parameter can also be a direct keycode without providing the help description // The binding parameter can also be a direct keycode without providing the help description
Reveal.addKeyBinding( 82, function() { Reveal.addKeyBinding( 82, () => {
// reset timer // reset timer
} ) } )
``` ```
@ -764,18 +764,24 @@ This allows plugins to add key bindings directly to Reveal so they can
* make use of Reveal's pre-processing logic for key handling (for example, ignoring key presses when paused); and * make use of Reveal's pre-processing logic for key handling (for example, ignoring key presses when paused); and
* be included in the help overlay (optional) * be included in the help overlay (optional)
### Slide Changed Event ### Slide Change Events
A `slidechanged` event is fired each time the slide is changed (regardless of state). The event object holds the index values of the current slide as well as a reference to the previous and current slide HTML nodes. A `slidechanged` event is fired each time the slide is changed. The event object holds the index values of the current slide as well as a reference to the previous and current slide DOM nodes.
Some libraries, like MathJax (see [#226](https://github.com/hakimel/reveal.js/issues/226#issuecomment-10261609)), get confused by the transforms and display states of slides. Often times, this can be fixed by calling their update or render function from this callback. Some libraries, like MathJax (see [#226](https://github.com/hakimel/reveal.js/issues/226#issuecomment-10261609)), get confused by the transforms and display states of slides. Often times, this can be fixed by calling their update or render function from this callback.
```javascript ```javascript
Reveal.on( 'slidechanged', function( event ) { Reveal.on( 'slidechanged', event => {
// event.previousSlide, event.currentSlide, event.indexh, event.indexv // event.previousSlide, event.currentSlide, event.indexh, event.indexv
} ); } );
``` ```
The `slidechanged` event fires instantly when the slide changes. If you'd rather invoke your event listener when the slide has finished transitioning and is fully visible, you can use the `slidetransitionend` event. The `slidetransitionend` event includes the same event data as described above.
```javascript
Reveal.on( 'slidetransitionend', event => console.log( event.currentSlide ) );
```
### Presentation State ### Presentation State
The presentation's current state can be fetched by using the `getState` method. A state object contains all of the information required to put the presentation back as it was when `getState` was first called. Sort of like a snapshot. It's a simple object that can easily be stringified and persisted or sent over the wire. The presentation's current state can be fetched by using the `getState` method. A state object contains all of the information required to put the presentation back as it was when `getState` was first called. Sort of like a snapshot. It's a simple object that can easily be stringified and persisted or sent over the wire.
@ -800,7 +806,7 @@ If you set `data-state="somestate"` on a slide `<section>`, "somestate" will be
Furthermore you can also listen to these changes in state via JavaScript: Furthermore you can also listen to these changes in state via JavaScript:
```javascript ```javascript
Reveal.on( 'somestate', function() { Reveal.on( 'somestate', () => {
// TODO: Sprinkle magic // TODO: Sprinkle magic
}, false ); }, false );
``` ```
@ -1007,10 +1013,10 @@ When a slide fragment is either shown or hidden reveal.js will dispatch an event
Some libraries, like MathJax (see #505), get confused by the initially hidden fragment elements. Often times this can be fixed by calling their update or render function from this callback. Some libraries, like MathJax (see #505), get confused by the initially hidden fragment elements. Often times this can be fixed by calling their update or render function from this callback.
```javascript ```javascript
Reveal.on( 'fragmentshown', function( event ) { Reveal.on( 'fragmentshown', event => {
// event.fragment = the fragment DOM element // event.fragment = the fragment DOM element
} ); } );
Reveal.on( 'fragmenthidden', function( event ) { Reveal.on( 'fragmenthidden', event => {
// event.fragment = the fragment DOM element // event.fragment = the fragment DOM element
} ); } );
``` ```
@ -1089,7 +1095,7 @@ Reveal.configure({ slideNumber: true });
Reveal.configure({ slideNumber: 'c/t' }); Reveal.configure({ slideNumber: 'c/t' });
// You can provide a function to fully customize the number: // You can provide a function to fully customize the number:
Reveal.configure({ slideNumber: function( slide ) { Reveal.configure({ slideNumber: slide => {
// Ignore numbering of vertical slides // Ignore numbering of vertical slides
return [ Reveal.getIndices( slide ).h ]; return [ Reveal.getIndices( slide ).h ];
}}); }});
@ -1107,8 +1113,8 @@ Press »ESC« or »O« keys to toggle the overview mode on and off. While you're
as if you were at 1,000 feet above your presentation. The overview mode comes with a few API hooks: as if you were at 1,000 feet above your presentation. The overview mode comes with a few API hooks:
```javascript ```javascript
Reveal.on( 'overviewshown', function( event ) { /* ... */ } ); Reveal.on( 'overviewshown', event => { /* ... */ } );
Reveal.on( 'overviewhidden', function( event ) { /* ... */ } ); Reveal.on( 'overviewhidden', event => { /* ... */ } );
// Toggle the overview mode programmatically // Toggle the overview mode programmatically
Reveal.toggleOverview(); Reveal.toggleOverview();
@ -1154,7 +1160,7 @@ Limitations:
When reveal.js changes the scale of the slides it fires a resize event. You can subscribe to the event to resize your elements accordingly. When reveal.js changes the scale of the slides it fires a resize event. You can subscribe to the event to resize your elements accordingly.
```javascript ```javascript
Reveal.on( 'resize', function( event ) { Reveal.on( 'resize', event => {
// event.scale, event.oldScale, event.size // event.scale, event.oldScale, event.size
} ); } );
``` ```
@ -1172,7 +1178,7 @@ The framework has a built-in postMessage API that can be used when communicating
When reveal.js runs inside of an iframe it can optionally bubble all of its events to the parent. Bubbled events are stringified JSON with three fields: namespace, eventName and state. Here's how you subscribe to them from the parent window: When reveal.js runs inside of an iframe it can optionally bubble all of its events to the parent. Bubbled events are stringified JSON with three fields: namespace, eventName and state. Here's how you subscribe to them from the parent window:
```javascript ```javascript
window.addEventListener( 'message', function( event ) { window.addEventListener( 'message', event => {
var data = JSON.parse( event.data ); var data = JSON.parse( event.data );
if( data.namespace === 'reveal' && data.eventName === 'slidechanged' ) { if( data.namespace === 'reveal' && data.eventName === 'slidechanged' ) {
// Slide changed, see data.state for slide number // Slide changed, see data.state for slide number
@ -1187,7 +1193,7 @@ When you call any method via the postMessage API, reveal.js will dispatch a mess
```javascript ```javascript
<revealWindow>.postMessage( JSON.stringify({ method: 'getTotalSlides' }), '*' ); <revealWindow>.postMessage( JSON.stringify({ method: 'getTotalSlides' }), '*' );
window.addEventListener( 'message', function( event ) { window.addEventListener( 'message', event => {
var data = JSON.parse( event.data ); var data = JSON.parse( event.data );
// `data.method`` is the method that we invoked // `data.method`` is the method that we invoked
if( data.namespace === 'reveal' && data.eventName === 'callback' && data.method === 'getTotalSlides' ) { if( data.namespace === 'reveal' && data.eventName === 'callback' && data.method === 'getTotalSlides' ) {

2
dist/reveal.es5.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/reveal.js vendored

File diff suppressed because one or more lines are too long

2
dist/reveal.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -83,6 +83,9 @@ export default function( revealElement, options ) {
// Flags if the interaction event listeners are bound // Flags if the interaction event listeners are bound
eventsAreBound = false, eventsAreBound = false,
// The current slide transition state; idle or running
transition = 'idle',
// The current auto-slide duration // The current auto-slide duration
autoSlide = 0, autoSlide = 0,
@ -484,6 +487,7 @@ export default function( revealElement, options ) {
if( config.progress ) progress.bind(); if( config.progress ) progress.bind();
controls.bind(); controls.bind();
dom.slides.addEventListener( 'transitionend', onTransitionEnd, false );
dom.pauseOverlay.addEventListener( 'click', resume, false ); dom.pauseOverlay.addEventListener( 'click', resume, false );
if( config.focusBodyOnPageVisibilityChange ) { if( config.focusBodyOnPageVisibilityChange ) {
@ -507,6 +511,7 @@ export default function( revealElement, options ) {
window.removeEventListener( 'hashchange', onWindowHashChange, false ); window.removeEventListener( 'hashchange', onWindowHashChange, false );
window.removeEventListener( 'resize', onWindowResize, false ); window.removeEventListener( 'resize', onWindowResize, false );
dom.slides.removeEventListener( 'transitionend', onTransitionEnd, false );
dom.pauseOverlay.removeEventListener( 'click', resume, false ); dom.pauseOverlay.removeEventListener( 'click', resume, false );
} }
@ -1197,6 +1202,7 @@ export default function( revealElement, options ) {
// Detect if we're moving between two auto-animated slides // Detect if we're moving between two auto-animated slides
if( slideChanged && previousSlide && currentSlide && !overview.isActive() ) { if( slideChanged && previousSlide && currentSlide && !overview.isActive() ) {
// If this is an auto-animated transition, we disable the // If this is an auto-animated transition, we disable the
// regular slide transition // regular slide transition
// //
@ -1207,6 +1213,9 @@ export default function( revealElement, options ) {
autoAnimateTransition = true; autoAnimateTransition = true;
dom.slides.classList.add( 'disable-slide-transitions' ); dom.slides.classList.add( 'disable-slide-transitions' );
} }
transition = 'running';
} }
// Update the visibility of slides now that the indices have changed // Update the visibility of slides now that the indices have changed
@ -2251,6 +2260,23 @@ export default function( revealElement, options ) {
} }
/**
* Event listener for transition end on the current slide.
*
* @param {object} [event]
*/
function onTransitionEnd( event ) {
if( transition === 'running' && /section/gi.test( event.target.nodeName ) ) {
transition = 'idle';
dispatchEvent({
type: 'slidetransitionend',
data: { indexh, indexv, previousSlide, currentSlide }
});
}
}
/** /**
* Handler for the window level 'hashchange' event. * Handler for the window level 'hashchange' event.
* *

View File

@ -16,7 +16,7 @@
<div id="qunit"></div> <div id="qunit"></div>
<div id="qunit-fixture"></div> <div id="qunit-fixture"></div>
<div class="reveal" style="display: none;"> <div class="reveal" style="visibility: hidden;">
<div class="slides"> <div class="slides">
@ -655,6 +655,32 @@
}); });
QUnit.test( 'slidetransitionend', function( assert ) {
assert.expect( 2 );
let done = assert.async( 2 );
let time = Date.now();
let horizontalCallback = event => {
assert.ok( Date.now() - time > 200, 'horizontal event fired' );
done();
let verticalCallback = event => {
assert.ok( true, 'vertical event fired' );
done();
Reveal.off( 'slidetransitionend', verticalCallback );
}
Reveal.off( 'slidetransitionend', horizontalCallback );
Reveal.on( 'slidetransitionend', verticalCallback );
Reveal.slide( 1, 1 );
}
Reveal.slide( 0, 0 );
Reveal.on( 'slidetransitionend', horizontalCallback );
Reveal.slide( 1, 0 );
});
QUnit.test( 'paused', function( assert ) { QUnit.test( 'paused', function( assert ) {
assert.expect( 1 ); assert.expect( 1 );
var done = assert.async(); var done = assert.async();