浏览代码

merge dev into flexbox

Hakim El Hattab 11 年之前
父节点
当前提交
dfcd60896b
共有 7 个文件被更改,包括 200 次插入65 次删除
  1. 17 1
      README.md
  2. 35 35
      index.html
  3. 78 13
      js/reveal.js
  4. 58 15
      plugin/notes/notes.html
  5. 1 1
      plugin/notes/notes.js
  6. 1 0
      test/test.html
  7. 10 0
      test/test.js

+ 17 - 1
README.md

@@ -13,7 +13,7 @@ reveal.js comes with a broad range of features including [nested slides](https:/
 
 
 ## Online Editor
 ## Online Editor
 
 
-Presentations are written using HTML or markdown but there's also an online editor for those of you who prefer a graphical interface. Give it a try at [http://slid.es](http://slid.es).
+Presentations are written using HTML or markdown but there's also an online editor for those of you who prefer a graphical interface. Give it a try at [http://slides.com](http://slides.com).
 
 
 
 
 ## Instructions
 ## Instructions
@@ -293,6 +293,22 @@ Reveal.configure({
 });
 });
 ```
 ```
 
 
+### Lazy Loading
+
+When working on presentation with a lot of image, video and audio content it's important to load lazily. Lazy loading means that reveal.js will only load the media for the few slides nearest to the current slide. The number of slides that are preloaded is determined by the `viewDistance` configuration option.
+
+To enable lazy loading all you need to do is change your "src" attributes to "data-src" as shown below. This is supported for image, video and audio elements.
+
+```html
+<section>
+  <img data-src="image.png">
+  <video>
+    <source data-src="video.webm" type="video/webm" />
+    <source data-src="video.mp4" type="video/mp4" />
+  </video>
+</section>
+```
+
 
 
 ### API
 ### API
 
 

+ 35 - 35
index.html

@@ -71,7 +71,7 @@
 							try pressing <a href="#" class="navigate-down">down</a>.
 							try pressing <a href="#" class="navigate-down">down</a>.
 						</p>
 						</p>
 						<a href="#" class="navigate-down">
 						<a href="#" class="navigate-down">
-							<img width="178" height="238" src="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png" alt="Down arrow">
+							<img width="178" height="238" data-src="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png" alt="Down arrow">
 						</a>
 						</a>
 					</section>
 					</section>
 					<section>
 					<section>
@@ -82,14 +82,14 @@
 						<h2>Basement Level 2</h2>
 						<h2>Basement Level 2</h2>
 						<p>Cornify</p>
 						<p>Cornify</p>
 						<a class="test" href="http://cornify.com">
 						<a class="test" href="http://cornify.com">
-							<img width="280" height="326" src="https://s3.amazonaws.com/hakim-static/reveal-js/cornify.gif" alt="Unicorn">
+							<img width="280" height="326" data-src="https://s3.amazonaws.com/hakim-static/reveal-js/cornify.gif" alt="Unicorn">
 						</a>
 						</a>
 					</section>
 					</section>
 					<section>
 					<section>
 						<h2>Basement Level 3</h2>
 						<h2>Basement Level 3</h2>
 						<p>That's it, time to go back up.</p>
 						<p>That's it, time to go back up.</p>
 						<a href="#/2">
 						<a href="#/2">
-							<img width="178" height="238" src="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png" alt="Up arrow" style="-webkit-transform: rotate(180deg);">
+							<img width="178" height="238" data-src="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png" alt="Up arrow" style="-webkit-transform: rotate(180deg);">
 						</a>
 						</a>
 					</section>
 					</section>
 				</section>
 				</section>
@@ -137,35 +137,35 @@
 					</ol>
 					</ol>
 				</section>
 				</section>
 
 
-                <section>
-                    <h2>Superb Tables</h2>
-                    <table>
-                        <thead>
-                            <tr>
-                                <th>Item</th>
-                                <th>Value</th>
-                                <th>Quantity</th>
-                            </tr>
-                        </thead>
-                        <tbody>
-                            <tr>
-                                <td>Apples</td>
-                                <td>$1</td>
-                                <td>7</td>
-                            <tr>
-                            <tr>
-                                <td>Lemonade</td>
-                                <td>$2</td>
-                                <td>18</td>
-                            <tr>
-                            <tr>
-                                <td>Bread</td>
-                                <td>$3</td>
-                                <td>2</td>
-                            <tr>
-                      </tbody>
-                   </table>
-               </section>
+				<section>
+					<h2>Superb Tables</h2>
+					<table>
+						<thead>
+							<tr>
+								<th>Item</th>
+								<th>Value</th>
+								<th>Quantity</th>
+							</tr>
+						</thead>
+						<tbody>
+							<tr>
+								<td>Apples</td>
+								<td>$1</td>
+								<td>7</td>
+							<tr>
+							<tr>
+								<td>Lemonade</td>
+								<td>$2</td>
+								<td>18</td>
+							<tr>
+							<tr>
+								<td>Bread</td>
+								<td>$3</td>
+								<td>2</td>
+							<tr>
+						</tbody>
+					</table>
+				</section>
 
 
 				<section data-markdown>
 				<section data-markdown>
 					<script type="text/template">
 					<script type="text/template">
