瀏覽代碼

switch old toArray helper to Array.from

Hakim El Hattab 5 年之前
父節點
當前提交
2540712714

File diff suppressed because it is too large
+ 0 - 0
dist/reveal.min.js


+ 3 - 3
js/controllers/autoanimate.js

@@ -1,4 +1,4 @@
-import { extend, toArray, createStyleSheet } from '../utils/util.js'
+import { queryAll, extend, createStyleSheet } from '../utils/util.js'
 
 /**
  * Automatically animates matching elements across
@@ -87,12 +87,12 @@ export default class AutoAnimate {
 	reset() {
 
 		// Reset slides
-		toArray( this.Reveal.getRevealElement().querySelectorAll( '[data-auto-animate]:not([data-auto-animate=""])' ) ).forEach( element => {
+		queryAll( this.Reveal.getRevealElement(), '[data-auto-animate]:not([data-auto-animate=""])' ).forEach( element => {
 			element.dataset.autoAnimate = '';
 		} );
 
 		// Reset elements
-		toArray( this.Reveal.getRevealElement().querySelectorAll( '[data-auto-animate-target]' ) ).forEach( element => {
+		queryAll( this.Reveal.getRevealElement(), '[data-auto-animate-target]' ).forEach( element => {
 			delete element.dataset.autoAnimateTarget;
 		} );
 

+ 4 - 4
js/controllers/backgrounds.js

@@ -1,4 +1,4 @@
-import { toArray } from '../utils/util.js'
+import { queryAll } from '../utils/util.js'
 import { colorToRgb, colorBrightness } from '../utils/color.js'
 
 /**
@@ -39,7 +39,7 @@ export default class Backgrounds {
 			let backgroundStack = this.createBackground( slideh, this.element );
 
 			// Iterate over all vertical slides
-			toArray( slideh.querySelectorAll( 'section' ) ).forEach( slidev => {
+			queryAll( slideh, 'section' ).forEach( slidev => {
 
 				this.createBackground( slidev, backgroundStack );
 
@@ -238,7 +238,7 @@ export default class Backgrounds {
 
 		// Update the classes of all backgrounds to match the
 		// states of their slides (past/present/future)
-		toArray( this.element.childNodes ).forEach( ( backgroundh, h ) => {
+		Array.from( this.element.childNodes ).forEach( ( backgroundh, h ) => {
 
 			backgroundh.classList.remove( 'past', 'present', 'future' );
 
@@ -256,7 +256,7 @@ export default class Backgrounds {
 			}
 
 			if( includeAll || h === indices.h ) {
-				toArray( backgroundh.querySelectorAll( '.slide-background' ) ).forEach( ( backgroundv, v ) => {
+				queryAll( backgroundh, '.slide-background' ).forEach( ( backgroundv, v ) => {
 
 					backgroundv.classList.remove( 'past', 'present', 'future' );
 

+ 7 - 7
js/controllers/controls.js

@@ -1,4 +1,4 @@
-import { toArray } from '../utils/util.js'
+import { queryAll } from '../utils/util.js'
 import { isAndroid } from '../utils/device.js'
 
 /**
@@ -44,12 +44,12 @@ export default class Controls {
 		this.Reveal.getRevealElement().appendChild( this.element );
 
 		// There can be multiple instances of controls throughout the page
-		this.controlsLeft = toArray( revealElement.querySelectorAll( '.navigate-left' ) );
-		this.controlsRight = toArray( revealElement.querySelectorAll( '.navigate-right' ) );
-		this.controlsUp = toArray( revealElement.querySelectorAll( '.navigate-up' ) );
-		this.controlsDown = toArray( revealElement.querySelectorAll( '.navigate-down' ) );
-		this.controlsPrev = toArray( revealElement.querySelectorAll( '.navigate-prev' ) );
-		this.controlsNext = toArray( revealElement.querySelectorAll( '.navigate-next' ) );
+		this.controlsLeft = queryAll( revealElement, '.navigate-left' );
+		this.controlsRight = queryAll( revealElement, '.navigate-right' );
+		this.controlsUp = queryAll( revealElement, '.navigate-up' );
+		this.controlsDown = queryAll( revealElement, '.navigate-down' );
+		this.controlsPrev = queryAll( revealElement, '.navigate-prev' );
+		this.controlsNext = queryAll( revealElement, '.navigate-next' );
 
 		// The left, right and down arrows in the standard reveal.js controls
 		this.controlsRightArrow = this.element.querySelector( '.navigate-right' );

+ 6 - 6
js/controllers/fragments.js

@@ -1,4 +1,4 @@
-import { extend, toArray } from '../utils/util.js'
+import { extend, queryAll } from '../utils/util.js'
 
 /**
  * Handles sorting and navigation of slide fragments.
@@ -33,7 +33,7 @@ export default class Fragments {
 	 */
 	disable() {
 
-		toArray( this.Reveal.getSlidesElement().querySelectorAll( '.fragment' ) ).forEach( element => {
+		queryAll( this.Reveal.getSlidesElement(), '.fragment' ).forEach( element => {
 			element.classList.add( 'visible' );
 			element.classList.remove( 'current-fragment' );
 		} );
@@ -46,7 +46,7 @@ export default class Fragments {
 	 */
 	enable() {
 
-		toArray( this.Reveal.getSlidesElement().querySelectorAll( '.fragment' ) ).forEach( element => {
+		queryAll( this.Reveal.getSlidesElement(), '.fragment' ).forEach( element => {
 			element.classList.remove( 'visible' );
 			element.classList.remove( 'current-fragment' );
 		} );
@@ -98,7 +98,7 @@ export default class Fragments {
 	 */
 	sort( fragments, grouped = false ) {
 
-		fragments = toArray( fragments );
+		fragments = Array.from( fragments );
 
 		let ordered = [],
 			unordered = [],
@@ -151,7 +151,7 @@ export default class Fragments {
 
 		this.Reveal.getHorizontalSlides().forEach( horizontalSlide => {
 
-			let verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) );
+			let verticalSlides = queryAll( horizontalSlide, 'section' );
 			verticalSlides.forEach( ( verticalSlide, y ) => {
 
 				this.sort( verticalSlide.querySelectorAll( '.fragment' ) );
@@ -197,7 +197,7 @@ export default class Fragments {
 					}
 				}
 
-				toArray( fragments ).forEach( ( el, i ) => {
+				Array.from( fragments ).forEach( ( el, i ) => {
 
 					if( el.hasAttribute( 'data-fragment-index' ) ) {
 						i = parseInt( el.getAttribute( 'data-fragment-index' ), 10 );

+ 7 - 7
js/controllers/overview.js

@@ -1,5 +1,5 @@
 import { SLIDES_SELECTOR } from '../utils/constants.js'
-import { extend, toArray, transformElement } from '../utils/util.js'
+import { extend, queryAll, transformElement } from '../utils/util.js'
 
 /**
  * Handles all logic related to the overview mode
@@ -38,7 +38,7 @@ export default class Overview {
 			this.Reveal.getSlidesElement().appendChild( this.Reveal.getBackgroundsElement() );
 
 			// Clicking on an overview slide navigates to it
-			toArray( this.Reveal.getRevealElement().querySelectorAll( SLIDES_SELECTOR ) ).forEach( slide => {
+			queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( slide => {
 				if( !slide.classList.contains( 'stack' ) ) {
 					slide.addEventListener( 'click', this.onSlideClicked, true );
 				}
@@ -91,7 +91,7 @@ export default class Overview {
 
 			if( hslide.classList.contains( 'stack' ) ) {
 
-				toArray( hslide.querySelectorAll( 'section' ) ).forEach( ( vslide, v ) => {
+				queryAll( hslide, 'section' ).forEach( ( vslide, v ) => {
 					vslide.setAttribute( 'data-index-h', h );
 					vslide.setAttribute( 'data-index-v', v );
 
@@ -102,10 +102,10 @@ export default class Overview {
 		} );
 
 		// Layout slide backgrounds
-		toArray( this.Reveal.getBackgroundsElement().childNodes ).forEach( ( hbackground, h ) => {
+		Array.from( this.Reveal.getBackgroundsElement().childNodes ).forEach( ( hbackground, h ) => {
 			transformElement( hbackground, 'translate3d(' + ( h * this.overviewSlideWidth ) + 'px, 0, 0)' );
 
-			toArray( hbackground.querySelectorAll( '.slide-background' ) ).forEach( ( vbackground, v ) => {
+			queryAll( hbackground, '.slide-background' ).forEach( ( vbackground, v ) => {
 				transformElement( vbackground, 'translate3d(0, ' + ( v * this.overviewSlideHeight ) + 'px, 0)' );
 			} );
 		} );
@@ -158,14 +158,14 @@ export default class Overview {
 			this.Reveal.getRevealElement().appendChild( this.Reveal.getBackgroundsElement() );
 
 			// Clean up changes made to slides
-			toArray( this.Reveal.getRevealElement().querySelectorAll( SLIDES_SELECTOR ) ).forEach( slide => {
+			queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( slide => {
 				transformElement( slide, '' );
 
 				slide.removeEventListener( 'click', this.onSlideClicked, true );
 			} );
 
 			// Clean up changes made to backgrounds
-			toArray( this.Reveal.getBackgroundsElement().querySelectorAll( '.slide-background' ) ).forEach( background => {
+			queryAll( this.Reveal.getBackgroundsElement(), '.slide-background' ).forEach( background => {
 				transformElement( background, '' );
 			} );
 

+ 4 - 4
js/controllers/print.js

@@ -1,5 +1,5 @@
 import { SLIDES_SELECTOR } from '../utils/constants.js'
-import { toArray, createStyleSheet } from '../utils/util.js'
+import { queryAll, createStyleSheet } from '../utils/util.js'
 
 /**
  * Setups up our presentation for printing/exporting to PDF.
@@ -45,12 +45,12 @@ export default class Print {
 
 		// Compute slide numbers now, before we start duplicating slides
 		let doingSlideNumbers = config.slideNumber && /all|print/i.test( config.showSlideNumber );
-		toArray( this.Reveal.getRevealElement().querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) {
+		queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( function( slide ) {
 			slide.setAttribute( 'data-slide-number', this.Reveal.slideNumber.getSlideNumber( slide ) );
 		}, this );
 
 		// Slide and slide background layout
-		toArray( this.Reveal.getRevealElement().querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) {
+		queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( function( slide ) {
 
 			// Vertical stacks are not centred since their section
 			// children will be
@@ -169,7 +169,7 @@ export default class Print {
 				}
 				// Show all fragments
 				else {
-					toArray( page.querySelectorAll( '.fragment:not(.fade-out)' ) ).forEach( function( fragment ) {
+					queryAll( page, '.fragment:not(.fade-out)' ).forEach( function( fragment ) {
 						fragment.classList.add( 'visible' );
 					} );
 				}

+ 17 - 17
js/controllers/slidecontent.js

@@ -1,5 +1,5 @@
 import { HORIZONTAL_SLIDES_SELECTOR, VERTICAL_SLIDES_SELECTOR } from '../utils/constants.js'
-import { extend, toArray, closestParent } from '../utils/util.js'
+import { extend, queryAll, closestParent } from '../utils/util.js'
 import { isMobile } from '../utils/device.js'
 
 /**
@@ -47,7 +47,7 @@ export default class SlideContent {
 		slide.style.display = this.Reveal.getConfig().display;
 
 		// Media elements with data-src attributes
-		toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ) ).forEach( element => {
+		queryAll( slide, 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ).forEach( element => {
 			if( element.tagName !== 'IFRAME' || this.shouldPreload( element ) ) {
 				element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
 				element.setAttribute( 'data-lazy-loaded', '' );
@@ -56,10 +56,10 @@ export default class SlideContent {
 		} );
 
 		// Media elements with <source> children
-		toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( media => {
+		queryAll( slide, 'video, audio' ).forEach( media => {
 			let sources = 0;
 
-			toArray( media.querySelectorAll( 'source[data-src]' ) ).forEach( source => {
+			queryAll( media, 'source[data-src]' ).forEach( source => {
 				source.setAttribute( 'src', source.getAttribute( 'data-src' ) );
 				source.removeAttribute( 'data-src' );
 				source.setAttribute( 'data-lazy-loaded', '' );
@@ -176,19 +176,19 @@ export default class SlideContent {
 			background.style.display = 'none';
 
 			// Unload any background iframes
-			toArray( background.querySelectorAll( 'iframe[src]' ) ).forEach( element => {
+			queryAll( background, 'iframe[src]' ).forEach( element => {
 				element.removeAttribute( 'src' );
 			} );
 		}
 
 		// Reset lazy-loaded media elements with src attributes
-		toArray( slide.querySelectorAll( 'video[data-lazy-loaded][src], audio[data-lazy-loaded][src], iframe[data-lazy-loaded][src]' ) ).forEach( element => {
+		queryAll( slide, 'video[data-lazy-loaded][src], audio[data-lazy-loaded][src], iframe[data-lazy-loaded][src]' ).forEach( element => {
 			element.setAttribute( 'data-src', element.getAttribute( 'src' ) );
 			element.removeAttribute( 'src' );
 		} );
 
 		// Reset lazy-loaded media elements with <source> children
-		toArray( slide.querySelectorAll( 'video[data-lazy-loaded] source[src], audio source[src]' ) ).forEach( source => {
+		queryAll( slide, 'video[data-lazy-loaded] source[src], audio source[src]' ).forEach( source => {
 			source.setAttribute( 'data-src', source.getAttribute( 'src' ) );
 			source.removeAttribute( 'src' );
 		} );
@@ -201,7 +201,7 @@ export default class SlideContent {
 	formatEmbeddedContent() {
 
 		let _appendParamToIframeSource = ( sourceAttribute, sourceURL, param ) => {
-			toArray( this.Reveal.getSlidesElement().querySelectorAll( 'iframe['+ sourceAttribute +'*="'+ sourceURL +'"]' ) ).forEach( el => {
+			queryAll( this.Reveal.getSlidesElement(), 'iframe['+ sourceAttribute +'*="'+ sourceURL +'"]' ).forEach( el => {
 				let src = el.getAttribute( sourceAttribute );
 				if( src && src.indexOf( param ) === -1 ) {
 					el.setAttribute( sourceAttribute, src + ( !/\?/.test( src ) ? '?' : '&' ) + param );
@@ -230,14 +230,14 @@ export default class SlideContent {
 		if( element && !this.Reveal.isSpeakerNotes() ) {
 
 			// Restart GIFs
-			toArray( element.querySelectorAll( 'img[src$=".gif"]' ) ).forEach( el => {
+			queryAll( element, 'img[src$=".gif"]' ).forEach( el => {
 				// Setting the same unchanged source like this was confirmed
 				// to work in Chrome, FF & Safari
 				el.setAttribute( 'src', el.getAttribute( 'src' ) );
 			} );
 
 			// HTML5 media elements
-			toArray( element.querySelectorAll( 'video, audio' ) ).forEach( el => {
+			queryAll( element, 'video, audio' ).forEach( el => {
 				if( closestParent( el, '.fragment' ) && !closestParent( el, '.fragment.visible' ) ) {
 					return;
 				}
@@ -285,7 +285,7 @@ export default class SlideContent {
 			} );
 
 			// Normal iframes
-			toArray( element.querySelectorAll( 'iframe[src]' ) ).forEach( el => {
+			queryAll( element, 'iframe[src]' ).forEach( el => {
 				if( closestParent( el, '.fragment' ) && !closestParent( el, '.fragment.visible' ) ) {
 					return;
 				}
@@ -294,7 +294,7 @@ export default class SlideContent {
 			} );
 
 			// Lazy loading iframes
-			toArray( element.querySelectorAll( 'iframe[data-src]' ) ).forEach( el => {
+			queryAll( element, 'iframe[data-src]' ).forEach( el => {
 				if( closestParent( el, '.fragment' ) && !closestParent( el, '.fragment.visible' ) ) {
 					return;
 				}
@@ -390,7 +390,7 @@ export default class SlideContent {
 
 		if( element && element.parentNode ) {
 			// HTML5 media elements
-			toArray( element.querySelectorAll( 'video, audio' ) ).forEach( el => {
+			queryAll( element, 'video, audio' ).forEach( el => {
 				if( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) {
 					el.setAttribute('data-paused-by-reveal', '');
 					el.pause();
@@ -398,20 +398,20 @@ export default class SlideContent {
 			} );
 
 			// Generic postMessage API for non-lazy loaded iframes
-			toArray( element.querySelectorAll( 'iframe' ) ).forEach( el => {
+			queryAll( element, 'iframe' ).forEach( el => {
 				if( el.contentWindow ) el.contentWindow.postMessage( 'slide:stop', '*' );
 				el.removeEventListener( 'load', this.startEmbeddedIframe );
 			});
 
 			// YouTube postMessage API
-			toArray( element.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( el => {
+			queryAll( element, 'iframe[src*="youtube.com/embed/"]' ).forEach( el => {
 				if( !el.hasAttribute( 'data-ignore' ) && el.contentWindow && typeof el.contentWindow.postMessage === 'function' ) {
 					el.contentWindow.postMessage( '{"event":"command","func":"pauseVideo","args":""}', '*' );
 				}
 			});
 
 			// Vimeo postMessage API
-			toArray( element.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( el => {
+			queryAll( element, 'iframe[src*="player.vimeo.com/"]' ).forEach( el => {
 				if( !el.hasAttribute( 'data-ignore' ) && el.contentWindow && typeof el.contentWindow.postMessage === 'function' ) {
 					el.contentWindow.postMessage( '{"method":"pause"}', '*' );
 				}
@@ -419,7 +419,7 @@ export default class SlideContent {
 
 			if( options.unloadIframes === true ) {
 				// Unload lazy-loaded iframes
-				toArray( element.querySelectorAll( 'iframe[data-src]' ) ).forEach( el => {
+				queryAll( element, 'iframe[data-src]' ).forEach( el => {
 					// Only removing the src doesn't actually unload the frame
 					// in all browsers (Firefox) so we set it to blank first
 					el.setAttribute( 'src', 'about:blank' );

+ 22 - 58
js/reveal.js

@@ -23,12 +23,13 @@ import {
 } from './utils/constants.js'
 import {
 	extend,
-	toArray,
+	queryAll,
 	deserialize,
 	transformElement,
 	createSingletonNode,
 	closestParent,
-	getQueryHash
+	getQueryHash,
+	getRemainingHeight
 } from './utils/util.js'
 
 /**
@@ -298,7 +299,7 @@ export default function( revealElement, options ) {
 			let isDisplayHidden = window.getComputedStyle( node )['display'] === 'none';
 			if( isAriaHidden !== 'true' && !isDisplayHidden ) {
 
-				toArray( node.childNodes ).forEach( child => {
+				Array.from( node.childNodes ).forEach( child => {
 					text += getStatusText( child );
 				} );
 
@@ -559,43 +560,6 @@ export default function( revealElement, options ) {
 
 	}
 
-	/**
-	 * Returns the remaining height within the parent of the
-	 * target element.
-	 *
-	 * remaining height = [ configured parent height ] - [ current parent height ]
-	 *
-	 * @param {HTMLElement} element
-	 * @param {number} [height]
-	 */
-	function getRemainingHeight( element, height = 0 ) {
-
-		if( element ) {
-			let newHeight, oldHeight = element.style.height;
-
-			// Change the .stretch element height to 0 in order find the height of all
-			// the other elements
-			element.style.height = '0px';
-
-			// In Overview mode, the parent (.slide) height is set of 700px.
-			// Restore it temporarily to its natural height.
-			element.parentNode.style.height = 'auto';
-
-			newHeight = height - element.parentNode.offsetHeight;
-
-			// Restore the old height, just in case
-			element.style.height = oldHeight + 'px';
-
-			// Clear the parent (.slide) height. .removeProperty works in IE9+
-			element.parentNode.style.removeProperty('height');
-
-			return newHeight;
-		}
-
-		return height;
-
-	}
-
 	/**
 	 * Dispatches an event of the specified type from the
 	 * reveal DOM element.
@@ -641,7 +605,7 @@ export default function( revealElement, options ) {
 	 */
 	function enablePreviewLinks( selector = 'a' ) {
 
-		toArray( dom.wrapper.querySelectorAll( selector ) ).forEach( element => {
+		Array.from( dom.wrapper.querySelectorAll( selector ) ).forEach( element => {
 			if( /^(http|www)/gi.test( element.getAttribute( 'href' ) ) ) {
 				element.addEventListener( 'click', onPreviewLinkClicked, false );
 			}
@@ -654,7 +618,7 @@ export default function( revealElement, options ) {
 	 */
 	function disablePreviewLinks( selector = 'a' ) {
 
-		toArray( dom.wrapper.querySelectorAll( selector ) ).forEach( element => {
+		Array.from( dom.wrapper.querySelectorAll( selector ) ).forEach( element => {
 			if( /^(http|www)/gi.test( element.getAttribute( 'href' ) ) ) {
 				element.removeEventListener( 'click', onPreviewLinkClicked, false );
 			}
@@ -864,7 +828,7 @@ export default function( revealElement, options ) {
 				}
 
 				// Select all slides, vertical and horizontal
-				const slides = toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) );
+				const slides = Array.from( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) );
 
 				for( let i = 0, len = slides.length; i < len; i++ ) {
 					const slide = slides[ i ];
@@ -923,7 +887,7 @@ export default function( revealElement, options ) {
 	function layoutSlideContents( width, height ) {
 
 		// Handle sizing of elements with the 'stretch' class
-		toArray( dom.slides.querySelectorAll( 'section > .stretch' ) ).forEach( element => {
+		queryAll( dom.slides, 'section > .stretch' ).forEach( element => {
 
 			// Determine how much vertical space we can use
 			let remainingHeight = getRemainingHeight( element, height );
@@ -1340,7 +1304,6 @@ export default function( revealElement, options ) {
 		// Announce the current slide contents to screen readers
 		announceStatus( getStatusText( currentSlide ) );
 
-
 		progress.update();
 		controls.update();
 		notes.update();
@@ -1459,7 +1422,7 @@ export default function( revealElement, options ) {
 
 		getHorizontalSlides().forEach( horizontalSlide => {
 
-			toArray( horizontalSlide.querySelectorAll( 'section' ) ).forEach( ( verticalSlide, y ) => {
+			queryAll( horizontalSlide, 'section' ).forEach( ( verticalSlide, y ) => {
 
 				if( y > 0 ) {
 					verticalSlide.classList.remove( 'present' );
@@ -1506,7 +1469,7 @@ export default function( revealElement, options ) {
 
 		// Select all slides and convert the NodeList result to
 		// an array
-		let slides = toArray( dom.wrapper.querySelectorAll( selector ) ),
+		let slides = queryAll( dom.wrapper, selector ),
 			slidesLength = slides.length;
 
 		let printMode = print.isPrintingPDF();
@@ -1553,7 +1516,7 @@ export default function( revealElement, options ) {
 
 					if( config.fragments ) {
 						// Show all fragments in prior slides
-						toArray( element.querySelectorAll( '.fragment' ) ).forEach( fragment => {
+						queryAll( element, '.fragment' ).forEach( fragment => {
 							fragment.classList.add( 'visible' );
 							fragment.classList.remove( 'current-fragment' );
 						} );
@@ -1565,7 +1528,7 @@ export default function( revealElement, options ) {
 
 					if( config.fragments ) {
 						// Hide all fragments in future slides
-						toArray( element.querySelectorAll( '.fragment.visible' ) ).forEach( fragment => {
+						queryAll( element, '.fragment.visible' ).forEach( fragment => {
 							fragment.classList.remove( 'visible', 'current-fragment' );
 						} );
 					}
@@ -1640,7 +1603,7 @@ export default function( revealElement, options ) {
 			for( let x = 0; x < horizontalSlidesLength; x++ ) {
 				let horizontalSlide = horizontalSlides[x];
 
-				let verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) ),
+				let verticalSlides = queryAll( horizontalSlide, 'section' ),
 					verticalSlidesLength = verticalSlides.length;
 
 				// Determine how far away this slide is from the present
@@ -1867,7 +1830,7 @@ export default function( revealElement, options ) {
 
 			// If this is a vertical slide, grab the vertical index
 			if( isVertical ) {
-				v = Math.max( toArray( slide.parentNode.querySelectorAll( 'section' ) ).indexOf( slide ), 0 );
+				v = Math.max( queryAll( slide.parentNode, 'section' ).indexOf( slide ), 0 );
 			}
 		}
 
@@ -1893,7 +1856,7 @@ export default function( revealElement, options ) {
 	 */
 	function getSlides() {
 
-		return toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ':not(.stack):not([data-visibility="uncounted"])' ) );
+		return queryAll( dom.wrapper, SLIDES_SELECTOR + ':not(.stack):not([data-visibility="uncounted"])' );
 
 	}
 
@@ -1904,7 +1867,7 @@ export default function( revealElement, options ) {
 	 */
 	function getHorizontalSlides() {
 
-		return toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
+		return queryAll( dom.wrapper, HORIZONTAL_SLIDES_SELECTOR );
 
 	}
 
@@ -1913,7 +1876,7 @@ export default function( revealElement, options ) {
 	 */
 	function getVerticalSlides() {
 
-		return toArray( dom.wrapper.querySelectorAll( '.slides>section>section' ) );
+		return queryAll( dom.wrapper, '.slides>section>section' );
 
 	}
 
@@ -1922,7 +1885,7 @@ export default function( revealElement, options ) {
 	 */
 	function getVerticalStacks() {
 
-		return toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.stack') );
+		return queryAll( dom.wrapper, HORIZONTAL_SLIDES_SELECTOR + '.stack');
 
 	}
 
@@ -2102,7 +2065,7 @@ export default function( revealElement, options ) {
 			// is divided up into fragments.
 			// playbackRate is accounted for in the duration.
 			if( currentSlide.querySelectorAll( '.fragment' ).length === 0 ) {
-				toArray( currentSlide.querySelectorAll( 'video, audio' ) ).forEach( el => {
+				queryAll( currentSlide, 'video, audio' ).forEach( el => {
 					if( el.hasAttribute( 'data-autoplay' ) ) {
 						if( autoSlide && (el.duration * 1000 / el.playbackRate ) > autoSlide ) {
 							autoSlide = ( el.duration * 1000 / el.playbackRate ) + 1000;
@@ -2244,10 +2207,10 @@ export default function( revealElement, options ) {
 				let previousSlide;
 
 				if( config.rtl ) {
-					previousSlide = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.future' ) ).pop();
+					previousSlide = queryAll( dom.wrapper, HORIZONTAL_SLIDES_SELECTOR + '.future' ).pop();
 				}
 				else {
-					previousSlide = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.past' ) ).pop();
+					previousSlide = queryAll( dom.wrapper, HORIZONTAL_SLIDES_SELECTOR + '.past' ).pop();
 				}
 
 				if( previousSlide ) {
@@ -2607,6 +2570,7 @@ export default function( revealElement, options ) {
 		// Returns reveal.js DOM elements
 		getRevealElement: () => dom.wrapper || document.querySelector( '.reveal' ),
 		getSlidesElement: () => dom.slides,
+		getBackgroundsElement: () => backgrounds.element,
 
 		// Checks if reveal.js has been loaded and is ready for use
 		isReady: () => ready,

+ 40 - 6
js/utils/util.js

@@ -16,14 +16,11 @@ export const extend = ( a, b ) => {
 }
 
 /**
- * Converts the target object to an array.
- *
- * @param {object} o
- * @return {object[]}
+ * querySelectorAll but returns an Array.
  */
-export const toArray = ( o ) => {
+export const queryAll = ( el, selector ) => {
 
-	return Array.prototype.slice.call( o );
+	return Array.from( el.querySelectorAll( selector ) );
 
 }
 
@@ -220,4 +217,41 @@ export const getQueryHash = () => {
 
 	return query;
 
+}
+
+/**
+ * Returns the remaining height within the parent of the
+ * target element.
+ *
+ * remaining height = [ configured parent height ] - [ current parent height ]
+ *
+ * @param {HTMLElement} element
+ * @param {number} [height]
+ */
+export const getRemainingHeight = ( element, height = 0 ) => {
+
+	if( element ) {
+		let newHeight, oldHeight = element.style.height;
+
+		// Change the .stretch element height to 0 in order find the height of all
+		// the other elements
+		element.style.height = '0px';
+
+		// In Overview mode, the parent (.slide) height is set of 700px.
+		// Restore it temporarily to its natural height.
+		element.parentNode.style.height = 'auto';
+
+		newHeight = height - element.parentNode.offsetHeight;
+
+		// Restore the old height, just in case
+		element.style.height = oldHeight + 'px';
+
+		// Clear the parent (.slide) height. .removeProperty works in IE9+
+		element.parentNode.style.removeProperty('height');
+
+		return newHeight;
+	}
+
+	return height;
+
 }

Some files were not shown because too many files changed in this diff