Browse Source

merge dev into flexbox

Hakim El Hattab 11 years ago
parent
commit
dfcd60896b
7 changed files with 200 additions and 65 deletions
  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
 
-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
@@ -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
 

+ 35 - 35
index.html

@@ -71,7 +71,7 @@
 							try pressing <a href="#" class="navigate-down">down</a>.
 						</p>
 						<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>
 					</section>
 					<section>
@@ -82,14 +82,14 @@
 						<h2>Basement Level 2</h2>
 						<p>Cornify</p>
 						<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>
 					</section>
 					<section>
 						<h2>Basement Level 3</h2>
 						<p>That's it, time to go back up.</p>
 						<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>
 					</section>
 				</section>
@@ -137,35 +137,35 @@
 					</ol>
 				</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>
 					<script type="text/template">
@@ -231,7 +231,7 @@
 					<p>
 						Additionally custom events can be triggered on a per slide basis by binding to the <code>data-state</code> name.
 					</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() {
 	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.
 						</p>
 						<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>
 					</section>
 					<section data-background="https://s3.amazonaws.com/hakim-static/reveal-js/arrow.png">
@@ -346,7 +346,7 @@ function linkify( selector ) {
 				<section>
 					<h2>Spectacular image!</h2>
 					<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>
 				</section>
 

+ 78 - 13
js/reveal.js

@@ -507,7 +507,9 @@ var Reveal = (function(){
 		};
 
 		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 ) {
 			// Auto-wrap image urls in url(...)
@@ -968,8 +970,6 @@ var Reveal = (function(){
 	 */
 	function dispatchEvent( type, args ) {
 
-		console.log('event', type);
-
 		var event = document.createEvent( 'HTMLEvents', 1, 2 );
 		event.initEvent( type, true, true );
 		extend( event, args );
@@ -1909,6 +1909,11 @@ var Reveal = (function(){
 				viewDistance = isOverview() ? 6 : 1;
 			}
 
+			// Limit view distance on weaker devices
+			if( isPrintingPDF() ) {
+				viewDistance = Number.MAX_VALUE;
+			}
+
 			for( var x = 0; x < horizontalSlidesLength; x++ ) {
 				var horizontalSlide = horizontalSlides[x];
 
@@ -1919,7 +1924,13 @@ var Reveal = (function(){
 				distanceX = Math.abs( ( indexh - x ) % ( horizontalSlidesLength - viewDistance ) ) || 0;
 
 				// 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 ) {
 
@@ -1930,7 +1941,13 @@ var Reveal = (function(){
 
 						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)
 		toArray( dom.background.childNodes ).forEach( function( backgroundh, h ) {
 
+			backgroundh.classList.remove( 'past' );
+			backgroundh.classList.remove( 'present' );
+			backgroundh.classList.remove( 'future' );
+
 			if( h < indexh ) {
-				backgroundh.className = 'slide-background ' + horizontalPast;
+				backgroundh.classList.add( horizontalPast );
 			}
 			else if ( h > indexh ) {
-				backgroundh.className = 'slide-background ' + horizontalFuture;
+				backgroundh.classList.add( horizontalFuture );
 			}
 			else {
-				backgroundh.className = 'slide-background present';
+				backgroundh.classList.add( 'present' );
 
 				// Store a reference to the current background element
 				currentBackground = backgroundh;
@@ -2058,14 +2079,18 @@ var Reveal = (function(){
 			if( includeAll || h === indexh ) {
 				toArray( backgroundh.querySelectorAll( '.slide-background' ) ).forEach( function( backgroundv, v ) {
 
+					backgroundv.classList.remove( 'past' );
+					backgroundv.classList.remove( 'present' );
+					backgroundv.classList.remove( 'future' );
+
 					if( v < indexv ) {
-						backgroundv.className = 'slide-background past';
+						backgroundv.classList.add( 'past' );
 					}
 					else if ( v > indexv ) {
-						backgroundv.className = 'slide-background future';
+						backgroundv.classList.add( 'future' );
 					}
 					else {
-						backgroundv.className = 'slide-background present';
+						backgroundv.classList.add( 'present' );
 
 						// Only if this is the present horizontal and vertical slide
 						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.
 	 *
@@ -2502,8 +2558,17 @@ var Reveal = (function(){
 
 		if( typeof state === 'object' ) {
 			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,
-			#next-slide,
+			#upcoming-slide,
 			#speaker-controls {
 				padding: 6px;
 				box-sizing: border-box;
@@ -19,14 +19,14 @@
 			}
 
 			#current-slide iframe,
-			#next-slide iframe {
+			#upcoming-slide iframe {
 				width: 100%;
 				height: 100%;
 				border: 1px solid #ddd;
 			}
 
 			#current-slide .label,
-			#next-slide .label {
+			#upcoming-slide .label {
 				position: absolute;
 				top: 10px;
 				left: 10px;
@@ -45,7 +45,7 @@
 				padding-right: 0;
 			}
 
-			#next-slide {
+			#upcoming-slide {
 				position: absolute;
 				width: 35%;
 				height: 40%;
@@ -141,7 +141,7 @@
 	<body>
 
 		<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 class="speaker-controls-time">
 				<h4 class="label">Time</h4>
@@ -169,7 +169,7 @@
 					notesValue,
 					currentState,
 					currentSlide,
-					nextSlide,
+					upcomingSlide,
 					connected = false;
 
 				window.addEventListener( 'message', function( event ) {
@@ -239,30 +239,42 @@
 
 					// Update the note slides
 					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.
 				 */
 				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 currentURL = data.url + '?' + params + '&postMessageEvents=true' + hash;
+					var upcomingURL = data.url + '?' + params + '&controls=false' + hash;
 
 					currentSlide = document.createElement( 'iframe' );
 					currentSlide.setAttribute( 'width', 1280 );
 					currentSlide.setAttribute( 'height', 1024 );
-					currentSlide.setAttribute( 'src', url + '&postMessageEvents=true' + hash );
+					currentSlide.setAttribute( 'src', currentURL );
 					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>

+ 1 - 1
plugin/notes/notes.js

@@ -14,7 +14,7 @@ var RevealNotes = (function() {
 	function openNotes() {
 		var jsFileLocation = document.querySelector('script[src$="notes.js"]').src;  // this js file 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.

+ 1 - 0
test/test.html

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