@@ -231,7 +231,7 @@
 					<p>
 					<p>
 						Additionally custom events can be triggered on a per slide basis by binding to the <code>data-state</code> name.
 						Additionally custom events can be triggered on a per slide basis by binding to the <code>data-state</code> name.
 					</p>
 					</p>
-					<pre><code data-trim contenteditable style="font-size: 18px; margin-top: 20px;">
+					<pre><code class="javascript" data-trim contenteditable style="font-size: 18px;">
 Reveal.addEventListener( 'customevent', function() {
 Reveal.addEventListener( 'customevent', function() {
 	console.log( '"customevent" has fired' );
 	console.log( '"customevent" has fired' );
 } );
 } );
@@ -245,7 +245,7 @@ Reveal.addEventListener( 'customevent', function() {
 							Set <code>data-background="#007777"</code> on a slide to change the full page background to the given color. All CSS color formats are supported.
 							Set <code>data-background="#007777"</code> on a slide to change the full page background to the given color. All CSS color formats are supported.
 						</p>
 						</p>
 						<a href="#" class="navigate-down">
 						<a href="#" class="navigate-down">
-							<img width="178" height="238" src="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png" alt="Down arrow">
+							<img width="178" height="238" data-src="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png" alt="Down arrow">
 						</a>
 						</a>
 					</section>
 					</section>
 					<section data-background="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png">
 					<section data-background="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png">
@@ -346,7 +346,7 @@ function linkify( selector ) {
 				<section>
 				<section>
 					<h2>Spectacular image!</h2>
 					<h2>Spectacular image!</h2>
 					<a href="http://lab.hakim.se/meny/" target="_blank">
 					<a href="http://lab.hakim.se/meny/" target="_blank">
-						<img width="320" height="299" src="http://s3.amazonaws.com/hakim-static/portfolio/images/meny.png" alt="Meny">
+						<img width="320" height="299" data-src="http://s3.amazonaws.com/hakim-static/portfolio/images/meny.png" alt="Meny">
 					</a>
 					</a>
 				</section>
 				</section>
 
 

+ 78 - 13
js/reveal.js

@@ -507,7 +507,9 @@ var Reveal = (function(){
 		};
 		};
 
 
 		var element = document.createElement( 'div' );
 		var element = document.createElement( 'div' );
-		element.className = 'slide-background';
+
+		// Carry over custom classes from the slide to the background
+		element.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' );
 
 
 		if( data.background ) {
 		if( data.background ) {
 			// Auto-wrap image urls in url(...)
 			// Auto-wrap image urls in url(...)
@@ -968,8 +970,6 @@ var Reveal = (function(){
 	 */
 	 */
 	function dispatchEvent( type, args ) {
 	function dispatchEvent( type, args ) {
 
 
-		console.log('event', type);
-
 		var event = document.createEvent( 'HTMLEvents', 1, 2 );
 		var event = document.createEvent( 'HTMLEvents', 1, 2 );
 		event.initEvent( type, true, true );
 		event.initEvent( type, true, true );
 		extend( event, args );
 		extend( event, args );
@@ -1909,6 +1909,11 @@ var Reveal = (function(){
 				viewDistance = isOverview() ? 6 : 1;
 				viewDistance = isOverview() ? 6 : 1;
 			}
 			}
 
 
+			// Limit view distance on weaker devices
+			if( isPrintingPDF() ) {
+				viewDistance = Number.MAX_VALUE;
+			}
+
 			for( var x = 0; x < horizontalSlidesLength; x++ ) {
 			for( var x = 0; x < horizontalSlidesLength; x++ ) {
 				var horizontalSlide = horizontalSlides[x];
 				var horizontalSlide = horizontalSlides[x];
 
 
@@ -1919,7 +1924,13 @@ var Reveal = (function(){
 				distanceX = Math.abs( ( indexh - x ) % ( horizontalSlidesLength - viewDistance ) ) || 0;
 				distanceX = Math.abs( ( indexh - x ) % ( horizontalSlidesLength - viewDistance ) ) || 0;
 
 
 				// Show the horizontal slide if it's within the view distance
 				// Show the horizontal slide if it's within the view distance
-				horizontalSlide.classList[ distanceX > viewDistance ? 'remove' : 'add' ]( 'visible' );
+				if( distanceX < viewDistance ) {
+					horizontalSlide.classList.add( 'visible' );
+					loadSlide( horizontalSlide );
+				}
+				else {
+					horizontalSlide.classList.remove( 'visible' );
+				}
 
 
 				if( verticalSlidesLength ) {
 				if( verticalSlidesLength ) {
 
 
@@ -1930,7 +1941,13 @@ var Reveal = (function(){
 
 
 						distanceY = x === indexh ? Math.abs( indexv - y ) : Math.abs( y - oy );
 						distanceY = x === indexh ? Math.abs( indexv - y ) : Math.abs( y - oy );
 
 
-						verticalSlide.classList[ ( distanceX + distanceY ) > viewDistance ? 'remove' : 'add' ]( 'visible' );
+						if( distanceX + distanceY < viewDistance ) {
+							verticalSlide.classList.add( 'visible' );
+							loadSlide( verticalSlide );
+						}
+						else {
+							verticalSlide.classList.remove( 'visible' );
+						}
 					}
 					}
 
 
 				}
 				}
@@ -2042,14 +2059,18 @@ var Reveal = (function(){
 		// states of their slides (past/present/future)
 		// states of their slides (past/present/future)
 		toArray( dom.background.childNodes ).forEach( function( backgroundh, h ) {
 		toArray( dom.background.childNodes ).forEach( function( backgroundh, h ) {
 
 
+			backgroundh.classList.remove( 'past' );
+			backgroundh.classList.remove( 'present' );
+			backgroundh.classList.remove( 'future' );
+
 			if( h < indexh ) {
 			if( h < indexh ) {
-				backgroundh.className = 'slide-background ' + horizontalPast;
+				backgroundh.classList.add( horizontalPast );
 			}
 			}
 			else if ( h > indexh ) {
 			else if ( h > indexh ) {
-				backgroundh.className = 'slide-background ' + horizontalFuture;
+				backgroundh.classList.add( horizontalFuture );
 			}
 			}
 			else {
 			else {
-				backgroundh.className = 'slide-background present';
+				backgroundh.classList.add( 'present' );
 
 
 				// Store a reference to the current background element
 				// Store a reference to the current background element
 				currentBackground = backgroundh;
 				currentBackground = backgroundh;
@@ -2058,14 +2079,18 @@ var Reveal = (function(){
 			if( includeAll || h === indexh ) {
 			if( includeAll || h === indexh ) {
 				toArray( backgroundh.querySelectorAll( '.slide-background' ) ).forEach( function( backgroundv, v ) {
 				toArray( backgroundh.querySelectorAll( '.slide-background' ) ).forEach( function( backgroundv, v ) {
 
 
+					backgroundv.classList.remove( 'past' );
+					backgroundv.classList.remove( 'present' );
+					backgroundv.classList.remove( 'future' );
+
 					if( v < indexv ) {
 					if( v < indexv ) {
-						backgroundv.className = 'slide-background past';
+						backgroundv.classList.add( 'past' );
 					}
 					}
 					else if ( v > indexv ) {
 					else if ( v > indexv ) {
-						backgroundv.className = 'slide-background future';
+						backgroundv.classList.add( 'future' );
 					}
 					}
 					else {
 					else {
-						backgroundv.className = 'slide-background present';
+						backgroundv.classList.add( 'present' );
 
 
 						// Only if this is the present horizontal and vertical slide
 						// Only if this is the present horizontal and vertical slide
 						if( h === indexh ) currentBackground = backgroundv;
 						if( h === indexh ) currentBackground = backgroundv;
@@ -2145,6 +2170,37 @@ var Reveal = (function(){
 
 
 	}
 	}
 
 
+	/**
+	 * Loads any content that is set to load lazily (data-src)
+	 * inside of the given slide.
+	 */
+	function loadSlide( slide ) {
+
+		// 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.removeAttribute( 'data-src' );
+		} );
+
+		// Media elements with multiple <source>s
+		toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( function( media ) {
+			var sources = 0;
+
+			toArray( media.querySelectorAll( 'source[data-src]' ) ).forEach( function( source ) {
+				source.setAttribute( 'src', source.getAttribute( 'data-src' ) );
+				source.removeAttribute( 'data-src' );
+				sources += 1;
+			} );
+
+			// If we rewrote sources for this video/audio element, we need
+			// to manually tell it to load from its new origin
+			if( sources > 0 ) {
+				media.load();
+			}
+		} );
+
+	}
+
 	/**
 	/**
 	 * Determine what available routes there are for navigation.
 	 * Determine what available routes there are for navigation.
 	 *
 	 *
@@ -2502,8 +2558,17 @@ var Reveal = (function(){
 
 
 		if( typeof state === 'object' ) {
 		if( typeof state === 'object' ) {
 			slide( deserialize( state.indexh ), deserialize( state.indexv ), deserialize( state.indexf ) );
 			slide( deserialize( state.indexh ), deserialize( state.indexv ), deserialize( state.indexf ) );
-			togglePause( deserialize( state.paused ) );
-			toggleOverview( deserialize( state.overview ) );
+
+			var pausedFlag = deserialize( state.paused ),
+				overviewFlag = deserialize( state.overview );
+
+			if( typeof pausedFlag === 'boolean' && pausedFlag !== isPaused() ) {
+				togglePause( pausedFlag );
+			}
+
+			if( typeof overviewFlag === 'boolean' && overviewFlag !== isOverview() ) {
+				toggleOverview( overviewFlag );
+			}
 		}
 		}
 
 
 	}
 	}

+ 58 - 15
plugin/notes/notes.html

@@ -11,7 +11,7 @@
 			}
 			}
 
 
 			#current-slide,
 			#current-slide,
-			#next-slide,
+			#upcoming-slide,
 			#speaker-controls {
 			#speaker-controls {
 				padding: 6px;
 				padding: 6px;
 				box-sizing: border-box;
 				box-sizing: border-box;
@@ -19,14 +19,14 @@
 			}
 			}
 
 
 			#current-slide iframe,
 			#current-slide iframe,
-			#next-slide iframe {
+			#upcoming-slide iframe {
 				width: 100%;
 				width: 100%;
 				height: 100%;
 				height: 100%;
 				border: 1px solid #ddd;
 				border: 1px solid #ddd;
 			}
 			}
 
 
 			#current-slide .label,
 			#current-slide .label,
-			#next-slide .label {
+			#upcoming-slide .label {
 				position: absolute;
 				position: absolute;
 				top: 10px;
 				top: 10px;
 				left: 10px;
 				left: 10px;
@@ -45,7 +45,7 @@
 				padding-right: 0;
 				padding-right: 0;
 			}
 			}
 
 
-			#next-slide {
+			#upcoming-slide {
 				position: absolute;
 				position: absolute;
 				width: 35%;
 				width: 35%;
 				height: 40%;
 				height: 40%;
@@ -141,7 +141,7 @@
 	<body>
 	<body>
 
 
 		<div id="current-slide"></div>
 		<div id="current-slide"></div>
-		<div id="next-slide"><span class="label">UPCOMING:</span></div>
+		<div id="upcoming-slide"><span class="label">UPCOMING:</span></div>
 		<div id="speaker-controls">
 		<div id="speaker-controls">
 			<div class="speaker-controls-time">
 			<div class="speaker-controls-time">
 				<h4 class="label">Time</h4>
 				<h4 class="label">Time</h4>
@@ -169,7 +169,7 @@
 					notesValue,
 					notesValue,
 					currentState,
 					currentState,
 					currentSlide,
 					currentSlide,
-					nextSlide,
+					upcomingSlide,
 					connected = false;
 					connected = false;
 
 
 				window.addEventListener( 'message', function( event ) {
 				window.addEventListener( 'message', function( event ) {
@@ -239,30 +239,42 @@
 
 
 					// Update the note slides
 					// Update the note slides
 					currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
 					currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
-					nextSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
-					nextSlide.contentWindow.postMessage( JSON.stringify({ method: 'next' }), '*' );
+					upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
+					upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'next' }), '*' );
 
 
 				}
 				}
 
 
+				// Limit to max one state update per X ms
+				handleStateMessage = debounce( handleStateMessage, 200 );
+
 				/**
 				/**
 				 * Creates the preview iframes.
 				 * Creates the preview iframes.
 				 */
 				 */
 				function setupIframes( data ) {
 				function setupIframes( data ) {
 
 
-					var url = data.url + '?receiver&progress=false&overview=false&history=false';
+					var params = [
+						'receiver',
+						'progress=false',
+						'history=false',
+						'transition=none',
+						'backgroundTransition=none'
+					].join( '&' );
+
 					var hash = '#/' + data.state.indexh + '/' + data.state.indexv;
 					var hash = '#/' + data.state.indexh + '/' + data.state.indexv;
+					var currentURL = data.url + '?' + params + '&postMessageEvents=true' + hash;
+					var upcomingURL = data.url + '?' + params + '&controls=false' + hash;
 
 
 					currentSlide = document.createElement( 'iframe' );
 					currentSlide = document.createElement( 'iframe' );
 					currentSlide.setAttribute( 'width', 1280 );
 					currentSlide.setAttribute( 'width', 1280 );
 					currentSlide.setAttribute( 'height', 1024 );
 					currentSlide.setAttribute( 'height', 1024 );
-					currentSlide.setAttribute( 'src', url + '&postMessageEvents=true' + hash );
+					currentSlide.setAttribute( 'src', currentURL );
 					document.querySelector( '#current-slide' ).appendChild( currentSlide );
 					document.querySelector( '#current-slide' ).appendChild( currentSlide );
 
 
-					nextSlide = document.createElement( 'iframe' );
-					nextSlide.setAttribute( 'width', 640 );
-					nextSlide.setAttribute( 'height', 512 );
-					nextSlide.setAttribute( 'src', url + '&controls=false' + hash );
-					document.querySelector( '#next-slide' ).appendChild( nextSlide );
+					upcomingSlide = document.createElement( 'iframe' );
+					upcomingSlide.setAttribute( 'width', 640 );
+					upcomingSlide.setAttribute( 'height', 512 );
+					upcomingSlide.setAttribute( 'src', upcomingURL );
+					document.querySelector( '#upcoming-slide' ).appendChild( upcomingSlide );
 
 
 				}
 				}
 
 
@@ -323,6 +335,37 @@
 
 
 				}
 				}
 
 
+				/**
+				 * Limits the frequency at which a function can be called.
+				 */
+				function debounce( fn, ms ) {
+
+					var lastTime = 0,
+						timeout;
+
+					return function() {
+
+						var args = arguments;
+						var context = this;
+
+						clearTimeout( timeout );
+
+						var timeSinceLastCall = Date.now() - lastTime;
+						if( timeSinceLastCall > ms ) {
+							fn.apply( context, args );
+							lastTime = Date.now();
+						}
+						else {
+							timeout = setTimeout( function() {
+								fn.apply( context, args );
+								lastTime = Date.now();
+							}, ms - timeSinceLastCall );
+						}
+
+					}
+
+				}
+
 			})();
 			})();
 
 
 		</script>
 		</script>

+ 1 - 1
plugin/notes/notes.js

@@ -14,7 +14,7 @@ var RevealNotes = (function() {
 	function openNotes() {
 	function openNotes() {
 		var jsFileLocation = document.querySelector('script[src$="notes.js"]').src;  // this js file path
 		var jsFileLocation = document.querySelector('script[src$="notes.js"]').src;  // this js file path
 		jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, '');   // the js folder path
 		jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, '');   // the js folder path
-		var notesPopup = window.open( jsFileLocation + 'notes.html', 'reveal.js - Notes', 'width=1120,height=850' );
+		var notesPopup = window.open( jsFileLocation + 'notes.html', 'reveal.js - Notes', 'width=1100,height=700' );
 
 
 		/**
 		/**
 		 * Connect to the notes window through a postmessage handshake.
 		 * Connect to the notes window through a postmessage handshake.

+ 1 - 0
test/test.html

@@ -21,6 +21,7 @@
 
 
 				<section>
 				<section>
 					<h1>1</h1>
 					<h1>1</h1>
+					<img data-src="fake-url.png">
 				</section>
 				</section>
 
 
 				<section>
 				<section>

+ 10 - 0
test/test.js

@@ -449,6 +449,16 @@ Reveal.addEventListener( 'ready', function() {
 	});
 	});
 
 
 
 
+	// ---------------------------------------------------------------
+	// LAZY-LOADING TESTS
+
+	QUnit.module( 'Lazy-Loading' );
+
+	test( 'img with data-src', function() {
+		strictEqual( document.querySelectorAll( '.reveal section img[src]' ).length, 1, 'Image source has been set' );
+	});
+
+
 	// ---------------------------------------------------------------
 	// ---------------------------------------------------------------
 	// EVENT TESTS
 	// EVENT TESTS