瀏覽代碼

update reveal.js version

Hakim El Hattab 5 年之前
父節點
當前提交
72949a2d28
共有 11 個文件被更改,包括 274 次插入77 次删除
  1. 1 1
      chromeless.html
  2. 16 8
      css/reveal.css
  3. 0 0
      css/reveal.min.css
  4. 14 5
      css/reveal.scss
  5. 218 56
      js/reveal.js
  6. 1 1
      js/reveal.min.js
  7. 0 2
      lib/js/classList.js
  8. 0 1
      lib/js/head.min.js
  9. 1 0
      lib/js/promise.js
  10. 0 0
      plugin/highlight/highlight.js
  11. 23 3
      plugin/notes/notes.html

+ 1 - 1
chromeless.html

@@ -18,7 +18,7 @@
 		<link rel="stylesheet" href="css/theme/black.css" id="theme">
 
 		<!-- Theme used for syntax highlighting of code -->
-		<link rel="stylesheet" href="lib/css/zenburn.css">
+		<link rel="stylesheet" href="lib/css/monokai.css">
 
 		<!-- Printing and PDF exports -->
 		<script>

+ 16 - 8
css/reveal.css

@@ -227,7 +227,7 @@ body {
   bottom: 12px;
   right: 12px;
   left: auto;
-  z-index: 1;
+  z-index: 11;
   color: #000;
   pointer-events: none;
   font-size: 10px; }
@@ -312,7 +312,8 @@ body {
               transform: rotate(90deg); }
   .reveal .controls .navigate-down {
     right: 3.2em;
-    bottom: 0;
+    bottom: -1.4em;
+    padding-bottom: 1.4em;
     -webkit-transform: translateY(10px);
             transform: translateY(10px); }
     .reveal .controls .navigate-down .controls-arrow {
@@ -395,18 +396,18 @@ body {
     right: auto; }
   .reveal .controls[data-controls-layout="edges"] .navigate-left {
     top: 50%;
-    left: 8px;
+    left: 0.8em;
     margin-top: -1.8em; }
   .reveal .controls[data-controls-layout="edges"] .navigate-right {
     top: 50%;
-    right: 8px;
+    right: 0.8em;
     margin-top: -1.8em; }
   .reveal .controls[data-controls-layout="edges"] .navigate-up {
-    top: 8px;
+    top: 0.8em;
     left: 50%;
     margin-left: -1.8em; }
   .reveal .controls[data-controls-layout="edges"] .navigate-down {
-    bottom: 8px;
+    bottom: -0.3em;
     left: 50%;
     margin-left: -1.8em; } }
 
@@ -1453,8 +1454,15 @@ body {
   text-align: right;
   vertical-align: top; }
 
-.reveal .hljs[data-line-numbers]:not([data-line-numbers=""]) tr:not(.highlight-line) {
-  opacity: 0.25; }
+.reveal .hljs.has-highlights tr:not(.highlight-line) {
+  opacity: 0.4; }
+
+.reveal .hljs:not(:first-child).fragment {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  box-sizing: border-box; }
 
 /*********************************************
  * ROLLING LINKS

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


+ 14 - 5
css/reveal.scss

@@ -263,7 +263,7 @@ $controlsArrowAngleActive: 36deg;
 	bottom: $spacing;
 	right: $spacing;
 	left: auto;
-	z-index: 1;
+	z-index: 11;
 	color: #000;
 	pointer-events: none;
 	font-size: 10px;
@@ -355,7 +355,8 @@ $controlsArrowAngleActive: 36deg;
 
 	.navigate-down {
 		right: $controlArrowSpacing + $controlArrowSize/2;
-		bottom: 0;
+		bottom: -$controlArrowSpacing;
+		padding-bottom: $controlArrowSpacing;
 		transform: translateY( 10px );
 
 		.controls-arrow {
@@ -452,7 +453,7 @@ $controlsArrowAngleActive: 36deg;
 // Edge aligned controls layout
 @media screen and (min-width: 500px) {
 
-	$spacing: 8px;
+	$spacing: 0.8em;
 
 	.reveal .controls[data-controls-layout="edges"] {
 		& {
@@ -489,7 +490,7 @@ $controlsArrowAngleActive: 36deg;
 		}
 
 		.navigate-down {
-			bottom: $spacing;
+			bottom: $spacing - $controlArrowSpacing + 0.3em;
 			left: 50%;
 			margin-left: -$controlArrowSize/2;
 		}
@@ -1590,10 +1591,18 @@ $controlsArrowAngleActive: 36deg;
 	vertical-align: top;
 }
 
-.reveal .hljs[data-line-numbers]:not([data-line-numbers=""]) tr:not(.highlight-line) {
+.reveal .hljs.has-highlights tr:not(.highlight-line) {
 	opacity: 0.4;
 }
 
+.reveal .hljs:not(:first-child).fragment {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	box-sizing: border-box;
+}
+
 
 /*********************************************
  * ROLLING LINKS

+ 218 - 56
js/reveal.js

@@ -26,7 +26,7 @@
 	var Reveal;
 
 	// The reveal.js version
-	var VERSION = '3.7.0';
+	var VERSION = '3.8.0';
 
 	var SLIDES_SELECTOR = '.slides section',
 		HORIZONTAL_SLIDES_SELECTOR = '.slides>section',
@@ -146,8 +146,8 @@
 			// 1.3    2.3
 			//
 			// If you're on slide 1.3 and navigate right, you will normally move
-			// from 1.3 -> 2.1. With "gridNavigation" enabled the same navigation
-			// takes you from 1.3 -> 2.3.
+			// from 1.3 -> 2.1. If "grid" is used, the same navigation takes you
+			// from 1.3 -> 2.3.
 			navigationMode: 'default',
 
 			// Randomizes the order of slides each time the presentation loads
@@ -180,6 +180,13 @@
 			// - false:  No media will autoplay, regardless of individual setting
 			autoPlayMedia: null,
 
+			// Global override for preloading lazy-loaded iframes
+			// - null:   Iframes with data-src AND data-preload will be loaded when within
+			//           the viewDistance, iframes with only data-src will be loaded when visible
+			// - true:   All iframes with data-src will be loaded when within the viewDistance
+			// - false:  All iframes with data-src will be loaded only when visible
+			preloadIframes: null,
+
 			// Controls automatic progression to the next slide
 			// - 0:      Auto-sliding only happens if the data-autoslide HTML attribute
 			//           is present on the current slide or fragment
@@ -367,20 +374,9 @@
 			threshold: 40
 		},
 
-		// Holds information about the keyboard shortcuts
-		keyboardShortcuts = {
-			'N  ,  SPACE':						'Next slide',
-			'P':								'Previous slide',
-			'&#8592;  ,  H':					'Navigate left',
-			'&#8594;  ,  L':					'Navigate right',
-			'&#8593;  ,  K':					'Navigate up',
-			'&#8595;  ,  J':					'Navigate down',
-			'Home  ,  &#8984;/CTRL &#8592;':	'First slide',
-			'End  ,  &#8984;/CTRL &#8594;':		'Last slide',
-			'B  ,  .':							'Pause',
-			'F':								'Fullscreen',
-			'ESC, O':							'Slide overview'
-		},
+		// A key:value map of shortcut keyboard keys and descriptions of
+		// the actions they trigger, generated in #configure()
+		keyboardShortcuts = {},
 
 		// Holds custom key code mappings
 		registeredKeyBindings = {};
@@ -1221,6 +1217,8 @@
 		if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor;
 		if( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition );
 
+		if( slide.hasAttribute( 'data-preload' ) ) element.setAttribute( 'data-preload', '' );
+
 		// Background image options are set on the content wrapper
 		if( data.backgroundSize ) contentElement.style.backgroundSize = data.backgroundSize;
 		if( data.backgroundRepeat ) contentElement.style.backgroundRepeat = data.backgroundRepeat;
@@ -1280,7 +1278,11 @@
 
 					// Check if the requested method can be found
 					if( data.method && typeof Reveal[data.method] === 'function' ) {
-						Reveal[data.method].apply( Reveal, data.args );
+						var result = Reveal[data.method].apply( Reveal, data.args );
+
+						// Dispatch a postMessage event with the returned value from
+						// our method invocation for getter functions
+						dispatchPostMessage( 'callback', { method: data.method, result: result } );
 					}
 				}
 			}, false );
@@ -1437,6 +1439,26 @@
 			dom.wrapper.removeAttribute( 'data-navigation-mode' );
 		}
 
+		// Define our contextual list of keyboard shortcuts
+		if( config.navigationMode === 'linear' ) {
+			keyboardShortcuts['&#8594;  ,  &#8595;  ,  SPACE  ,  N  ,  L  ,  J'] = 'Next slide';
+			keyboardShortcuts['&#8592;  ,  &#8593;  ,  P  ,  H  ,  K']           = 'Previous slide';
+		}
+		else {
+			keyboardShortcuts['N  ,  SPACE']   = 'Next slide';
+			keyboardShortcuts['P']             = 'Previous slide';
+			keyboardShortcuts['&#8592;  ,  H'] = 'Navigate left';
+			keyboardShortcuts['&#8594;  ,  L'] = 'Navigate right';
+			keyboardShortcuts['&#8593;  ,  K'] = 'Navigate up';
+			keyboardShortcuts['&#8595;  ,  J'] = 'Navigate down';
+		}
+
+		keyboardShortcuts['Home  ,  Shift &#8592;']        = 'First slide';
+		keyboardShortcuts['End  ,  Shift &#8594;']         = 'Last slide';
+		keyboardShortcuts['B  ,  .']                       = 'Pause';
+		keyboardShortcuts['F']                             = 'Fullscreen';
+		keyboardShortcuts['ESC, O']                        = 'Slide overview';
+
 		sync();
 
 	}
@@ -1587,6 +1609,29 @@
 
 	}
 
+	/**
+	 * Checks if a specific plugin has been registered.
+	 *
+	 * @param {String} id Unique plugin identifier
+	 */
+	function hasPlugin( id ) {
+
+		return !!plugins[id];
+
+	}
+
+	/**
+	 * Returns the specific plugin instance, if a plugin
+	 * with the given ID has been registered.
+	 *
+	 * @param {String} id Unique plugin identifier
+	 */
+	function getPlugin( id ) {
+
+		return plugins[id];
+
+	}
+
 	/**
 	 * Add a custom key binding with optional description to
 	 * be added to the help screen.
@@ -1942,8 +1987,25 @@
 
 		// If we're in an iframe, post each reveal.js event to the
 		// parent window. Used by the notes plugin
+		dispatchPostMessage( type );
+
+	}
+
+	/**
+	 * Dispatched a postMessage of the given type from our window.
+	 */
+	function dispatchPostMessage( type, data ) {
+
 		if( config.postMessageEvents && window.parent !== window.self ) {
-			window.parent.postMessage( JSON.stringify({ namespace: 'reveal', eventName: type, state: getState() }), '*' );
+			var message = {
+				namespace: 'reveal',
+				eventName: type,
+				state: getState()
+			};
+
+			extend( message, data );
+
+			window.parent.postMessage( JSON.stringify( message ), '*' );
 		}
 
 	}
@@ -2204,10 +2266,12 @@
 					transformSlides( { layout: '' } );
 				}
 				else {
-					// Prefer zoom for scaling up so that content remains crisp.
-					// Don't use zoom to scale down since that can lead to shifts
-					// in text layout/line breaks.
-					if( scale > 1 && features.zoom ) {
+					// Zoom Scaling
+					// Content remains crisp no matter how much we scale. Side
+					// effects are minor differences in text layout and iframe
+					// viewports changing size. A 200x200 iframe viewport in a
+					// 2x zoomed presentation ends up having a 400x400 viewport.
+					if( scale > 1 && features.zoom && window.devicePixelRatio < 2 ) {
 						dom.slides.style.zoom = scale;
 						dom.slides.style.left = '';
 						dom.slides.style.top = '';
@@ -2215,7 +2279,10 @@
 						dom.slides.style.right = '';
 						transformSlides( { layout: '' } );
 					}
-					// Apply scale transform as a fallback
+					// Transform Scaling
+					// Content layout remains the exact same when scaled up.
+					// Side effect is content becoming blurred, especially with
+					// high scale values on ldpi screens.
 					else {
 						dom.slides.style.zoom = '';
 						dom.slides.style.left = '50%';
@@ -3000,11 +3067,11 @@
 		syncBackground( slide );
 		syncFragments( slide );
 
+		loadSlide( slide );
+
 		updateBackground();
 		updateNotes();
 
-		loadSlide( slide );
-
 	}
 
 	/**
@@ -3270,7 +3337,7 @@
 			}
 
 			// Flag if there are ANY vertical slides, anywhere in the deck
-			if( dom.wrapper.querySelectorAll( '.slides>section>section' ).length ) {
+			if( hasVerticalSlides() ) {
 				dom.wrapper.classList.add( 'has-vertical-slides' );
 			}
 			else {
@@ -3278,7 +3345,7 @@
 			}
 
 			// Flag if there are ANY horizontal slides, anywhere in the deck
-			if( dom.wrapper.querySelectorAll( '.slides>section' ).length > 1 ) {
+			if( hasHorizontalSlides() ) {
 				dom.wrapper.classList.add( 'has-horizontal-slides' );
 			}
 			else {
@@ -3560,7 +3627,7 @@
 		// Stop content inside of previous backgrounds
 		if( previousBackground ) {
 
-			stopEmbeddedContent( previousBackground );
+			stopEmbeddedContent( previousBackground, { unloadIframes: !shouldPreload( previousBackground ) } );
 
 		}
 
@@ -3671,6 +3738,26 @@
 
 	}
 
+	/**
+	 * 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
+		var 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;
+	}
+
 	/**
 	 * Called when the given slide is within the configured view
 	 * distance. Shows the slide element and loads any content
@@ -3686,10 +3773,12 @@
 		slide.style.display = config.display;
 
 		// Media elements with data-src attributes
-		toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src]' ) ).forEach( function( element ) {
-			element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
-			element.setAttribute( 'data-lazy-loaded', '' );
-			element.removeAttribute( 'data-src' );
+		toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ) ).forEach( function( element ) {
+			if( element.tagName !== 'IFRAME' || shouldPreload( element ) ) {
+				element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
+				element.setAttribute( 'data-lazy-loaded', '' );
+				element.removeAttribute( 'data-src' );
+			}
 		} );
 
 		// Media elements with <source> children
@@ -3717,6 +3806,7 @@
 			background.style.display = 'block';
 
 			var backgroundContent = slide.slideBackgroundContentElement;
+			var backgroundIframe = slide.getAttribute( 'data-background-iframe' );
 
 			// If the background contains media, load it
 			if( background.hasAttribute( 'data-loaded' ) === false ) {
@@ -3725,8 +3815,7 @@
 				var backgroundImage = slide.getAttribute( 'data-background-image' ),
 					backgroundVideo = slide.getAttribute( 'data-background-video' ),
 					backgroundVideoLoop = slide.hasAttribute( 'data-background-video-loop' ),
-					backgroundVideoMuted = slide.hasAttribute( 'data-background-video-muted' ),
-					backgroundIframe = slide.getAttribute( 'data-background-iframe' );
+					backgroundVideoMuted = slide.hasAttribute( 'data-background-video-muted' );
 
 				// Images
 				if( backgroundImage ) {
@@ -3767,14 +3856,7 @@
 					iframe.setAttribute( 'mozallowfullscreen', '' );
 					iframe.setAttribute( 'webkitallowfullscreen', '' );
 
-					// Only load autoplaying content when the slide is shown to
-					// avoid having it play in the background
-					if( /autoplay=(1|true|yes)/gi.test( backgroundIframe ) ) {
-						iframe.setAttribute( 'data-src', backgroundIframe );
-					}
-					else {
-						iframe.setAttribute( 'src', backgroundIframe );
-					}
+					iframe.setAttribute( 'data-src', backgroundIframe );
 
 					iframe.style.width  = '100%';
 					iframe.style.height = '100%';
@@ -3785,6 +3867,19 @@
 				}
 			}
 
+			// Start loading preloadable iframes
+			var backgroundIframeElement = backgroundContent.querySelector( 'iframe[data-src]' );
+			if( backgroundIframeElement ) {
+
+				// Check if this iframe is eligible to be preloaded
+				if( shouldPreload( background ) && !/autoplay=(1|true|yes)/gi.test( backgroundIframe ) ) {
+					if( backgroundIframeElement.getAttribute( 'src' ) !== backgroundIframe ) {
+						backgroundIframeElement.setAttribute( 'src', backgroundIframe );
+					}
+				}
+
+			}
+
 		}
 
 	}
@@ -3804,10 +3899,15 @@
 		var background = getSlideBackground( slide );
 		if( background ) {
 			background.style.display = 'none';
+
+			// Unload any background iframes
+			toArray( background.querySelectorAll( 'iframe[src]' ) ).forEach( function( 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]' ) ).forEach( function( element ) {
+		toArray( slide.querySelectorAll( 'video[data-lazy-loaded][src], audio[data-lazy-loaded][src], iframe[data-lazy-loaded][src]' ) ).forEach( function( element ) {
 			element.setAttribute( 'data-src', element.getAttribute( 'src' ) );
 			element.removeAttribute( 'src' );
 		} );
@@ -4197,7 +4297,7 @@
 
 		}
 
-		return pastCount / ( totalCount - 1 );
+		return Math.min( pastCount / ( totalCount - 1 ), 1 );
 
 	}
 
@@ -4290,11 +4390,21 @@
 			writeURLTimeout = setTimeout( writeURL, delay );
 		}
 		else if( currentSlide ) {
+			// If we're configured to push to history OR the history
+			// API is not avaialble.
 			if( config.history || !window.history ) {
 				window.location.hash = locationHash();
 			}
+			// If we're configured to reflect the current slide in the
+			// URL without pushing to history.
 			else if( config.hash ) {
-				window.history.replaceState(null, null, '#' + locationHash());
+				window.history.replaceState( null, null, '#' + locationHash() );
+			}
+			// If history and hash are both disabled, a hash may still
+			// be added to the URL by clicking on a href with a hash
+			// target. Counter this by always removing the hash.
+			else {
+				window.history.replaceState( null, null, window.location.pathname + window.location.search );
 			}
 		}
 
@@ -4358,7 +4468,44 @@
 	 */
 	function getSlides() {
 
-		return toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ':not(.stack)' ));
+		return toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ':not(.stack)' ) );
+
+	}
+
+	/**
+	 * Returns a list of all horizontal slides in the deck. Each
+	 * vertical stack is included as one horizontal slide in the
+	 * resulting array.
+	 */
+	function getHorizontalSlides() {
+
+		return toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
+
+	}
+
+	/**
+	 * Returns all vertical slides that exist within this deck.
+	 */
+	function getVerticalSlides() {
+
+		return toArray( dom.wrapper.querySelectorAll( '.slides>section>section' ) );
+
+	}
+
+	/**
+	 * Returns true if there are at least two horizontal slides.
+	 */
+	function hasHorizontalSlides() {
+
+		return getHorizontalSlides().length > 1;
+	}
+
+	/**
+	 * Returns true if there are at least two vertical slides.
+	 */
+	function hasVerticalSlides() {
+
+		return getVerticalSlides().length > 1;
 
 	}
 
@@ -5045,8 +5192,8 @@
 
 		// Whitelist specific modified + keycode combinations
 		var prevSlideShortcut = event.shiftKey && event.keyCode === 32;
-		var firstSlideShortcut = ( event.metaKey || event.ctrlKey ) && keyCode === 37;
-		var lastSlideShortcut = ( event.metaKey || event.ctrlKey ) && keyCode === 39;
+		var firstSlideShortcut = event.shiftKey && keyCode === 37;
+		var lastSlideShortcut = event.shiftKey && keyCode === 39;
 
 		// Prevent all other events when a modifier is pressed
 		var unusedModifier = 	!prevSlideShortcut && !firstSlideShortcut && !lastSlideShortcut &&
@@ -5073,6 +5220,10 @@
 			return false;
 		}
 
+		// Use linear navigation if we're configured to OR if
+		// the presentation is one-dimensional
+		var useLinearMode = config.navigationMode === 'linear' || !hasHorizontalSlides() || !hasVerticalSlides();
+
 		var triggered = false;
 
 		// 1. User defined key bindings
@@ -5145,7 +5296,7 @@
 				if( firstSlideShortcut ) {
 					slide( 0 );
 				}
-				else if( !isOverview() && config.navigationMode === 'linear' ) {
+				else if( !isOverview() && useLinearMode ) {
 					navigatePrev();
 				}
 				else {
@@ -5157,7 +5308,7 @@
 				if( lastSlideShortcut ) {
 					slide( Number.MAX_VALUE );
 				}
-				else if( !isOverview() && config.navigationMode === 'linear' ) {
+				else if( !isOverview() && useLinearMode ) {
 					navigateNext();
 				}
 				else {
@@ -5166,7 +5317,7 @@
 			}
 			// K, UP
 			else if( keyCode === 75 || keyCode === 38 ) {
-				if( !isOverview() && config.navigationMode === 'linear' ) {
+				if( !isOverview() && useLinearMode ) {
 					navigatePrev();
 				}
 				else {
@@ -5175,7 +5326,7 @@
 			}
 			// J, DOWN
 			else if( keyCode === 74 || keyCode === 40 ) {
-				if( !isOverview() && config.navigationMode === 'linear' ) {
+				if( !isOverview() && useLinearMode ) {
 					navigateNext();
 				}
 				else {
@@ -5834,6 +5985,15 @@
 		// Returns the speaker notes string for a slide, or null
 		getSlideNotes: getSlideNotes,
 
+		// Returns an array with all horizontal/vertical slides in the deck
+		getHorizontalSlides: getHorizontalSlides,
+		getVerticalSlides: getVerticalSlides,
+
+		// Checks if the presentation contains two or more
+		// horizontal/vertical slides
+		hasHorizontalSlides: hasHorizontalSlides,
+		hasVerticalSlides: hasVerticalSlides,
+
 		// Returns the previous slide element, may be null
 		getPreviousSlide: function() {
 			return previousSlide;
@@ -5932,14 +6092,16 @@
 			}
 		},
 
-		// Adds/remvoes a custom key binding
+		// Adds/removes a custom key binding
 		addKeyBinding: addKeyBinding,
 		removeKeyBinding: removeKeyBinding,
 
-		// Called by plugins to register themselves
+		// API for registering and retrieving plugins
 		registerPlugin: registerPlugin,
+		hasPlugin: hasPlugin,
+		getPlugin: getPlugin,
 
-		// Programatically triggers a keyboard event
+		// Programmatically triggers a keyboard event
 		triggerKey: function( keyCode ) {
 			onDocumentKeyDown( { keyCode: keyCode } );
 		},

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


+ 0 - 2
lib/js/classList.js

@@ -1,2 +0,0 @@
-/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
-if(typeof document!=="undefined"&&!("classList" in document.createElement("a"))){(function(j){var a="classList",f="prototype",m=(j.HTMLElement||j.Element)[f],b=Object,k=String[f].trim||function(){return this.replace(/^\s+|\s+$/g,"")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===""){throw new n("SYNTAX_ERR","An invalid or illegal string was specified")}if(/\s/.test(o)){throw new n("INVALID_CHARACTER_ERR","String contains an invalid character")}return c.call(p,o)},d=function(s){var r=k.call(s.className),q=r?r.split(/\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.className=this.toString()}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+="";return g(this,o)!==-1};e.add=function(o){o+="";if(g(this,o)===-1){this.push(o);this._updateClassName()}};e.remove=function(p){p+="";var o=g(this,p);if(o!==-1){this.splice(o,1);this._updateClassName()}};e.toggle=function(o){o+="";if(g(this,o)===-1){this.add(o)}else{this.remove(o)}};e.toString=function(){return this.join(" ")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))};

File diff suppressed because it is too large
+ 0 - 1
lib/js/head.min.js


File diff suppressed because it is too large
+ 1 - 0
lib/js/promise.js


File diff suppressed because it is too large
+ 0 - 0
plugin/highlight/highlight.js


+ 23 - 3
plugin/notes/notes.html

@@ -539,12 +539,17 @@
 
 					callRevealApi( 'getSlidesAttributes', [], function ( slideAttributes ) {
 						callRevealApi( 'getConfig', [], function ( config ) {
+							var totalTime = config.totalTime;
+							var minTimePerSlide = config.minimumTimePerSlide || 0;
 							var defaultTiming = config.defaultTiming;
-							if (defaultTiming == null) {
+							if ((defaultTiming == null) && (totalTime == null)) {
 								callback(null);
 								return;
 							}
-
+							// Setting totalTime overrides defaultTiming
+							if (totalTime) {
+								defaultTiming = 0;
+							}
 							var timings = [];
 							for ( var i in slideAttributes ) {
 								var slide = slideAttributes[ i ];
@@ -559,7 +564,22 @@
 								}
 								timings.push(timing);
 							}
-
+							if ( totalTime ) {
+								// After we've allocated time to individual slides, we summarize it and
+								// subtract it from the total time
+								var remainingTime = totalTime - timings.reduce( function(a, b) { return a + b; }, 0 );
+								// The remaining time is divided by the number of slides that have 0 seconds
+								// allocated at the moment, giving the average time-per-slide on the remaining slides
+								var remainingSlides = (timings.filter( function(x) { return x == 0 }) ).length
+								var timePerSlide = Math.round( remainingTime / remainingSlides, 0 )
+								// And now we replace every zero-value timing with that average
+								timings = timings.map( function(x) { return (x==0 ? timePerSlide : x) } );
+							}
+							var slidesUnderMinimum = timings.filter( function(x) { return (x < minTimePerSlide) } ).length
+							if ( slidesUnderMinimum ) {
+								message = "The pacing time for " + slidesUnderMinimum + " slide(s) is under the configured minimum of " + minTimePerSlide + " seconds. Check the data-timing attribute on individual slides, or consider increasing the totalTime or minimumTimePerSlide configuration options (or removing some slides).";
+								alert(message);
+							}
 							callback( timings );
 						} );
 					} );

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