move fragments to separate controller
This commit is contained in:
		
							parent
							
								
									bdedc56d6f
								
							
						
					
					
						commit
						8a43753000
					
				
					 7 changed files with 1032 additions and 999 deletions
				
			
		
							
								
								
									
										2
									
								
								dist/reveal.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/reveal.min.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										302
									
								
								js/controllers/fragments.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								js/controllers/fragments.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,302 @@
 | 
				
			||||||
 | 
					import { extend, toArray } from '../utils/util.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default class Fragments {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						constructor( Reveal ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.Reveal = Reveal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Shows all fragments in the presentation. Used when
 | 
				
			||||||
 | 
						 * fragments are disabled presentation-wide.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						showAll() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							toArray( this.Reveal.getSlidesElement().querySelectorAll( '.fragment' ) ).forEach( element => {
 | 
				
			||||||
 | 
								element.classList.add( 'visible' );
 | 
				
			||||||
 | 
								element.classList.remove( 'current-fragment' );
 | 
				
			||||||
 | 
							} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns an object describing the available fragment
 | 
				
			||||||
 | 
						 * directions.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @return {{prev: boolean, next: boolean}}
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						availableRoutes() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let currentSlide = this.Reveal.getCurrentSlide();
 | 
				
			||||||
 | 
							if( currentSlide && this.Reveal.getConfig().fragments ) {
 | 
				
			||||||
 | 
								let fragments = currentSlide.querySelectorAll( '.fragment' );
 | 
				
			||||||
 | 
								let hiddenFragments = currentSlide.querySelectorAll( '.fragment:not(.visible)' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return {
 | 
				
			||||||
 | 
									prev: fragments.length - hiddenFragments.length > 0,
 | 
				
			||||||
 | 
									next: !!hiddenFragments.length
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								return { prev: false, next: false };
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Return a sorted fragments list, ordered by an increasing
 | 
				
			||||||
 | 
						 * "data-fragment-index" attribute.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Fragments will be revealed in the order that they are returned by
 | 
				
			||||||
 | 
						 * this function, so you can use the index attributes to control the
 | 
				
			||||||
 | 
						 * order of fragment appearance.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * To maintain a sensible default fragment order, fragments are presumed
 | 
				
			||||||
 | 
						 * to be passed in document order. This function adds a "fragment-index"
 | 
				
			||||||
 | 
						 * attribute to each node if such an attribute is not already present,
 | 
				
			||||||
 | 
						 * and sets that attribute to an integer value which is the position of
 | 
				
			||||||
 | 
						 * the fragment within the fragments list.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param {object[]|*} fragments
 | 
				
			||||||
 | 
						 * @param {boolean} grouped If true the returned array will contain
 | 
				
			||||||
 | 
						 * nested arrays for all fragments with the same index
 | 
				
			||||||
 | 
						 * @return {object[]} sorted Sorted array of fragments
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						sort( fragments, grouped = false ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fragments = toArray( fragments );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let ordered = [],
 | 
				
			||||||
 | 
								unordered = [],
 | 
				
			||||||
 | 
								sorted = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Group ordered and unordered elements
 | 
				
			||||||
 | 
							fragments.forEach( fragment => {
 | 
				
			||||||
 | 
								if( fragment.hasAttribute( 'data-fragment-index' ) ) {
 | 
				
			||||||
 | 
									let index = parseInt( fragment.getAttribute( 'data-fragment-index' ), 10 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if( !ordered[index] ) {
 | 
				
			||||||
 | 
										ordered[index] = [];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									ordered[index].push( fragment );
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									unordered.push( [ fragment ] );
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Append fragments without explicit indices in their
 | 
				
			||||||
 | 
							// DOM order
 | 
				
			||||||
 | 
							ordered = ordered.concat( unordered );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Manually count the index up per group to ensure there
 | 
				
			||||||
 | 
							// are no gaps
 | 
				
			||||||
 | 
							let index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Push all fragments in their sorted order to an array,
 | 
				
			||||||
 | 
							// this flattens the groups
 | 
				
			||||||
 | 
							ordered.forEach( group => {
 | 
				
			||||||
 | 
								group.forEach( fragment => {
 | 
				
			||||||
 | 
									sorted.push( fragment );
 | 
				
			||||||
 | 
									fragment.setAttribute( 'data-fragment-index', index );
 | 
				
			||||||
 | 
								} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								index ++;
 | 
				
			||||||
 | 
							} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return grouped === true ? ordered : sorted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sorts and formats all of fragments in the
 | 
				
			||||||
 | 
						 * presentation.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						sortAll() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.Reveal.getHorizontalSlides().forEach( horizontalSlide => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) );
 | 
				
			||||||
 | 
								verticalSlides.forEach( ( verticalSlide, y ) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									this.sort( verticalSlide.querySelectorAll( '.fragment' ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}, this );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if( verticalSlides.length === 0 ) this.sort( horizontalSlide.querySelectorAll( '.fragment' ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Refreshes the fragments on the current slide so that they
 | 
				
			||||||
 | 
						 * have the appropriate classes (.visible + .current-fragment).
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param {number} [index] The index of the current fragment
 | 
				
			||||||
 | 
						 * @param {array} [fragments] Array containing all fragments
 | 
				
			||||||
 | 
						 * in the current slide
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @return {{shown: array, hidden: array}}
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						update( index, fragments ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let changedFragments = {
 | 
				
			||||||
 | 
								shown: [],
 | 
				
			||||||
 | 
								hidden: []
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let currentSlide = this.Reveal.getCurrentSlide();
 | 
				
			||||||
 | 
							if( currentSlide && this.Reveal.getConfig().fragments ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								fragments = fragments || this.sort( currentSlide.querySelectorAll( '.fragment' ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if( fragments.length ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									let maxIndex = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if( typeof index !== 'number' ) {
 | 
				
			||||||
 | 
										let currentFragment = this.sort( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop();
 | 
				
			||||||
 | 
										if( currentFragment ) {
 | 
				
			||||||
 | 
											index = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									toArray( fragments ).forEach( ( el, i ) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if( el.hasAttribute( 'data-fragment-index' ) ) {
 | 
				
			||||||
 | 
											i = parseInt( el.getAttribute( 'data-fragment-index' ), 10 );
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										maxIndex = Math.max( maxIndex, i );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Visible fragments
 | 
				
			||||||
 | 
										if( i <= index ) {
 | 
				
			||||||
 | 
											if( !el.classList.contains( 'visible' ) ) changedFragments.shown.push( el );
 | 
				
			||||||
 | 
											el.classList.add( 'visible' );
 | 
				
			||||||
 | 
											el.classList.remove( 'current-fragment' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											// Announce the fragments one by one to the Screen Reader
 | 
				
			||||||
 | 
											this.Reveal.announceStatus( this.Reveal.getStatusText( el ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if( i === index ) {
 | 
				
			||||||
 | 
												el.classList.add( 'current-fragment' );
 | 
				
			||||||
 | 
												this.Reveal.slideContent.startEmbeddedContent( el );
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										// Hidden fragments
 | 
				
			||||||
 | 
										else {
 | 
				
			||||||
 | 
											if( el.classList.contains( 'visible' ) ) changedFragments.hidden.push( el );
 | 
				
			||||||
 | 
											el.classList.remove( 'visible' );
 | 
				
			||||||
 | 
											el.classList.remove( 'current-fragment' );
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Write the current fragment index to the slide <section>.
 | 
				
			||||||
 | 
									// This can be used by end users to apply styles based on
 | 
				
			||||||
 | 
									// the current fragment index.
 | 
				
			||||||
 | 
									index = typeof index === 'number' ? index : -1;
 | 
				
			||||||
 | 
									index = Math.max( Math.min( index, maxIndex ), -1 );
 | 
				
			||||||
 | 
									currentSlide.setAttribute( 'data-fragment', index );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return changedFragments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Navigate to the specified slide fragment.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param {?number} index The index of the fragment that
 | 
				
			||||||
 | 
						 * should be shown, -1 means all are invisible
 | 
				
			||||||
 | 
						 * @param {number} offset Integer offset to apply to the
 | 
				
			||||||
 | 
						 * fragment index
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @return {boolean} true if a change was made in any
 | 
				
			||||||
 | 
						 * fragments visibility as part of this call
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						goto( index, offset = 0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let currentSlide = this.Reveal.getCurrentSlide();
 | 
				
			||||||
 | 
							if( currentSlide && this.Reveal.getConfig().fragments ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let fragments = this.sort( currentSlide.querySelectorAll( '.fragment' ) );
 | 
				
			||||||
 | 
								if( fragments.length ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// If no index is specified, find the current
 | 
				
			||||||
 | 
									if( typeof index !== 'number' ) {
 | 
				
			||||||
 | 
										let lastVisibleFragment = this.sort( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if( lastVisibleFragment ) {
 | 
				
			||||||
 | 
											index = parseInt( lastVisibleFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else {
 | 
				
			||||||
 | 
											index = -1;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Apply the offset if there is one
 | 
				
			||||||
 | 
									index += offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									let changedFragments = this.update( index, fragments );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if( changedFragments.hidden.length ) {
 | 
				
			||||||
 | 
										this.Reveal.dispatchEvent( 'fragmenthidden', { fragment: changedFragments.hidden[0], fragments: changedFragments.hidden } );
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if( changedFragments.shown.length ) {
 | 
				
			||||||
 | 
										this.Reveal.dispatchEvent( 'fragmentshown', { fragment: changedFragments.shown[0], fragments: changedFragments.shown } );
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									this.Reveal.updateControls();
 | 
				
			||||||
 | 
									this.Reveal.updateProgress();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if( this.Reveal.getConfig().fragmentInURL ) {
 | 
				
			||||||
 | 
										this.Reveal.writeURL();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return !!( changedFragments.shown.length || changedFragments.hidden.length );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Navigate to the next slide fragment.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @return {boolean} true if there was a next fragment,
 | 
				
			||||||
 | 
						 * false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						next() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return this.goto( null, 1 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Navigate to the previous slide fragment.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @return {boolean} true if there was a previous fragment,
 | 
				
			||||||
 | 
						 * false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						prev() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return this.goto( null, -1 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
import { HORIZONTAL_SLIDES_SELECTOR, VERTICAL_SLIDES_SELECTOR } from '../utils/constants.js'
 | 
					import { HORIZONTAL_SLIDES_SELECTOR, VERTICAL_SLIDES_SELECTOR } from '../utils/constants.js'
 | 
				
			||||||
import { extend, toArray, closestParent } from '../utils/util.js'
 | 
					import { extend, toArray, closestParent } from '../utils/util.js'
 | 
				
			||||||
 | 
					import { isMobile } from '../utils/device.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Handles loading, unloading and playback of slide
 | 
					 * Handles loading, unloading and playback of slide
 | 
				
			||||||
| 
						 | 
					@ -13,6 +14,26 @@ export default class SlideContent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Should the given element be preloaded?
 | 
				
			||||||
 | 
						 * Decides based on local element attributes and global config.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param {HTMLElement} element
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						shouldPreload( element ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Prefer an explicit global preload setting
 | 
				
			||||||
 | 
							let preload = this.Reveal.getConfig().preloadIframes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If no global setting is available, fall back on the element's
 | 
				
			||||||
 | 
							// own preload setting
 | 
				
			||||||
 | 
							if( typeof preload !== 'boolean' ) {
 | 
				
			||||||
 | 
								preload = element.hasAttribute( 'data-preload' );
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return preload;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Called when the given slide is within the configured view
 | 
						 * Called when the given slide is within the configured view
 | 
				
			||||||
	 * distance. Shows the slide element and loads any content
 | 
						 * distance. Shows the slide element and loads any content
 | 
				
			||||||
| 
						 | 
					@ -27,7 +48,7 @@ export default class SlideContent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Media elements with data-src attributes
 | 
							// Media elements with data-src attributes
 | 
				
			||||||
		toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ) ).forEach( element => {
 | 
							toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ) ).forEach( element => {
 | 
				
			||||||
			if( element.tagName !== 'IFRAME' || shouldPreload( element ) ) {
 | 
								if( element.tagName !== 'IFRAME' || this.shouldPreload( element ) ) {
 | 
				
			||||||
				element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
 | 
									element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
 | 
				
			||||||
				element.setAttribute( 'data-lazy-loaded', '' );
 | 
									element.setAttribute( 'data-lazy-loaded', '' );
 | 
				
			||||||
				element.removeAttribute( 'data-src' );
 | 
									element.removeAttribute( 'data-src' );
 | 
				
			||||||
| 
						 | 
					@ -89,7 +110,7 @@ export default class SlideContent {
 | 
				
			||||||
					// Inline video playback works (at least in Mobile Safari) as
 | 
										// Inline video playback works (at least in Mobile Safari) as
 | 
				
			||||||
					// long as the video is muted and the `playsinline` attribute is
 | 
										// long as the video is muted and the `playsinline` attribute is
 | 
				
			||||||
					// present
 | 
										// present
 | 
				
			||||||
					if( isMobileDevice ) {
 | 
										if( isMobile ) {
 | 
				
			||||||
						video.muted = true;
 | 
											video.muted = true;
 | 
				
			||||||
						video.autoplay = true;
 | 
											video.autoplay = true;
 | 
				
			||||||
						video.setAttribute( 'playsinline', '' );
 | 
											video.setAttribute( 'playsinline', '' );
 | 
				
			||||||
| 
						 | 
					@ -126,7 +147,7 @@ export default class SlideContent {
 | 
				
			||||||
			if( backgroundIframeElement ) {
 | 
								if( backgroundIframeElement ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Check if this iframe is eligible to be preloaded
 | 
									// Check if this iframe is eligible to be preloaded
 | 
				
			||||||
				if( shouldPreload( background ) && !/autoplay=(1|true|yes)/gi.test( backgroundIframe ) ) {
 | 
									if( this.shouldPreload( background ) && !/autoplay=(1|true|yes)/gi.test( backgroundIframe ) ) {
 | 
				
			||||||
					if( backgroundIframeElement.getAttribute( 'src' ) !== backgroundIframe ) {
 | 
										if( backgroundIframeElement.getAttribute( 'src' ) !== backgroundIframe ) {
 | 
				
			||||||
						backgroundIframeElement.setAttribute( 'src', backgroundIframe );
 | 
											backgroundIframeElement.setAttribute( 'src', backgroundIframe );
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
| 
						 | 
					@ -222,7 +243,7 @@ export default class SlideContent {
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Prefer an explicit global autoplay setting
 | 
									// Prefer an explicit global autoplay setting
 | 
				
			||||||
				let autoplay = config.autoPlayMedia;
 | 
									let autoplay = this.Reveal.getConfig().autoPlayMedia;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// If no global setting is available, fall back on the element's
 | 
									// If no global setting is available, fall back on the element's
 | 
				
			||||||
				// own autoplay setting
 | 
									// own autoplay setting
 | 
				
			||||||
| 
						 | 
					@ -238,7 +259,7 @@ export default class SlideContent {
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					// Mobile devices never fire a loaded event so instead
 | 
										// Mobile devices never fire a loaded event so instead
 | 
				
			||||||
					// of waiting, we initiate playback
 | 
										// of waiting, we initiate playback
 | 
				
			||||||
					else if( isMobileDevice ) {
 | 
										else if( isMobile ) {
 | 
				
			||||||
						let promise = el.play();
 | 
											let promise = el.play();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						// If autoplay does not work, ensure that the controls are visible so
 | 
											// If autoplay does not work, ensure that the controls are visible so
 | 
				
			||||||
| 
						 | 
					@ -327,7 +348,7 @@ export default class SlideContent {
 | 
				
			||||||
			if( isAttachedToDOM && isVisible ) {
 | 
								if( isAttachedToDOM && isVisible ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Prefer an explicit global autoplay setting
 | 
									// Prefer an explicit global autoplay setting
 | 
				
			||||||
				let autoplay = config.autoPlayMedia;
 | 
									let autoplay = this.Reveal.getConfig().autoPlayMedia;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// If no global setting is available, fall back on the element's
 | 
									// If no global setting is available, fall back on the element's
 | 
				
			||||||
				// own autoplay setting
 | 
									// own autoplay setting
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										453
									
								
								js/reveal.js
									
										
									
									
									
								
							
							
						
						
									
										453
									
								
								js/reveal.js
									
										
									
									
									
								
							| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
import SlideContent from './controllers/slidecontent.js'
 | 
					import SlideContent from './controllers/slidecontent.js'
 | 
				
			||||||
import AutoAnimate from './controllers/autoanimate.js'
 | 
					import AutoAnimate from './controllers/autoanimate.js'
 | 
				
			||||||
 | 
					import Fragments from './controllers/fragments.js'
 | 
				
			||||||
import Plugins from './controllers/plugins.js'
 | 
					import Plugins from './controllers/plugins.js'
 | 
				
			||||||
import Playback from './components/playback.js'
 | 
					import Playback from './components/playback.js'
 | 
				
			||||||
import defaultConfig from './config.js'
 | 
					import defaultConfig from './config.js'
 | 
				
			||||||
| 
						 | 
					@ -19,6 +20,7 @@ import {
 | 
				
			||||||
	closestParent,
 | 
						closestParent,
 | 
				
			||||||
	enterFullscreen
 | 
						enterFullscreen
 | 
				
			||||||
} from './utils/util.js'
 | 
					} from './utils/util.js'
 | 
				
			||||||
 | 
					import { isMobile, isChrome, isAndroid, supportsZoom } from './utils/device.js'
 | 
				
			||||||
import { colorToRgb, colorBrightness } from './utils/color.js'
 | 
					import { colorToRgb, colorBrightness } from './utils/color.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -88,18 +90,12 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		// Controls auto-animations between slides
 | 
							// Controls auto-animations between slides
 | 
				
			||||||
		autoAnimate = new AutoAnimate( Reveal ),
 | 
							autoAnimate = new AutoAnimate( Reveal ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Controls navigation between slide fragments
 | 
				
			||||||
 | 
							fragments = new Fragments( Reveal ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// List of asynchronously loaded reveal.js dependencies
 | 
							// List of asynchronously loaded reveal.js dependencies
 | 
				
			||||||
		asyncDependencies = [],
 | 
							asyncDependencies = [],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Features supported by the browser, see #checkCapabilities()
 | 
					 | 
				
			||||||
		features = {},
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Client is a mobile device, see #checkCapabilities()
 | 
					 | 
				
			||||||
		isMobileDevice,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Client is a desktop Chrome, see #checkCapabilities()
 | 
					 | 
				
			||||||
		isChrome,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Throttles mouse wheel navigation
 | 
							// Throttles mouse wheel navigation
 | 
				
			||||||
		lastMouseWheelStep = 0,
 | 
							lastMouseWheelStep = 0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,8 +146,6 @@ export default function( revealElement, options ) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		checkCapabilities();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Cache references to key DOM elements
 | 
							// Cache references to key DOM elements
 | 
				
			||||||
		dom.wrapper = revealElement;
 | 
							dom.wrapper = revealElement;
 | 
				
			||||||
		dom.slides = revealElement.querySelector( '.slides' );
 | 
							dom.slides = revealElement.querySelector( '.slides' );
 | 
				
			||||||
| 
						 | 
					@ -169,25 +163,6 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Inspect the client to see what features it supports.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function checkCapabilities() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		isMobileDevice = /(iphone|ipod|ipad|android)/gi.test( UA ) ||
 | 
					 | 
				
			||||||
							( navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 ); // iPadOS
 | 
					 | 
				
			||||||
		isChrome = /chrome/i.test( UA ) && !/edge/i.test( UA );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		let testElement = document.createElement( 'div' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Flags if we should use zoom instead of transform to scale
 | 
					 | 
				
			||||||
		// up slides. Zoom produces crisper results but has a lot of
 | 
					 | 
				
			||||||
		// xbrowser quirks so we only use it in whitelsited browsers.
 | 
					 | 
				
			||||||
		features.zoom = 'zoom' in testElement.style && !isMobileDevice &&
 | 
					 | 
				
			||||||
						( isChrome || /Version\/[\d\.]+.*Safari/.test( UA ) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Starts up reveal.js by binding input events and navigating
 | 
						 * Starts up reveal.js by binding input events and navigating
 | 
				
			||||||
	 * to the current URL deeplink if there is one.
 | 
						 * to the current URL deeplink if there is one.
 | 
				
			||||||
| 
						 | 
					@ -258,20 +233,13 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		// Prevent transitions while we're loading
 | 
							// Prevent transitions while we're loading
 | 
				
			||||||
		dom.slides.classList.add( 'no-transition' );
 | 
							dom.slides.classList.add( 'no-transition' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if( isMobileDevice ) {
 | 
							if( isMobile ) {
 | 
				
			||||||
			dom.wrapper.classList.add( 'no-hover' );
 | 
								dom.wrapper.classList.add( 'no-hover' );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			dom.wrapper.classList.remove( 'no-hover' );
 | 
								dom.wrapper.classList.remove( 'no-hover' );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if( /iphone/gi.test( UA ) ) {
 | 
					 | 
				
			||||||
			dom.wrapper.classList.add( 'ua-iphone' );
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			dom.wrapper.classList.remove( 'ua-iphone' );
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Background element
 | 
							// Background element
 | 
				
			||||||
		dom.background = createSingletonNode( dom.wrapper, 'div', 'backgrounds', null );
 | 
							dom.background = createSingletonNode( dom.wrapper, 'div', 'backgrounds', null );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -341,6 +309,15 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Announces the given text to screen readers.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						function announceStatus( value ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dom.statusDiv.textContent = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Converts the given HTML element into a string of text
 | 
						 * Converts the given HTML element into a string of text
 | 
				
			||||||
	 * that can be announced to a screen reader. Hidden
 | 
						 * that can be announced to a screen reader. Hidden
 | 
				
			||||||
| 
						 | 
					@ -492,7 +469,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
					// Each fragment 'group' is an array containing one or more
 | 
										// Each fragment 'group' is an array containing one or more
 | 
				
			||||||
					// fragments. Multiple fragments that appear at the same time
 | 
										// fragments. Multiple fragments that appear at the same time
 | 
				
			||||||
					// are part of the same group.
 | 
										// are part of the same group.
 | 
				
			||||||
					let fragmentGroups = sortFragments( page.querySelectorAll( '.fragment' ), true );
 | 
										let fragmentGroups = fragments.sort( page.querySelectorAll( '.fragment' ), true );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					let previousFragmentStep;
 | 
										let previousFragmentStep;
 | 
				
			||||||
					let previousPage;
 | 
										let previousPage;
 | 
				
			||||||
| 
						 | 
					@ -954,10 +931,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// When fragments are turned off they should be visible
 | 
							// When fragments are turned off they should be visible
 | 
				
			||||||
		if( config.fragments === false ) {
 | 
							if( config.fragments === false ) {
 | 
				
			||||||
			toArray( dom.slides.querySelectorAll( '.fragment' ) ).forEach( element => {
 | 
								fragments.showAll();
 | 
				
			||||||
				element.classList.add( 'visible' );
 | 
					 | 
				
			||||||
				element.classList.remove( 'current-fragment' );
 | 
					 | 
				
			||||||
			} );
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Slide numbers
 | 
							// Slide numbers
 | 
				
			||||||
| 
						 | 
					@ -1057,7 +1031,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Only support touch for Android, fixes double navigations in
 | 
							// Only support touch for Android, fixes double navigations in
 | 
				
			||||||
		// stock browser
 | 
							// stock browser
 | 
				
			||||||
		if( UA.match( /android/gi ) ) {
 | 
							if( isAndroid ) {
 | 
				
			||||||
			pointerEvents = [ 'touchstart' ];
 | 
								pointerEvents = [ 'touchstart' ];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1418,7 +1392,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
				// property where 100x adds up to the correct height.
 | 
									// property where 100x adds up to the correct height.
 | 
				
			||||||
				//
 | 
									//
 | 
				
			||||||
				// https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
 | 
									// https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
 | 
				
			||||||
				if( isMobileDevice ) {
 | 
									if( isMobile ) {
 | 
				
			||||||
					document.documentElement.style.setProperty( '--vh', ( window.innerHeight * 0.01 ) + 'px' );
 | 
										document.documentElement.style.setProperty( '--vh', ( window.innerHeight * 0.01 ) + 'px' );
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1454,7 +1428,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
					// effects are minor differences in text layout and iframe
 | 
										// effects are minor differences in text layout and iframe
 | 
				
			||||||
					// viewports changing size. A 200x200 iframe viewport in a
 | 
										// viewports changing size. A 200x200 iframe viewport in a
 | 
				
			||||||
					// 2x zoomed presentation ends up having a 400x400 viewport.
 | 
										// 2x zoomed presentation ends up having a 400x400 viewport.
 | 
				
			||||||
					if( scale > 1 && features.zoom && window.devicePixelRatio < 2 ) {
 | 
										if( scale > 1 && supportsZoom && window.devicePixelRatio < 2 ) {
 | 
				
			||||||
						dom.slides.style.zoom = scale;
 | 
											dom.slides.style.zoom = scale;
 | 
				
			||||||
						dom.slides.style.left = '';
 | 
											dom.slides.style.left = '';
 | 
				
			||||||
						dom.slides.style.top = '';
 | 
											dom.slides.style.top = '';
 | 
				
			||||||
| 
						 | 
					@ -2060,7 +2034,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Show fragment, if specified
 | 
							// Show fragment, if specified
 | 
				
			||||||
		if( typeof f !== 'undefined' ) {
 | 
							if( typeof f !== 'undefined' ) {
 | 
				
			||||||
			navigateFragment( f );
 | 
								fragments.goto( f );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Dispatch an event if the slide changed
 | 
							// Dispatch an event if the slide changed
 | 
				
			||||||
| 
						 | 
					@ -2126,8 +2100,8 @@ export default function( revealElement, options ) {
 | 
				
			||||||
			slideContent.startEmbeddedContent( currentSlide );
 | 
								slideContent.startEmbeddedContent( currentSlide );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Announce the current slide contents, for screen readers
 | 
							// Announce the current slide contents to screen readers
 | 
				
			||||||
		dom.statusDiv.textContent = getStatusText( currentSlide );
 | 
							announceStatus( getStatusText( currentSlide ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		updateControls();
 | 
							updateControls();
 | 
				
			||||||
		updateProgress();
 | 
							updateProgress();
 | 
				
			||||||
| 
						 | 
					@ -2135,7 +2109,8 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		updateParallax();
 | 
							updateParallax();
 | 
				
			||||||
		updateSlideNumber();
 | 
							updateSlideNumber();
 | 
				
			||||||
		updateNotes();
 | 
							updateNotes();
 | 
				
			||||||
		updateFragments();
 | 
					
 | 
				
			||||||
 | 
							fragments.update();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Update the URL hash
 | 
							// Update the URL hash
 | 
				
			||||||
		writeURL();
 | 
							writeURL();
 | 
				
			||||||
| 
						 | 
					@ -2190,7 +2165,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		// Write the current hash to the URL
 | 
							// Write the current hash to the URL
 | 
				
			||||||
		writeURL();
 | 
							writeURL();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sortAllFragments();
 | 
							fragments.sortAll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		updateControls();
 | 
							updateControls();
 | 
				
			||||||
		updateProgress();
 | 
							updateProgress();
 | 
				
			||||||
| 
						 | 
					@ -2248,7 +2223,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	function syncFragments( slide = currentSlide ) {
 | 
						function syncFragments( slide = currentSlide ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sortFragments( slide.querySelectorAll( '.fragment' ) );
 | 
							return config.sort( slide.querySelectorAll( '.fragment' ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2275,27 +2250,6 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Sorts and formats all of fragments in the
 | 
					 | 
				
			||||||
	 * presentation.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function sortAllFragments() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		getHorizontalSlides().forEach( horizontalSlide => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			let verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) );
 | 
					 | 
				
			||||||
			verticalSlides.forEach( ( verticalSlide, y ) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				sortFragments( verticalSlide.querySelectorAll( '.fragment' ) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			} );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if( verticalSlides.length === 0 ) sortFragments( horizontalSlide.querySelectorAll( '.fragment' ) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		} );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Randomly shuffles all slides in the deck.
 | 
						 * Randomly shuffles all slides in the deck.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
| 
						 | 
					@ -2438,7 +2392,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Shorten the view distance on devices that typically have
 | 
								// Shorten the view distance on devices that typically have
 | 
				
			||||||
			// less resources
 | 
								// less resources
 | 
				
			||||||
			if( isMobileDevice ) {
 | 
								if( isMobile ) {
 | 
				
			||||||
				viewDistance = isOverview() ? 6 : config.mobileViewDistance;
 | 
									viewDistance = isOverview() ? 6 : config.mobileViewDistance;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2657,7 +2611,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
	function updateControls() {
 | 
						function updateControls() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let routes = availableRoutes();
 | 
							let routes = availableRoutes();
 | 
				
			||||||
		let fragments = availableFragments();
 | 
							let fragmentsRoutes = fragments.availableRoutes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Remove the 'enabled' class from all directions
 | 
							// Remove the 'enabled' class from all directions
 | 
				
			||||||
		[...dom.controlsLeft, ...dom.controlsRight, ...dom.controlsUp, ...dom.controlsDown, ...dom.controlsPrev, ...dom.controlsNext].forEach( node => {
 | 
							[...dom.controlsLeft, ...dom.controlsRight, ...dom.controlsUp, ...dom.controlsDown, ...dom.controlsPrev, ...dom.controlsNext].forEach( node => {
 | 
				
			||||||
| 
						 | 
					@ -2681,23 +2635,22 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		if( currentSlide ) {
 | 
							if( currentSlide ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Always apply fragment decorator to prev/next buttons
 | 
								// Always apply fragment decorator to prev/next buttons
 | 
				
			||||||
			if( fragments.prev ) dom.controlsPrev.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
								if( fragmentsRoutes.prev ) dom.controlsPrev.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
				
			||||||
			if( fragments.next ) dom.controlsNext.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
								if( fragmentsRoutes.next ) dom.controlsNext.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Apply fragment decorators to directional buttons based on
 | 
								// Apply fragment decorators to directional buttons based on
 | 
				
			||||||
			// what slide axis they are in
 | 
								// what slide axis they are in
 | 
				
			||||||
			if( isVerticalSlide( currentSlide ) ) {
 | 
								if( isVerticalSlide( currentSlide ) ) {
 | 
				
			||||||
				if( fragments.prev ) dom.controlsUp.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
									if( fragmentsRoutes.prev ) dom.controlsUp.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
				
			||||||
				if( fragments.next ) dom.controlsDown.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
									if( fragmentsRoutes.next ) dom.controlsDown.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else {
 | 
								else {
 | 
				
			||||||
				if( fragments.prev ) dom.controlsLeft.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
									if( fragmentsRoutes.prev ) dom.controlsLeft.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
				
			||||||
				if( fragments.next ) dom.controlsRight.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
									if( fragmentsRoutes.next ) dom.controlsRight.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if( config.controlsTutorial ) {
 | 
							if( config.controlsTutorial ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Highlight control arrows with an animation to ensure
 | 
								// Highlight control arrows with an animation to ensure
 | 
				
			||||||
| 
						 | 
					@ -2790,7 +2743,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		// Stop content inside of previous backgrounds
 | 
							// Stop content inside of previous backgrounds
 | 
				
			||||||
		if( previousBackground ) {
 | 
							if( previousBackground ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			slideContent.stopEmbeddedContent( previousBackground, { unloadIframes: !shouldPreload( previousBackground ) } );
 | 
								slideContent.stopEmbeddedContent( previousBackground, { unloadIframes: !slideContent.shouldPreload( previousBackground ) } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2901,26 +2854,6 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Should the given element be preloaded?
 | 
					 | 
				
			||||||
	 * Decides based on local element attributes and global config.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param {HTMLElement} element
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function shouldPreload( element ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Prefer an explicit global preload setting
 | 
					 | 
				
			||||||
		let preload = config.preloadIframes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// If no global setting is available, fall back on the element's
 | 
					 | 
				
			||||||
		// own preload setting
 | 
					 | 
				
			||||||
		if( typeof preload !== 'boolean' ) {
 | 
					 | 
				
			||||||
			preload = element.hasAttribute( 'data-preload' );
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return preload;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Determine what available routes there are for navigation.
 | 
						 * Determine what available routes there are for navigation.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
| 
						 | 
					@ -2963,29 +2896,6 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Returns an object describing the available fragment
 | 
					 | 
				
			||||||
	 * directions.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @return {{prev: boolean, next: boolean}}
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function availableFragments() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if( currentSlide && config.fragments ) {
 | 
					 | 
				
			||||||
			let fragments = currentSlide.querySelectorAll( '.fragment' );
 | 
					 | 
				
			||||||
			let hiddenFragments = currentSlide.querySelectorAll( '.fragment:not(.visible)' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return {
 | 
					 | 
				
			||||||
				prev: fragments.length - hiddenFragments.length > 0,
 | 
					 | 
				
			||||||
				next: !!hiddenFragments.length
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			return { prev: false, next: false };
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Returns the number of past slides. This can be used as a global
 | 
						 * Returns the number of past slides. This can be used as a global
 | 
				
			||||||
	 * flattened index for slides.
 | 
						 * flattened index for slides.
 | 
				
			||||||
| 
						 | 
					@ -3433,234 +3343,6 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Return a sorted fragments list, ordered by an increasing
 | 
					 | 
				
			||||||
	 * "data-fragment-index" attribute.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * Fragments will be revealed in the order that they are returned by
 | 
					 | 
				
			||||||
	 * this function, so you can use the index attributes to control the
 | 
					 | 
				
			||||||
	 * order of fragment appearance.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * To maintain a sensible default fragment order, fragments are presumed
 | 
					 | 
				
			||||||
	 * to be passed in document order. This function adds a "fragment-index"
 | 
					 | 
				
			||||||
	 * attribute to each node if such an attribute is not already present,
 | 
					 | 
				
			||||||
	 * and sets that attribute to an integer value which is the position of
 | 
					 | 
				
			||||||
	 * the fragment within the fragments list.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param {object[]|*} fragments
 | 
					 | 
				
			||||||
	 * @param {boolean} grouped If true the returned array will contain
 | 
					 | 
				
			||||||
	 * nested arrays for all fragments with the same index
 | 
					 | 
				
			||||||
	 * @return {object[]} sorted Sorted array of fragments
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function sortFragments( fragments, grouped = false ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		fragments = toArray( fragments );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		let ordered = [],
 | 
					 | 
				
			||||||
			unordered = [],
 | 
					 | 
				
			||||||
			sorted = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Group ordered and unordered elements
 | 
					 | 
				
			||||||
		fragments.forEach( fragment => {
 | 
					 | 
				
			||||||
			if( fragment.hasAttribute( 'data-fragment-index' ) ) {
 | 
					 | 
				
			||||||
				let index = parseInt( fragment.getAttribute( 'data-fragment-index' ), 10 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if( !ordered[index] ) {
 | 
					 | 
				
			||||||
					ordered[index] = [];
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				ordered[index].push( fragment );
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else {
 | 
					 | 
				
			||||||
				unordered.push( [ fragment ] );
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Append fragments without explicit indices in their
 | 
					 | 
				
			||||||
		// DOM order
 | 
					 | 
				
			||||||
		ordered = ordered.concat( unordered );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Manually count the index up per group to ensure there
 | 
					 | 
				
			||||||
		// are no gaps
 | 
					 | 
				
			||||||
		let index = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Push all fragments in their sorted order to an array,
 | 
					 | 
				
			||||||
		// this flattens the groups
 | 
					 | 
				
			||||||
		ordered.forEach( group => {
 | 
					 | 
				
			||||||
			group.forEach( fragment => {
 | 
					 | 
				
			||||||
				sorted.push( fragment );
 | 
					 | 
				
			||||||
				fragment.setAttribute( 'data-fragment-index', index );
 | 
					 | 
				
			||||||
			} );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			index ++;
 | 
					 | 
				
			||||||
		} );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return grouped === true ? ordered : sorted;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Refreshes the fragments on the current slide so that they
 | 
					 | 
				
			||||||
	 * have the appropriate classes (.visible + .current-fragment).
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param {number} [index] The index of the current fragment
 | 
					 | 
				
			||||||
	 * @param {array} [fragments] Array containing all fragments
 | 
					 | 
				
			||||||
	 * in the current slide
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @return {{shown: array, hidden: array}}
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function updateFragments( index, fragments ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		let changedFragments = {
 | 
					 | 
				
			||||||
			shown: [],
 | 
					 | 
				
			||||||
			hidden: []
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if( currentSlide && config.fragments ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			fragments = fragments || sortFragments( currentSlide.querySelectorAll( '.fragment' ) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if( fragments.length ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				let maxIndex = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if( typeof index !== 'number' ) {
 | 
					 | 
				
			||||||
					let currentFragment = sortFragments( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop();
 | 
					 | 
				
			||||||
					if( currentFragment ) {
 | 
					 | 
				
			||||||
						index = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				toArray( fragments ).forEach( ( el, i ) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if( el.hasAttribute( 'data-fragment-index' ) ) {
 | 
					 | 
				
			||||||
						i = parseInt( el.getAttribute( 'data-fragment-index' ), 10 );
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					maxIndex = Math.max( maxIndex, i );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					// Visible fragments
 | 
					 | 
				
			||||||
					if( i <= index ) {
 | 
					 | 
				
			||||||
						if( !el.classList.contains( 'visible' ) ) changedFragments.shown.push( el );
 | 
					 | 
				
			||||||
						el.classList.add( 'visible' );
 | 
					 | 
				
			||||||
						el.classList.remove( 'current-fragment' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						// Announce the fragments one by one to the Screen Reader
 | 
					 | 
				
			||||||
						dom.statusDiv.textContent = getStatusText( el );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						if( i === index ) {
 | 
					 | 
				
			||||||
							el.classList.add( 'current-fragment' );
 | 
					 | 
				
			||||||
							slideContent.startEmbeddedContent( el );
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					// Hidden fragments
 | 
					 | 
				
			||||||
					else {
 | 
					 | 
				
			||||||
						if( el.classList.contains( 'visible' ) ) changedFragments.hidden.push( el );
 | 
					 | 
				
			||||||
						el.classList.remove( 'visible' );
 | 
					 | 
				
			||||||
						el.classList.remove( 'current-fragment' );
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				} );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// Write the current fragment index to the slide <section>.
 | 
					 | 
				
			||||||
				// This can be used by end users to apply styles based on
 | 
					 | 
				
			||||||
				// the current fragment index.
 | 
					 | 
				
			||||||
				index = typeof index === 'number' ? index : -1;
 | 
					 | 
				
			||||||
				index = Math.max( Math.min( index, maxIndex ), -1 );
 | 
					 | 
				
			||||||
				currentSlide.setAttribute( 'data-fragment', index );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return changedFragments;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Navigate to the specified slide fragment.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param {?number} index The index of the fragment that
 | 
					 | 
				
			||||||
	 * should be shown, -1 means all are invisible
 | 
					 | 
				
			||||||
	 * @param {number} offset Integer offset to apply to the
 | 
					 | 
				
			||||||
	 * fragment index
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @return {boolean} true if a change was made in any
 | 
					 | 
				
			||||||
	 * fragments visibility as part of this call
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function navigateFragment( index, offset = 0 ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if( currentSlide && config.fragments ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			let fragments = sortFragments( currentSlide.querySelectorAll( '.fragment' ) );
 | 
					 | 
				
			||||||
			if( fragments.length ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// If no index is specified, find the current
 | 
					 | 
				
			||||||
				if( typeof index !== 'number' ) {
 | 
					 | 
				
			||||||
					let lastVisibleFragment = sortFragments( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if( lastVisibleFragment ) {
 | 
					 | 
				
			||||||
						index = parseInt( lastVisibleFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					else {
 | 
					 | 
				
			||||||
						index = -1;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// Apply the offset if there is one
 | 
					 | 
				
			||||||
				index += offset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				let changedFragments = updateFragments( index, fragments );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if( changedFragments.hidden.length ) {
 | 
					 | 
				
			||||||
					dispatchEvent( 'fragmenthidden', { fragment: changedFragments.hidden[0], fragments: changedFragments.hidden } );
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if( changedFragments.shown.length ) {
 | 
					 | 
				
			||||||
					dispatchEvent( 'fragmentshown', { fragment: changedFragments.shown[0], fragments: changedFragments.shown } );
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				updateControls();
 | 
					 | 
				
			||||||
				updateProgress();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if( config.fragmentInURL ) {
 | 
					 | 
				
			||||||
					writeURL();
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				return !!( changedFragments.shown.length || changedFragments.hidden.length );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Navigate to the next slide fragment.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @return {boolean} true if there was a next fragment,
 | 
					 | 
				
			||||||
	 * false otherwise
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function nextFragment() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return navigateFragment( null, 1 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Navigate to the previous slide fragment.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @return {boolean} true if there was a previous fragment,
 | 
					 | 
				
			||||||
	 * false otherwise
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	function prevFragment() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return navigateFragment( null, -1 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Cues a new automated slide if enabled in the config.
 | 
						 * Cues a new automated slide if enabled in the config.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
| 
						 | 
					@ -3719,7 +3401,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
			// - The presentation isn't paused
 | 
								// - The presentation isn't paused
 | 
				
			||||||
			// - The overview isn't active
 | 
								// - The overview isn't active
 | 
				
			||||||
			// - The presentation isn't over
 | 
								// - The presentation isn't over
 | 
				
			||||||
			if( autoSlide && !autoSlidePaused && !isPaused() && !isOverview() && ( !Reveal.isLastSlide() || availableFragments().next || config.loop === true ) ) {
 | 
								if( autoSlide && !autoSlidePaused && !isPaused() && !isOverview() && ( !Reveal.isLastSlide() || fragments.availableRoutes().next || config.loop === true ) ) {
 | 
				
			||||||
				autoSlideTimeout = setTimeout( () => {
 | 
									autoSlideTimeout = setTimeout( () => {
 | 
				
			||||||
					if( typeof config.autoSlideMethod === 'function' ) {
 | 
										if( typeof config.autoSlideMethod === 'function' ) {
 | 
				
			||||||
						config.autoSlideMethod()
 | 
											config.autoSlideMethod()
 | 
				
			||||||
| 
						 | 
					@ -3780,12 +3462,12 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Reverse for RTL
 | 
							// Reverse for RTL
 | 
				
			||||||
		if( config.rtl ) {
 | 
							if( config.rtl ) {
 | 
				
			||||||
			if( ( isOverview() || nextFragment() === false ) && availableRoutes().left ) {
 | 
								if( ( isOverview() || fragments.next() === false ) && availableRoutes().left ) {
 | 
				
			||||||
				slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
 | 
									slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Normal navigation
 | 
							// Normal navigation
 | 
				
			||||||
		else if( ( isOverview() || prevFragment() === false ) && availableRoutes().left ) {
 | 
							else if( ( isOverview() || fragments.prev() === false ) && availableRoutes().left ) {
 | 
				
			||||||
			slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
 | 
								slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3797,12 +3479,12 @@ export default function( revealElement, options ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Reverse for RTL
 | 
							// Reverse for RTL
 | 
				
			||||||
		if( config.rtl ) {
 | 
							if( config.rtl ) {
 | 
				
			||||||
			if( ( isOverview() || prevFragment() === false ) && availableRoutes().right ) {
 | 
								if( ( isOverview() || fragments.prev() === false ) && availableRoutes().right ) {
 | 
				
			||||||
				slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
 | 
									slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Normal navigation
 | 
							// Normal navigation
 | 
				
			||||||
		else if( ( isOverview() || nextFragment() === false ) && availableRoutes().right ) {
 | 
							else if( ( isOverview() || fragments.next() === false ) && availableRoutes().right ) {
 | 
				
			||||||
			slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
 | 
								slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3811,7 +3493,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
	function navigateUp() {
 | 
						function navigateUp() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Prioritize hiding fragments
 | 
							// Prioritize hiding fragments
 | 
				
			||||||
		if( ( isOverview() || prevFragment() === false ) && availableRoutes().up ) {
 | 
							if( ( isOverview() || fragments.prev() === false ) && availableRoutes().up ) {
 | 
				
			||||||
			slide( indexh, indexv - 1 );
 | 
								slide( indexh, indexv - 1 );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3822,7 +3504,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		hasNavigatedVertically = true;
 | 
							hasNavigatedVertically = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Prioritize revealing fragments
 | 
							// Prioritize revealing fragments
 | 
				
			||||||
		if( ( isOverview() || nextFragment() === false ) && availableRoutes().down ) {
 | 
							if( ( isOverview() || fragments.next() === false ) && availableRoutes().down ) {
 | 
				
			||||||
			slide( indexh, indexv + 1 );
 | 
								slide( indexh, indexv + 1 );
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3837,7 +3519,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
	function navigatePrev() {
 | 
						function navigatePrev() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Prioritize revealing fragments
 | 
							// Prioritize revealing fragments
 | 
				
			||||||
		if( prevFragment() === false ) {
 | 
							if( fragments.prev() === false ) {
 | 
				
			||||||
			if( availableRoutes().up ) {
 | 
								if( availableRoutes().up ) {
 | 
				
			||||||
				navigateUp();
 | 
									navigateUp();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -3871,7 +3553,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		hasNavigatedVertically = true;
 | 
							hasNavigatedVertically = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Prioritize revealing fragments
 | 
							// Prioritize revealing fragments
 | 
				
			||||||
		if( nextFragment() === false ) {
 | 
							if( fragments.next() === false ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			let routes = availableRoutes();
 | 
								let routes = availableRoutes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4293,7 +3975,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// There's a bug with swiping on some Android devices unless
 | 
							// There's a bug with swiping on some Android devices unless
 | 
				
			||||||
		// the default action is always prevented
 | 
							// the default action is always prevented
 | 
				
			||||||
		else if( UA.match( /android/gi ) ) {
 | 
							else if( isAndroid ) {
 | 
				
			||||||
			event.preventDefault();
 | 
								event.preventDefault();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4562,9 +4244,9 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		navigateNext: navigateNext,
 | 
							navigateNext: navigateNext,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Fragment methods
 | 
							// Fragment methods
 | 
				
			||||||
		navigateFragment,
 | 
							navigateFragment: () => fragments.goto,
 | 
				
			||||||
		prevFragment,
 | 
							prevFragment: () => fragments.prev,
 | 
				
			||||||
		nextFragment,
 | 
							nextFragment: () => fragments.next,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Forces an update in slide layout
 | 
							// Forces an update in slide layout
 | 
				
			||||||
		layout,
 | 
							layout,
 | 
				
			||||||
| 
						 | 
					@ -4576,7 +4258,7 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		availableRoutes,
 | 
							availableRoutes,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Returns an object with the available fragments as booleans (prev/next)
 | 
							// Returns an object with the available fragments as booleans (prev/next)
 | 
				
			||||||
		availableFragments,
 | 
							availableFragments: () => fragments.availableRoutes(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Toggles a help overlay with keyboard shortcuts
 | 
							// Toggles a help overlay with keyboard shortcuts
 | 
				
			||||||
		toggleHelp,
 | 
							toggleHelp,
 | 
				
			||||||
| 
						 | 
					@ -4650,6 +4332,20 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		addKeyBinding,
 | 
							addKeyBinding,
 | 
				
			||||||
		removeKeyBinding,
 | 
							removeKeyBinding,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Programmatically triggers a keyboard event
 | 
				
			||||||
 | 
							triggerKey: keyCode => onDocumentKeyDown( { keyCode } ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Registers a new shortcut to include in the help overlay
 | 
				
			||||||
 | 
							registerKeyboardShortcut: ( key, value ) => keyboardShortcuts[key] = value,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Forward event binding to the reveal DOM element
 | 
				
			||||||
 | 
							addEventListener: ( type, listener, useCapture ) => {
 | 
				
			||||||
 | 
								Reveal.getRevealElement().addEventListener( type, listener, useCapture );
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							removeEventListener: ( type, listener, useCapture ) => {
 | 
				
			||||||
 | 
								Reveal.getRevealElement().removeEventListener( type, listener, useCapture );
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// API for registering and retrieving plugins
 | 
							// API for registering and retrieving plugins
 | 
				
			||||||
		registerPlugin: (...args) => plugins.registerPlugin( ...args ),
 | 
							registerPlugin: (...args) => plugins.registerPlugin( ...args ),
 | 
				
			||||||
		hasPlugin: (...args) => plugins.hasPlugin( ...args ),
 | 
							hasPlugin: (...args) => plugins.hasPlugin( ...args ),
 | 
				
			||||||
| 
						 | 
					@ -4732,19 +4428,18 @@ export default function( revealElement, options ) {
 | 
				
			||||||
		// Checks if reveal.js has been loaded and is ready for use
 | 
							// Checks if reveal.js has been loaded and is ready for use
 | 
				
			||||||
		isReady: () => ready,
 | 
							isReady: () => ready,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Forward event binding to the reveal DOM element
 | 
					 | 
				
			||||||
		addEventListener: ( type, listener, useCapture ) => {
 | 
					 | 
				
			||||||
			Reveal.getRevealElement().addEventListener( type, listener, useCapture );
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		removeEventListener: ( type, listener, useCapture ) => {
 | 
					 | 
				
			||||||
			Reveal.getRevealElement().removeEventListener( type, listener, useCapture );
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Programmatically triggers a keyboard event
 | 
							// Methods for announcing content to screen readers
 | 
				
			||||||
		triggerKey: keyCode => onDocumentKeyDown( { keyCode } ),
 | 
							announceStatus,
 | 
				
			||||||
 | 
							getStatusText,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Expose direct access to controllers via the API
 | 
				
			||||||
 | 
							slideContent,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							updateControls,
 | 
				
			||||||
 | 
							updateProgress,
 | 
				
			||||||
 | 
							writeURL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Registers a new shortcut to include in the help overlay
 | 
					 | 
				
			||||||
		registerKeyboardShortcut: ( key, value ) => keyboardShortcuts[key] = value
 | 
					 | 
				
			||||||
	} );
 | 
						} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
							
								
								
									
										15
									
								
								js/utils/device.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								js/utils/device.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					const UA = navigator.userAgent;
 | 
				
			||||||
 | 
					const testElement = document.createElement( 'div' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const isMobile = /(iphone|ipod|ipad|android)/gi.test( UA ) ||
 | 
				
			||||||
 | 
											( navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 ); // iPadOS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const isChrome = /chrome/i.test( UA ) && !/edge/i.test( UA );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const isAndroid = /android/gi.test( UA );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Flags if we should use zoom instead of transform to scale
 | 
				
			||||||
 | 
					// up slides. Zoom produces crisper results but has a lot of
 | 
				
			||||||
 | 
					// xbrowser quirks so we only use it in whitelsited browsers.
 | 
				
			||||||
 | 
					export const supportsZoom = 'zoom' in testElement.style && !isMobile &&
 | 
				
			||||||
 | 
									( isChrome || /Version\/[\d\.]+.*Safari/.test( UA ) );
 | 
				
			||||||
							
								
								
									
										614
									
								
								test/test.html
									
										
									
									
									
								
							
							
						
						
									
										614
									
								
								test/test.html
									
										
									
									
									
								
							| 
						 | 
					@ -78,7 +78,619 @@
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		<script src="../dist/reveal.min.js"></script>
 | 
							<script src="../dist/reveal.min.js"></script>
 | 
				
			||||||
		<script src="test.js"></script>
 | 
							<script>
 | 
				
			||||||
 | 
								// These tests expect the DOM to contain a presentation
 | 
				
			||||||
 | 
								// with the following slide structure:
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								// 1
 | 
				
			||||||
 | 
								// 2 - Three sub-slides
 | 
				
			||||||
 | 
								// 3 - Three fragment elements
 | 
				
			||||||
 | 
								// 3 - Two fragments with same data-fragment-index
 | 
				
			||||||
 | 
								// 4
 | 
				
			||||||
 | 
								Reveal.initialize().then( function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// ---------------------------------------------------------------
 | 
				
			||||||
 | 
									// DOM TESTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.module( 'DOM' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Initial slides classes', function( assert ) {
 | 
				
			||||||
 | 
										var horizontalSlides = document.querySelectorAll( '.reveal .slides>section' )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal .slides section.past' ).length, 0, 'no .past slides' );
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal .slides section.present' ).length, 1, 'one .present slide' );
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal .slides>section.future' ).length, horizontalSlides.length - 1, 'remaining horizontal slides are .future' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal .slides section.stack' ).length, 2, 'two .stacks' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										assert.ok( document.querySelectorAll( '.reveal .slides section.stack' )[0].querySelectorAll( '.future' ).length > 0, 'vertical slides are given .future' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// ---------------------------------------------------------------
 | 
				
			||||||
 | 
									// API TESTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.module( 'API' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.isReady', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isReady(), true, 'returns true' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.isOverview', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isOverview(), false, 'false by default' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.toggleOverview();
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isOverview(), true, 'true after toggling on' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.toggleOverview();
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isOverview(), false, 'false after toggling off' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.isPaused', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isPaused(), false, 'false by default' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.togglePause();
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isPaused(), true, 'true after pausing' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.togglePause();
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isPaused(), false, 'false after resuming' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.isFirstSlide', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isFirstSlide(), true, 'true after Reveal.slide( 0, 0 )' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 1, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isFirstSlide(), false, 'false after Reveal.slide( 1, 0 )' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isFirstSlide(), true, 'true after Reveal.slide( 0, 0 )' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.isFirstSlide after vertical slide', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 1, 1 );
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isFirstSlide(), true, 'true after Reveal.slide( 1, 1 ) and then Reveal.slide( 0, 0 )' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.isLastSlide', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isLastSlide(), false, 'false after Reveal.slide( 0, 0 )' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var lastSlideIndex = document.querySelectorAll( '.reveal .slides>section' ).length - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( lastSlideIndex, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isLastSlide(), true, 'true after Reveal.slide( '+ lastSlideIndex +', 0 )' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isLastSlide(), false, 'false after Reveal.slide( 0, 0 )' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.isLastSlide after vertical slide', function( assert ) {
 | 
				
			||||||
 | 
										var lastSlideIndex = document.querySelectorAll( '.reveal .slides>section' ).length - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 1, 1 );
 | 
				
			||||||
 | 
										Reveal.slide( lastSlideIndex );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isLastSlide(), true, 'true after Reveal.slide( 1, 1 ) and then Reveal.slide( '+ lastSlideIndex +', 0 )' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getTotalSlides', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getTotalSlides(), 8, 'eight slides in total' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getIndices', function( assert ) {
 | 
				
			||||||
 | 
										var indices = Reveal.getIndices();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										assert.ok( indices.hasOwnProperty( 'h' ), 'h exists' );
 | 
				
			||||||
 | 
										assert.ok( indices.hasOwnProperty( 'v' ), 'v exists' );
 | 
				
			||||||
 | 
										assert.ok( indices.hasOwnProperty( 'f' ), 'f exists' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 1, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getIndices().h, 1, 'h 1' );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getIndices().v, 0, 'v 0' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 1, 2 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getIndices().h, 1, 'h 1' );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getIndices().v, 2, 'v 2' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getIndices().h, 0, 'h 0' );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getIndices().v, 0, 'v 0' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getSlide', function( assert ) {
 | 
				
			||||||
 | 
										assert.equal( Reveal.getSlide( 0 ), document.querySelector( '.reveal .slides>section:first-child' ), 'gets correct first slide' );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getSlide( 1 ), document.querySelector( '.reveal .slides>section:nth-child(2)' ), 'no v index returns stack' );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getSlide( 1, 0 ), document.querySelector( '.reveal .slides>section:nth-child(2)>section:nth-child(1)' ), 'v index 0 returns first vertical child' );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getSlide( 1, 1 ), document.querySelector( '.reveal .slides>section:nth-child(2)>section:nth-child(2)' ), 'v index 1 returns second vertical child' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getSlide( 100 ), undefined, 'undefined when out of horizontal bounds' );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getSlide( 1, 100 ), undefined, 'undefined when out of vertical bounds' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getSlideBackground', function( assert ) {
 | 
				
			||||||
 | 
										assert.equal( Reveal.getSlideBackground( 0 ), document.querySelector( '.reveal .backgrounds>.slide-background:first-child' ), 'gets correct first background' );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getSlideBackground( 1 ), document.querySelector( '.reveal .backgrounds>.slide-background:nth-child(2)' ), 'no v index returns stack' );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getSlideBackground( 1, 0 ), document.querySelector( '.reveal .backgrounds>.slide-background:nth-child(2) .slide-background:nth-child(2)' ), 'v index 0 returns first vertical child' );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getSlideBackground( 1, 1 ), document.querySelector( '.reveal .backgrounds>.slide-background:nth-child(2) .slide-background:nth-child(3)' ), 'v index 1 returns second vertical child' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getSlideBackground( 100 ), undefined, 'undefined when out of horizontal bounds' );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getSlideBackground( 1, 100 ), undefined, 'undefined when out of vertical bounds' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getSlideNotes', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.ok( Reveal.getSlideNotes() === 'speaker notes 1', 'works with <aside class="notes">' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 1, 0 );
 | 
				
			||||||
 | 
										assert.ok( Reveal.getSlideNotes() === 'speaker notes 2', 'works with <section data-notes="">' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getPreviousSlide/getCurrentSlide', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										Reveal.slide( 1, 0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var firstSlide = document.querySelector( '.reveal .slides>section:first-child' );
 | 
				
			||||||
 | 
										var secondSlide = document.querySelector( '.reveal .slides>section:nth-child(2)>section' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										assert.equal( Reveal.getPreviousSlide(), firstSlide, 'previous is slide #0' );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getCurrentSlide(), secondSlide, 'current is slide #1' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getProgress', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getProgress(), 0, 'progress is 0 on first slide' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var lastSlideIndex = document.querySelectorAll( '.reveal .slides>section' ).length - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( lastSlideIndex, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getProgress(), 1, 'progress is 1 on last slide' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getScale', function( assert ) {
 | 
				
			||||||
 | 
										assert.ok( typeof Reveal.getScale() === 'number', 'has scale' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.getConfig', function( assert ) {
 | 
				
			||||||
 | 
										assert.ok( typeof Reveal.getConfig() === 'object', 'has config' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.configure', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getConfig().loop, false, '"loop" is false to start with' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ loop: true });
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getConfig().loop, true, '"loop" has changed to true' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ loop: false, customTestValue: 1 });
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.getConfig().customTestValue, 1, 'supports custom values' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.availableRoutes', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.availableRoutes(), { left: false, up: false, down: false, right: true }, 'correct for first slide' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 1, 0 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.availableRoutes(), { left: true, up: false, down: true, right: true }, 'correct for vertical slide' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.next', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Step through vertical child slides
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 1, v: 0, f: undefined } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 1, v: 1, f: undefined } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 1, v: 2, f: undefined } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Step through fragments
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: -1 } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 1 } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 2 } );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.next at end', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 3 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// We're at the end, this should have no effect
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 3, v: 0, f: undefined } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 3, v: 0, f: undefined } );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// ---------------------------------------------------------------
 | 
				
			||||||
 | 
									// FRAGMENT TESTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.module( 'Fragments' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Sliding to fragments', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, -1 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: -1 }, 'Reveal.slide( 2, 0, -1 )' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 0 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 }, 'Reveal.slide( 2, 0, 0 )' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 2 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 2 }, 'Reveal.slide( 2, 0, 2 )' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 1 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 1 }, 'Reveal.slide( 2, 0, 1 )' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'data-fragment is set on slide <section>', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, -1 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getCurrentSlide().getAttribute( 'data-fragment' ), '-1' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 2 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getCurrentSlide().getAttribute( 'data-fragment' ), '2' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 0 );
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getCurrentSlide().getAttribute( 'data-fragment' ), '0' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var fragmentSlide = Reveal.getCurrentSlide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 3, 0 );
 | 
				
			||||||
 | 
										assert.deepEqual( fragmentSlide.getAttribute( 'data-fragment' ), '0', 'data-fragment persists when jumping to another slide' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Hiding all fragments', function( assert ) {
 | 
				
			||||||
 | 
										var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 1, 'one fragment visible when index is 0' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, -1 );
 | 
				
			||||||
 | 
										assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 0, 'no fragments visible when index is -1' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Current fragment', function( assert ) {
 | 
				
			||||||
 | 
										var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' );
 | 
				
			||||||
 | 
										var lastFragmentIndex = [].slice.call( fragmentSlide.querySelectorAll( '.fragment' ) ).pop().getAttribute( 'data-fragment-index' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 0, 'no current fragment at index -1' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 1, 'one current fragment at index 0' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 1, 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 0, 'no current fragment when navigating to previous slide' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 3, 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 0, 'no current fragment when navigating to next slide' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 1, -1 );
 | 
				
			||||||
 | 
										Reveal.prev();
 | 
				
			||||||
 | 
										assert.strictEqual( fragmentSlide.querySelector( '.fragment.current-fragment' ).getAttribute( 'data-fragment-index' ), lastFragmentIndex, 'last fragment is current fragment when returning from future slide' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Stepping through fragments', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, -1 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// forwards:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 }, 'next() goes to next fragment' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.right();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 1 }, 'right() goes to next fragment' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.down();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 2 }, 'down() goes to next fragment' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.down(); // moves to f #3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// backwards:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.prev();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 2 }, 'prev() goes to prev fragment' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.left();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 1 }, 'left() goes to prev fragment' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.up();
 | 
				
			||||||
 | 
										assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 }, 'up() goes to prev fragment' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Stepping past fragments', function( assert ) {
 | 
				
			||||||
 | 
										var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0, 0 );
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 0, 'no fragments visible when on previous slide' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 3, 0, 0 );
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 3, 'all fragments visible when on future slide' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Fragment indices', function( assert ) {
 | 
				
			||||||
 | 
										var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(2)' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 3, 0, 0 );
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 2, 'both fragments of same index are shown' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// This slide has three fragments, first one is index 0, second and third have index 1
 | 
				
			||||||
 | 
										Reveal.slide( 2, 2, 0 );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getIndices().f, 0, 'returns correct index for first fragment' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 2, 1 );
 | 
				
			||||||
 | 
										assert.equal( Reveal.getIndices().f, 1, 'returns correct index for two fragments with same index' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Index generation', function( assert ) {
 | 
				
			||||||
 | 
										var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// These have no indices defined to start with
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[0].getAttribute( 'data-fragment-index' ), '0' );
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[1].getAttribute( 'data-fragment-index' ), '1' );
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[2].getAttribute( 'data-fragment-index' ), '2' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Index normalization', function( assert ) {
 | 
				
			||||||
 | 
										var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(3)' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// These start out as 1-4-4 and should normalize to 0-1-1
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[0].getAttribute( 'data-fragment-index' ), '0' );
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[1].getAttribute( 'data-fragment-index' ), '1' );
 | 
				
			||||||
 | 
										assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[2].getAttribute( 'data-fragment-index' ), '1' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'fragmentshown event', function( assert ) {
 | 
				
			||||||
 | 
										assert.expect( 2 );
 | 
				
			||||||
 | 
										var done = assert.async( 2 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var _onEvent = function( event ) {
 | 
				
			||||||
 | 
											assert.ok( true, 'event fired' );
 | 
				
			||||||
 | 
											done();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.addEventListener( 'fragmentshown', _onEvent );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0 );
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0 ); // should do nothing
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 0 ); // should do nothing
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										Reveal.next();
 | 
				
			||||||
 | 
										Reveal.prev(); // shouldn't fire fragmentshown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.removeEventListener( 'fragmentshown', _onEvent );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'fragmenthidden event', function( assert ) {
 | 
				
			||||||
 | 
										assert.expect( 2 );
 | 
				
			||||||
 | 
										var done = assert.async( 2 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var _onEvent = function( event ) {
 | 
				
			||||||
 | 
											assert.ok( true, 'event fired' );
 | 
				
			||||||
 | 
											done();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.addEventListener( 'fragmenthidden', _onEvent );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 2 );
 | 
				
			||||||
 | 
										Reveal.slide( 2, 0, 2 ); // should do nothing
 | 
				
			||||||
 | 
										Reveal.prev();
 | 
				
			||||||
 | 
										Reveal.prev();
 | 
				
			||||||
 | 
										Reveal.next(); // shouldn't fire fragmenthidden
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.removeEventListener( 'fragmenthidden', _onEvent );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// ---------------------------------------------------------------
 | 
				
			||||||
 | 
									// AUTO-SLIDE TESTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.module( 'Auto Sliding' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.isAutoSliding', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isAutoSliding(), false, 'false by default' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ autoSlide: 10000 });
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isAutoSliding(), true, 'true after starting' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ autoSlide: 0 });
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isAutoSliding(), false, 'false after setting to 0' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Reveal.toggleAutoSlide', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.configure({ autoSlide: 10000 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.toggleAutoSlide();
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isAutoSliding(), false, 'false after first toggle' );
 | 
				
			||||||
 | 
										Reveal.toggleAutoSlide();
 | 
				
			||||||
 | 
										assert.strictEqual( Reveal.isAutoSliding(), true, 'true after second toggle' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ autoSlide: 0 });
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'autoslidepaused', function( assert ) {
 | 
				
			||||||
 | 
										assert.expect( 1 );
 | 
				
			||||||
 | 
										var done = assert.async();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var _onEvent = function( event ) {
 | 
				
			||||||
 | 
											assert.ok( true, 'event fired' );
 | 
				
			||||||
 | 
											done();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.addEventListener( 'autoslidepaused', _onEvent );
 | 
				
			||||||
 | 
										Reveal.configure({ autoSlide: 10000 });
 | 
				
			||||||
 | 
										Reveal.toggleAutoSlide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// cleanup
 | 
				
			||||||
 | 
										Reveal.configure({ autoSlide: 0 });
 | 
				
			||||||
 | 
										Reveal.removeEventListener( 'autoslidepaused', _onEvent );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'autoslideresumed', function( assert ) {
 | 
				
			||||||
 | 
										assert.expect( 1 );
 | 
				
			||||||
 | 
										var done = assert.async();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var _onEvent = function( event ) {
 | 
				
			||||||
 | 
											assert.ok( true, 'event fired' );
 | 
				
			||||||
 | 
											done();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.addEventListener( 'autoslideresumed', _onEvent );
 | 
				
			||||||
 | 
										Reveal.configure({ autoSlide: 10000 });
 | 
				
			||||||
 | 
										Reveal.toggleAutoSlide();
 | 
				
			||||||
 | 
										Reveal.toggleAutoSlide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// cleanup
 | 
				
			||||||
 | 
										Reveal.configure({ autoSlide: 0 });
 | 
				
			||||||
 | 
										Reveal.removeEventListener( 'autoslideresumed', _onEvent );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// ---------------------------------------------------------------
 | 
				
			||||||
 | 
									// CONFIGURATION VALUES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.module( 'Configuration' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Controls', function( assert ) {
 | 
				
			||||||
 | 
										var controlsElement = document.querySelector( '.reveal>.controls' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ controls: false });
 | 
				
			||||||
 | 
										assert.equal( controlsElement.style.display, 'none', 'controls are hidden' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ controls: true });
 | 
				
			||||||
 | 
										assert.equal( controlsElement.style.display, 'block', 'controls are visible' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Progress', function( assert ) {
 | 
				
			||||||
 | 
										var progressElement = document.querySelector( '.reveal>.progress' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ progress: false });
 | 
				
			||||||
 | 
										assert.equal( progressElement.style.display, 'none', 'progress are hidden' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ progress: true });
 | 
				
			||||||
 | 
										assert.equal( progressElement.style.display, 'block', 'progress are visible' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'Loop', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.configure({ loop: true });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.left();
 | 
				
			||||||
 | 
										assert.notEqual( Reveal.getIndices().h, 0, 'looped from start to end' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.right();
 | 
				
			||||||
 | 
										assert.equal( Reveal.getIndices().h, 0, 'looped from end to start' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.configure({ loop: false });
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// ---------------------------------------------------------------
 | 
				
			||||||
 | 
									// LAZY-LOADING TESTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.module( 'Lazy-Loading' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'img with data-src', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal section img[src]' ).length, 1, 'Image source has been set' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'video with data-src', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal section video[src]' ).length, 1, 'Video source has been set' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'audio with data-src', function( assert ) {
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal section audio[src]' ).length, 1, 'Audio source has been set' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'iframe with data-src', function( assert ) {
 | 
				
			||||||
 | 
										Reveal.slide( 0, 0 );
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal section iframe[src]' ).length, 0, 'Iframe source is not set' );
 | 
				
			||||||
 | 
										Reveal.slide( 2, 1 );
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal section iframe[src]' ).length, 1, 'Iframe source is set' );
 | 
				
			||||||
 | 
										Reveal.slide( 2, 2 );
 | 
				
			||||||
 | 
										assert.strictEqual( document.querySelectorAll( '.reveal section iframe[src]' ).length, 0, 'Iframe source is not set' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'background images', function( assert ) {
 | 
				
			||||||
 | 
										var imageSource1 = Reveal.getSlide( 0 ).getAttribute( 'data-background-image' );
 | 
				
			||||||
 | 
										var imageSource2 = Reveal.getSlide( 1, 0 ).getAttribute( 'data-background' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// check that the images are applied to the background elements
 | 
				
			||||||
 | 
										assert.ok( Reveal.getSlideBackground( 0 ).querySelector( '.slide-background-content' ).style.backgroundImage.indexOf( imageSource1 ) !== -1, 'data-background-image worked' );
 | 
				
			||||||
 | 
										assert.ok( Reveal.getSlideBackground( 1, 0 ).querySelector( '.slide-background-content' ).style.backgroundImage.indexOf( imageSource2 ) !== -1, 'data-background worked' );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// ---------------------------------------------------------------
 | 
				
			||||||
 | 
									// EVENT TESTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.module( 'Events' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'slidechanged', function( assert ) {
 | 
				
			||||||
 | 
										assert.expect( 3 );
 | 
				
			||||||
 | 
										var done = assert.async( 3 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var _onEvent = function( event ) {
 | 
				
			||||||
 | 
											assert.ok( true, 'event fired' );
 | 
				
			||||||
 | 
											done();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.addEventListener( 'slidechanged', _onEvent );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.slide( 1, 0 ); // should trigger
 | 
				
			||||||
 | 
										Reveal.slide( 1, 0 ); // should do nothing
 | 
				
			||||||
 | 
										Reveal.next(); // should trigger
 | 
				
			||||||
 | 
										Reveal.slide( 3, 0 ); // should trigger
 | 
				
			||||||
 | 
										Reveal.next(); // should do nothing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.removeEventListener( 'slidechanged', _onEvent );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'paused', function( assert ) {
 | 
				
			||||||
 | 
										assert.expect( 1 );
 | 
				
			||||||
 | 
										var done = assert.async();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var _onEvent = function( event ) {
 | 
				
			||||||
 | 
											assert.ok( true, 'event fired' );
 | 
				
			||||||
 | 
											done();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.addEventListener( 'paused', _onEvent );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.togglePause();
 | 
				
			||||||
 | 
										Reveal.togglePause();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.removeEventListener( 'paused', _onEvent );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									QUnit.test( 'resumed', function( assert ) {
 | 
				
			||||||
 | 
										assert.expect( 1 );
 | 
				
			||||||
 | 
										var done = assert.async();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var _onEvent = function( event ) {
 | 
				
			||||||
 | 
											assert.ok( true, 'event fired' );
 | 
				
			||||||
 | 
											done();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.addEventListener( 'resumed', _onEvent );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.togglePause();
 | 
				
			||||||
 | 
										Reveal.togglePause();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Reveal.removeEventListener( 'resumed', _onEvent );
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} );
 | 
				
			||||||
 | 
							</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	</body>
 | 
						</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										612
									
								
								test/test.js
									
										
									
									
									
								
							
							
						
						
									
										612
									
								
								test/test.js
									
										
									
									
									
								
							| 
						 | 
					@ -1,612 +0,0 @@
 | 
				
			||||||
// These tests expect the DOM to contain a presentation
 | 
					 | 
				
			||||||
// with the following slide structure:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 1
 | 
					 | 
				
			||||||
// 2 - Three sub-slides
 | 
					 | 
				
			||||||
// 3 - Three fragment elements
 | 
					 | 
				
			||||||
// 3 - Two fragments with same data-fragment-index
 | 
					 | 
				
			||||||
// 4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Reveal.initialize().then( function() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ---------------------------------------------------------------
 | 
					 | 
				
			||||||
	// DOM TESTS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.module( 'DOM' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Initial slides classes', function( assert ) {
 | 
					 | 
				
			||||||
		var horizontalSlides = document.querySelectorAll( '.reveal .slides>section' )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal .slides section.past' ).length, 0, 'no .past slides' );
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal .slides section.present' ).length, 1, 'one .present slide' );
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal .slides>section.future' ).length, horizontalSlides.length - 1, 'remaining horizontal slides are .future' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal .slides section.stack' ).length, 2, 'two .stacks' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert.ok( document.querySelectorAll( '.reveal .slides section.stack' )[0].querySelectorAll( '.future' ).length > 0, 'vertical slides are given .future' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ---------------------------------------------------------------
 | 
					 | 
				
			||||||
	// API TESTS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.module( 'API' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.isReady', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isReady(), true, 'returns true' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.isOverview', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isOverview(), false, 'false by default' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.toggleOverview();
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isOverview(), true, 'true after toggling on' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.toggleOverview();
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isOverview(), false, 'false after toggling off' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.isPaused', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isPaused(), false, 'false by default' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.togglePause();
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isPaused(), true, 'true after pausing' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.togglePause();
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isPaused(), false, 'false after resuming' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.isFirstSlide', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isFirstSlide(), true, 'true after Reveal.slide( 0, 0 )' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isFirstSlide(), false, 'false after Reveal.slide( 1, 0 )' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isFirstSlide(), true, 'true after Reveal.slide( 0, 0 )' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.isFirstSlide after vertical slide', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 1 );
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isFirstSlide(), true, 'true after Reveal.slide( 1, 1 ) and then Reveal.slide( 0, 0 )' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.isLastSlide', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isLastSlide(), false, 'false after Reveal.slide( 0, 0 )' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var lastSlideIndex = document.querySelectorAll( '.reveal .slides>section' ).length - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( lastSlideIndex, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isLastSlide(), true, 'true after Reveal.slide( '+ lastSlideIndex +', 0 )' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isLastSlide(), false, 'false after Reveal.slide( 0, 0 )' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.isLastSlide after vertical slide', function( assert ) {
 | 
					 | 
				
			||||||
		var lastSlideIndex = document.querySelectorAll( '.reveal .slides>section' ).length - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 1 );
 | 
					 | 
				
			||||||
		Reveal.slide( lastSlideIndex );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isLastSlide(), true, 'true after Reveal.slide( 1, 1 ) and then Reveal.slide( '+ lastSlideIndex +', 0 )' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getTotalSlides', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getTotalSlides(), 8, 'eight slides in total' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getIndices', function( assert ) {
 | 
					 | 
				
			||||||
		var indices = Reveal.getIndices();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert.ok( indices.hasOwnProperty( 'h' ), 'h exists' );
 | 
					 | 
				
			||||||
		assert.ok( indices.hasOwnProperty( 'v' ), 'v exists' );
 | 
					 | 
				
			||||||
		assert.ok( indices.hasOwnProperty( 'f' ), 'f exists' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getIndices().h, 1, 'h 1' );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getIndices().v, 0, 'v 0' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 2 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getIndices().h, 1, 'h 1' );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getIndices().v, 2, 'v 2' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getIndices().h, 0, 'h 0' );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getIndices().v, 0, 'v 0' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getSlide', function( assert ) {
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getSlide( 0 ), document.querySelector( '.reveal .slides>section:first-child' ), 'gets correct first slide' );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getSlide( 1 ), document.querySelector( '.reveal .slides>section:nth-child(2)' ), 'no v index returns stack' );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getSlide( 1, 0 ), document.querySelector( '.reveal .slides>section:nth-child(2)>section:nth-child(1)' ), 'v index 0 returns first vertical child' );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getSlide( 1, 1 ), document.querySelector( '.reveal .slides>section:nth-child(2)>section:nth-child(2)' ), 'v index 1 returns second vertical child' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getSlide( 100 ), undefined, 'undefined when out of horizontal bounds' );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getSlide( 1, 100 ), undefined, 'undefined when out of vertical bounds' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getSlideBackground', function( assert ) {
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getSlideBackground( 0 ), document.querySelector( '.reveal .backgrounds>.slide-background:first-child' ), 'gets correct first background' );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getSlideBackground( 1 ), document.querySelector( '.reveal .backgrounds>.slide-background:nth-child(2)' ), 'no v index returns stack' );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getSlideBackground( 1, 0 ), document.querySelector( '.reveal .backgrounds>.slide-background:nth-child(2) .slide-background:nth-child(2)' ), 'v index 0 returns first vertical child' );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getSlideBackground( 1, 1 ), document.querySelector( '.reveal .backgrounds>.slide-background:nth-child(2) .slide-background:nth-child(3)' ), 'v index 1 returns second vertical child' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getSlideBackground( 100 ), undefined, 'undefined when out of horizontal bounds' );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getSlideBackground( 1, 100 ), undefined, 'undefined when out of vertical bounds' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getSlideNotes', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.ok( Reveal.getSlideNotes() === 'speaker notes 1', 'works with <aside class="notes">' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 0 );
 | 
					 | 
				
			||||||
		assert.ok( Reveal.getSlideNotes() === 'speaker notes 2', 'works with <section data-notes="">' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getPreviousSlide/getCurrentSlide', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 0 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var firstSlide = document.querySelector( '.reveal .slides>section:first-child' );
 | 
					 | 
				
			||||||
		var secondSlide = document.querySelector( '.reveal .slides>section:nth-child(2)>section' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getPreviousSlide(), firstSlide, 'previous is slide #0' );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getCurrentSlide(), secondSlide, 'current is slide #1' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getProgress', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getProgress(), 0, 'progress is 0 on first slide' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var lastSlideIndex = document.querySelectorAll( '.reveal .slides>section' ).length - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( lastSlideIndex, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getProgress(), 1, 'progress is 1 on last slide' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getScale', function( assert ) {
 | 
					 | 
				
			||||||
		assert.ok( typeof Reveal.getScale() === 'number', 'has scale' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.getConfig', function( assert ) {
 | 
					 | 
				
			||||||
		assert.ok( typeof Reveal.getConfig() === 'object', 'has config' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.configure', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getConfig().loop, false, '"loop" is false to start with' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ loop: true });
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getConfig().loop, true, '"loop" has changed to true' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ loop: false, customTestValue: 1 });
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.getConfig().customTestValue, 1, 'supports custom values' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.availableRoutes', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.availableRoutes(), { left: false, up: false, down: false, right: true }, 'correct for first slide' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 0 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.availableRoutes(), { left: true, up: false, down: true, right: true }, 'correct for vertical slide' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.next', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Step through vertical child slides
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 1, v: 0, f: undefined } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 1, v: 1, f: undefined } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 1, v: 2, f: undefined } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Step through fragments
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: -1 } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 1 } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 2 } );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.next at end', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 3 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// We're at the end, this should have no effect
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 3, v: 0, f: undefined } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 3, v: 0, f: undefined } );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ---------------------------------------------------------------
 | 
					 | 
				
			||||||
	// FRAGMENT TESTS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.module( 'Fragments' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Sliding to fragments', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, -1 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: -1 }, 'Reveal.slide( 2, 0, -1 )' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 0 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 }, 'Reveal.slide( 2, 0, 0 )' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 2 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 2 }, 'Reveal.slide( 2, 0, 2 )' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 1 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 1 }, 'Reveal.slide( 2, 0, 1 )' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'data-fragment is set on slide <section>', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, -1 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getCurrentSlide().getAttribute( 'data-fragment' ), '-1' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 2 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getCurrentSlide().getAttribute( 'data-fragment' ), '2' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 0 );
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getCurrentSlide().getAttribute( 'data-fragment' ), '0' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var fragmentSlide = Reveal.getCurrentSlide();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 3, 0 );
 | 
					 | 
				
			||||||
		assert.deepEqual( fragmentSlide.getAttribute( 'data-fragment' ), '0', 'data-fragment persists when jumping to another slide' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Hiding all fragments', function( assert ) {
 | 
					 | 
				
			||||||
		var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 1, 'one fragment visible when index is 0' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, -1 );
 | 
					 | 
				
			||||||
		assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 0, 'no fragments visible when index is -1' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Current fragment', function( assert ) {
 | 
					 | 
				
			||||||
		var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' );
 | 
					 | 
				
			||||||
		var lastFragmentIndex = [].slice.call( fragmentSlide.querySelectorAll( '.fragment' ) ).pop().getAttribute( 'data-fragment-index' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 0, 'no current fragment at index -1' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 1, 'one current fragment at index 0' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 0, 'no current fragment when navigating to previous slide' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 3, 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 0, 'no current fragment when navigating to next slide' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 1, -1 );
 | 
					 | 
				
			||||||
		Reveal.prev();
 | 
					 | 
				
			||||||
		assert.strictEqual( fragmentSlide.querySelector( '.fragment.current-fragment' ).getAttribute( 'data-fragment-index' ), lastFragmentIndex, 'last fragment is current fragment when returning from future slide' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Stepping through fragments', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, -1 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// forwards:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 }, 'next() goes to next fragment' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.right();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 1 }, 'right() goes to next fragment' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.down();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 2 }, 'down() goes to next fragment' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.down(); // moves to f #3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// backwards:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.prev();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 2 }, 'prev() goes to prev fragment' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.left();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 1 }, 'left() goes to prev fragment' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.up();
 | 
					 | 
				
			||||||
		assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: 0 }, 'up() goes to prev fragment' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Stepping past fragments', function( assert ) {
 | 
					 | 
				
			||||||
		var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0, 0 );
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 0, 'no fragments visible when on previous slide' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 3, 0, 0 );
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 3, 'all fragments visible when on future slide' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Fragment indices', function( assert ) {
 | 
					 | 
				
			||||||
		var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(2)' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 3, 0, 0 );
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment.visible' ).length, 2, 'both fragments of same index are shown' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// This slide has three fragments, first one is index 0, second and third have index 1
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 2, 0 );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getIndices().f, 0, 'returns correct index for first fragment' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 2, 1 );
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getIndices().f, 1, 'returns correct index for two fragments with same index' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Index generation', function( assert ) {
 | 
					 | 
				
			||||||
		var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// These have no indices defined to start with
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[0].getAttribute( 'data-fragment-index' ), '0' );
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[1].getAttribute( 'data-fragment-index' ), '1' );
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[2].getAttribute( 'data-fragment-index' ), '2' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Index normalization', function( assert ) {
 | 
					 | 
				
			||||||
		var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(3)' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// These start out as 1-4-4 and should normalize to 0-1-1
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[0].getAttribute( 'data-fragment-index' ), '0' );
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[1].getAttribute( 'data-fragment-index' ), '1' );
 | 
					 | 
				
			||||||
		assert.equal( fragmentSlide.querySelectorAll( '.fragment' )[2].getAttribute( 'data-fragment-index' ), '1' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'fragmentshown event', function( assert ) {
 | 
					 | 
				
			||||||
		assert.expect( 2 );
 | 
					 | 
				
			||||||
		var done = assert.async( 2 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var _onEvent = function( event ) {
 | 
					 | 
				
			||||||
			assert.ok( true, 'event fired' );
 | 
					 | 
				
			||||||
			done();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.addEventListener( 'fragmentshown', _onEvent );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0 );
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0 ); // should do nothing
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 0 ); // should do nothing
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		Reveal.next();
 | 
					 | 
				
			||||||
		Reveal.prev(); // shouldn't fire fragmentshown
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.removeEventListener( 'fragmentshown', _onEvent );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'fragmenthidden event', function( assert ) {
 | 
					 | 
				
			||||||
		assert.expect( 2 );
 | 
					 | 
				
			||||||
		var done = assert.async( 2 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var _onEvent = function( event ) {
 | 
					 | 
				
			||||||
			assert.ok( true, 'event fired' );
 | 
					 | 
				
			||||||
			done();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.addEventListener( 'fragmenthidden', _onEvent );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 2 );
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 0, 2 ); // should do nothing
 | 
					 | 
				
			||||||
		Reveal.prev();
 | 
					 | 
				
			||||||
		Reveal.prev();
 | 
					 | 
				
			||||||
		Reveal.next(); // shouldn't fire fragmenthidden
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.removeEventListener( 'fragmenthidden', _onEvent );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ---------------------------------------------------------------
 | 
					 | 
				
			||||||
	// AUTO-SLIDE TESTS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.module( 'Auto Sliding' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.isAutoSliding', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isAutoSliding(), false, 'false by default' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ autoSlide: 10000 });
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isAutoSliding(), true, 'true after starting' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ autoSlide: 0 });
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isAutoSliding(), false, 'false after setting to 0' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Reveal.toggleAutoSlide', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.configure({ autoSlide: 10000 });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.toggleAutoSlide();
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isAutoSliding(), false, 'false after first toggle' );
 | 
					 | 
				
			||||||
		Reveal.toggleAutoSlide();
 | 
					 | 
				
			||||||
		assert.strictEqual( Reveal.isAutoSliding(), true, 'true after second toggle' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ autoSlide: 0 });
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'autoslidepaused', function( assert ) {
 | 
					 | 
				
			||||||
		assert.expect( 1 );
 | 
					 | 
				
			||||||
		var done = assert.async();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var _onEvent = function( event ) {
 | 
					 | 
				
			||||||
			assert.ok( true, 'event fired' );
 | 
					 | 
				
			||||||
			done();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.addEventListener( 'autoslidepaused', _onEvent );
 | 
					 | 
				
			||||||
		Reveal.configure({ autoSlide: 10000 });
 | 
					 | 
				
			||||||
		Reveal.toggleAutoSlide();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// cleanup
 | 
					 | 
				
			||||||
		Reveal.configure({ autoSlide: 0 });
 | 
					 | 
				
			||||||
		Reveal.removeEventListener( 'autoslidepaused', _onEvent );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'autoslideresumed', function( assert ) {
 | 
					 | 
				
			||||||
		assert.expect( 1 );
 | 
					 | 
				
			||||||
		var done = assert.async();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var _onEvent = function( event ) {
 | 
					 | 
				
			||||||
			assert.ok( true, 'event fired' );
 | 
					 | 
				
			||||||
			done();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.addEventListener( 'autoslideresumed', _onEvent );
 | 
					 | 
				
			||||||
		Reveal.configure({ autoSlide: 10000 });
 | 
					 | 
				
			||||||
		Reveal.toggleAutoSlide();
 | 
					 | 
				
			||||||
		Reveal.toggleAutoSlide();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// cleanup
 | 
					 | 
				
			||||||
		Reveal.configure({ autoSlide: 0 });
 | 
					 | 
				
			||||||
		Reveal.removeEventListener( 'autoslideresumed', _onEvent );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ---------------------------------------------------------------
 | 
					 | 
				
			||||||
	// CONFIGURATION VALUES
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.module( 'Configuration' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Controls', function( assert ) {
 | 
					 | 
				
			||||||
		var controlsElement = document.querySelector( '.reveal>.controls' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ controls: false });
 | 
					 | 
				
			||||||
		assert.equal( controlsElement.style.display, 'none', 'controls are hidden' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ controls: true });
 | 
					 | 
				
			||||||
		assert.equal( controlsElement.style.display, 'block', 'controls are visible' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Progress', function( assert ) {
 | 
					 | 
				
			||||||
		var progressElement = document.querySelector( '.reveal>.progress' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ progress: false });
 | 
					 | 
				
			||||||
		assert.equal( progressElement.style.display, 'none', 'progress are hidden' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ progress: true });
 | 
					 | 
				
			||||||
		assert.equal( progressElement.style.display, 'block', 'progress are visible' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'Loop', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.configure({ loop: true });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.left();
 | 
					 | 
				
			||||||
		assert.notEqual( Reveal.getIndices().h, 0, 'looped from start to end' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.right();
 | 
					 | 
				
			||||||
		assert.equal( Reveal.getIndices().h, 0, 'looped from end to start' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.configure({ loop: false });
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ---------------------------------------------------------------
 | 
					 | 
				
			||||||
	// LAZY-LOADING TESTS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.module( 'Lazy-Loading' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'img with data-src', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal section img[src]' ).length, 1, 'Image source has been set' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'video with data-src', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal section video[src]' ).length, 1, 'Video source has been set' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'audio with data-src', function( assert ) {
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal section audio[src]' ).length, 1, 'Audio source has been set' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'iframe with data-src', function( assert ) {
 | 
					 | 
				
			||||||
		Reveal.slide( 0, 0 );
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal section iframe[src]' ).length, 0, 'Iframe source is not set' );
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 1 );
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal section iframe[src]' ).length, 1, 'Iframe source is set' );
 | 
					 | 
				
			||||||
		Reveal.slide( 2, 2 );
 | 
					 | 
				
			||||||
		assert.strictEqual( document.querySelectorAll( '.reveal section iframe[src]' ).length, 0, 'Iframe source is not set' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'background images', function( assert ) {
 | 
					 | 
				
			||||||
		var imageSource1 = Reveal.getSlide( 0 ).getAttribute( 'data-background-image' );
 | 
					 | 
				
			||||||
		var imageSource2 = Reveal.getSlide( 1, 0 ).getAttribute( 'data-background' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// check that the images are applied to the background elements
 | 
					 | 
				
			||||||
		assert.ok( Reveal.getSlideBackground( 0 ).querySelector( '.slide-background-content' ).style.backgroundImage.indexOf( imageSource1 ) !== -1, 'data-background-image worked' );
 | 
					 | 
				
			||||||
		assert.ok( Reveal.getSlideBackground( 1, 0 ).querySelector( '.slide-background-content' ).style.backgroundImage.indexOf( imageSource2 ) !== -1, 'data-background worked' );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ---------------------------------------------------------------
 | 
					 | 
				
			||||||
	// EVENT TESTS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.module( 'Events' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'slidechanged', function( assert ) {
 | 
					 | 
				
			||||||
		assert.expect( 3 );
 | 
					 | 
				
			||||||
		var done = assert.async( 3 );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var _onEvent = function( event ) {
 | 
					 | 
				
			||||||
			assert.ok( true, 'event fired' );
 | 
					 | 
				
			||||||
			done();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.addEventListener( 'slidechanged', _onEvent );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 0 ); // should trigger
 | 
					 | 
				
			||||||
		Reveal.slide( 1, 0 ); // should do nothing
 | 
					 | 
				
			||||||
		Reveal.next(); // should trigger
 | 
					 | 
				
			||||||
		Reveal.slide( 3, 0 ); // should trigger
 | 
					 | 
				
			||||||
		Reveal.next(); // should do nothing
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.removeEventListener( 'slidechanged', _onEvent );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'paused', function( assert ) {
 | 
					 | 
				
			||||||
		assert.expect( 1 );
 | 
					 | 
				
			||||||
		var done = assert.async();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var _onEvent = function( event ) {
 | 
					 | 
				
			||||||
			assert.ok( true, 'event fired' );
 | 
					 | 
				
			||||||
			done();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.addEventListener( 'paused', _onEvent );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.togglePause();
 | 
					 | 
				
			||||||
		Reveal.togglePause();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.removeEventListener( 'paused', _onEvent );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QUnit.test( 'resumed', function( assert ) {
 | 
					 | 
				
			||||||
		assert.expect( 1 );
 | 
					 | 
				
			||||||
		var done = assert.async();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var _onEvent = function( event ) {
 | 
					 | 
				
			||||||
			assert.ok( true, 'event fired' );
 | 
					 | 
				
			||||||
			done();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.addEventListener( 'resumed', _onEvent );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.togglePause();
 | 
					 | 
				
			||||||
		Reveal.togglePause();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reveal.removeEventListener( 'resumed', _onEvent );
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} );
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue