new postMessage-based notes plugin, moved node-based notes to notes-server (#190)
This commit is contained in:
		
							
								
								
									
										33
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								README.md
									
									
									
									
									
								
							| @@ -105,10 +105,9 @@ Reveal.initialize({ | ||||
| 		{ src: 'lib/js/data-markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, | ||||
| 		{ src: 'lib/js/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, | ||||
| 		// Zoom in and out with Alt+click | ||||
| 		{ src: 'plugin/zoom-js/zoom.js', condition: function() { return !!document.body.classList; } }, | ||||
| 		// Speaker notes support | ||||
| 		{ src: 'plugin/speakernotes/client.js', async: true, condition: function() { return window.location.host === 'localhost:1947'; } }, | ||||
| 		{ src: '/socket.io/socket.io.js', async: true, condition: function() { return window.location.host === 'localhost:1947'; } }, | ||||
| 		{ src: 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } }, | ||||
| 		// Speaker notes | ||||
| 		{ src: 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } } | ||||
| 	] | ||||
| }); | ||||
| ``` | ||||
| @@ -230,27 +229,23 @@ Here's an example of an exported presentation that's been uploaded to SlideShare | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Speaker Notes | ||||
|  | ||||
| If you're interested in using speaker notes, reveal.js comes with a Node server that allows you to deliver your presentation in one browser while viewing speaker notes in another.  | ||||
| reveal.js comes with a speaker notes plugin which can be used to present per-slide notes in a separate browser window. The notes window also gives you a preview of the next upcoming slide so it may be helpful even if you haven't written any notes. Append ```?notes``` to presentation URL or press the 's' key on your keyboard to open the notes window. | ||||
|  | ||||
| To include speaker notes in your presentation, simply add an `<aside class="notes">` element to any slide. These notes will be hidden in the main presentation view. | ||||
| Notes are written using the following markup structure: | ||||
|  | ||||
| It's also possible to write your notes with Markdown. To enable Markdown, add the ```data-markdown``` attribute to your note ```<aside>``` elements. | ||||
| ```html | ||||
| <section> | ||||
| 	<h2>Some Slide</h2> | ||||
|  | ||||
| You'll also need to [install Node.js](http://nodejs.org/); then, install the server dependencies by running `npm install`. | ||||
| 	<aside class="notes"> | ||||
| 		Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you open the speaker notes window (hit 's' on your keyboard). | ||||
| 	</aside> | ||||
| </section> | ||||
| ``` | ||||
|  | ||||
| Once Node.js and the dependencies are installed, run the following command from the root directory: | ||||
|  | ||||
| 		node plugin/speakernotes | ||||
|  | ||||
| By default, the slides will be served at [localhost:1947](http://localhost:1947). | ||||
|  | ||||
| You can change the appearance of the speaker notes by editing the file at `plugin/speakernotes/notes.html`.	 | ||||
|  | ||||
| ### Known Issues | ||||
|  | ||||
| - The notes page is supposed to show the current slide and the next slide, but when it first starts, it always shows the first slide in both positions.  | ||||
|  | ||||
| ## Folder Structure | ||||
| - **css/** Core styles without which the project does not function | ||||
|   | ||||
| @@ -51,7 +51,7 @@ | ||||
| 					</p> | ||||
|  | ||||
| 					<aside class="notes"> | ||||
| 						Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you run the speaker notes server. | ||||
| 						Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you open the speaker notes window (hit 's' on your keyboard). | ||||
| 					</aside> | ||||
| 				</section> | ||||
| 				 | ||||
| @@ -356,12 +356,10 @@ function linkify( selector ) { | ||||
| 					{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } }, | ||||
| 					{ src: 'lib/js/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, | ||||
| 					{ src: 'lib/js/data-markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, | ||||
| 					{ src: 'plugin/zoom-js/zoom.js', condition: function() { return !!document.body.classList; } }, | ||||
| 					{ src: '/socket.io/socket.io.js', async: true, condition: function() { return window.location.host === 'localhost:1947'; } }, | ||||
| 					{ src: 'plugin/speakernotes/client.js', async: true, condition: function() { return window.location.host === 'localhost:1947'; } } | ||||
| 					{ src: 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } }, | ||||
| 					{ src: 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } } | ||||
| 				] | ||||
| 			}); | ||||
|  | ||||
| 		</script> | ||||
|  | ||||
| 	</body> | ||||
|   | ||||
| @@ -32,12 +32,12 @@ app.get("/", function(req, res) { | ||||
| 
 | ||||
| app.get("/notes/:socketId", function(req, res) { | ||||
| 
 | ||||
| 	fs.readFile(opts.baseDir + 'plugin/speakernotes/notes.html', function(err, data) { | ||||
| 	fs.readFile(opts.baseDir + 'plugin/notes-server/notes.html', function(err, data) { | ||||
| 		res.send(Mustache.to_html(data.toString(), { | ||||
| 			socketId : req.params.socketId | ||||
| 		})); | ||||
| 	}); | ||||
| 	// fs.createReadStream(opts.baseDir + 'speakernotes/notes.html').pipe(res);
 | ||||
| 	// fs.createReadStream(opts.baseDir + 'notes-server/notes.html').pipe(res);
 | ||||
| }); | ||||
| 
 | ||||
| // Actually listen
 | ||||
							
								
								
									
										157
									
								
								plugin/notes/notes.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								plugin/notes/notes.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| <!doctype html> | ||||
| <html lang="en"> | ||||
| 	<head> | ||||
| 		<meta charset="utf-8"> | ||||
|  | ||||
| 		<title>reveal.js - Slide Notes</title> | ||||
|  | ||||
| 		<style> | ||||
| 			body { | ||||
| 				font-family: Helvetica; | ||||
| 			} | ||||
|  | ||||
| 			#notes { | ||||
| 				font-size: 24px; | ||||
| 				width: 640px; | ||||
| 				margin-top: 5px; | ||||
| 			} | ||||
|  | ||||
| 			#wrap-current-slide { | ||||
| 				width: 640px; | ||||
| 				height: 512px; | ||||
| 				float: left; | ||||
| 				overflow: hidden; | ||||
| 			} | ||||
|  | ||||
| 			#current-slide { | ||||
| 				width: 1280px; | ||||
| 				height: 1024px; | ||||
| 				border: none; | ||||
|  | ||||
| 				-webkit-transform-origin: 0 0; | ||||
| 					 -moz-transform-origin: 0 0; | ||||
| 						-ms-transform-origin: 0 0; | ||||
| 						 -o-transform-origin: 0 0; | ||||
| 								transform-origin: 0 0; | ||||
|  | ||||
| 				-webkit-transform: scale(0.5); | ||||
| 					 -moz-transform: scale(0.5); | ||||
| 						-ms-transform: scale(0.5); | ||||
| 						 -o-transform: scale(0.5); | ||||
| 								transform: scale(0.5); | ||||
| 			} | ||||
|  | ||||
| 			#wrap-next-slide { | ||||
| 				width: 448px; | ||||
| 				height: 358px; | ||||
| 				float: left; | ||||
| 				margin: 0 0 0 10px; | ||||
| 				overflow: hidden; | ||||
| 			} | ||||
|  | ||||
| 			#next-slide { | ||||
| 				width: 1280px; | ||||
| 				height: 1024px; | ||||
| 				border: none; | ||||
|  | ||||
| 				-webkit-transform-origin: 0 0; | ||||
| 					 -moz-transform-origin: 0 0; | ||||
| 						-ms-transform-origin: 0 0; | ||||
| 						 -o-transform-origin: 0 0; | ||||
| 								transform-origin: 0 0; | ||||
|  | ||||
| 				-webkit-transform: scale(0.35); | ||||
| 					 -moz-transform: scale(0.35); | ||||
| 						-ms-transform: scale(0.35); | ||||
| 						 -o-transform: scale(0.35); | ||||
| 								transform: scale(0.35); | ||||
| 			} | ||||
|  | ||||
| 			.slides { | ||||
| 				position: relative; | ||||
| 				margin-bottom: 10px; | ||||
| 				border: 1px solid black; | ||||
| 				border-radius: 2px; | ||||
| 				background: rgb(28, 30, 32); | ||||
| 			} | ||||
|  | ||||
| 			.slides span { | ||||
| 				position: absolute; | ||||
| 				top: 3px; | ||||
| 				left: 3px; | ||||
| 				font-weight: bold; | ||||
| 				font-size: 14px; | ||||
| 				color: rgba( 255, 255, 255, 0.9 ); | ||||
| 			} | ||||
| 		</style> | ||||
| 	</head> | ||||
|  | ||||
| 	<body> | ||||
|  | ||||
| 		<div id="wrap-current-slide" class="slides"> | ||||
| 			<iframe src="../../index.html" width="1280" height="1024" id="current-slide"></iframe> | ||||
| 		</div> | ||||
|  | ||||
| 		<div id="wrap-next-slide" class="slides"> | ||||
| 			<iframe src="../../index.html" width="640" height="512" id="next-slide"></iframe> | ||||
| 			<span>UPCOMING:</span> | ||||
| 		</div> | ||||
| 		<div id="notes"></div> | ||||
|  | ||||
| 		<script src="../../lib/js/showdown.js"></script> | ||||
| 		<script> | ||||
| 			window.addEventListener( 'load', function() { | ||||
|  | ||||
| 				(function( window, undefined ) { | ||||
| 					var notes = document.getElementById( 'notes' ), | ||||
| 						currentSlide = document.getElementById( 'current-slide' ), | ||||
| 						nextSlide = document.getElementById( 'next-slide' ); | ||||
|  | ||||
| 					window.addEventListener( 'message', function( event ) { | ||||
| 						var data = JSON.parse( event.data ); | ||||
|  | ||||
| 						if( data.markdown ) { | ||||
| 							notes.innerHTML = (new Showdown.converter()).makeHtml( data.notes ); | ||||
| 						} | ||||
| 						else { | ||||
| 							notes.innerHTML = data.notes; | ||||
| 						} | ||||
|  | ||||
| 						// Kill the slide listeners while responding to the event | ||||
| 						removeSlideListeners(); | ||||
|  | ||||
| 						// Update the note slides | ||||
| 						currentSlide.contentWindow.Reveal.slide( data.indexh, data.indexv ); | ||||
| 						nextSlide.contentWindow.Reveal.slide( data.nextindexh, data.nextindexv ); | ||||
|  | ||||
| 						// Resume listening on the next cycle | ||||
| 						setTimeout( addSlideListeners, 1 ); | ||||
|  | ||||
| 					}, false ); | ||||
|  | ||||
| 					function addSlideListeners() { | ||||
| 						currentSlide.contentWindow.Reveal.addEventListener( 'slidechanged', onNotesSlideChange, false ); | ||||
| 						nextSlide.contentWindow.Reveal.addEventListener( 'slidechanged', onNotesSlideChange, false ); | ||||
| 					} | ||||
|  | ||||
| 					function removeSlideListeners() { | ||||
| 						currentSlide.contentWindow.Reveal.removeEventListener( 'slidechanged', onNotesSlideChange, false ); | ||||
| 						nextSlide.contentWindow.Reveal.removeEventListener( 'slidechanged', onNotesSlideChange, false ); | ||||
| 					} | ||||
|  | ||||
| 					function onNotesSlideChange( event ) { | ||||
| 						window.opener.postMessage( JSON.stringify({ | ||||
| 							indexh : event.indexh, | ||||
| 							indexv : event.indexv | ||||
| 						}), '*' ); | ||||
| 					} | ||||
|  | ||||
| 					addSlideListeners(); | ||||
|  | ||||
| 				})( window ); | ||||
|  | ||||
| 			}, false ); | ||||
|  | ||||
| 		</script> | ||||
| 	</body> | ||||
| </html> | ||||
							
								
								
									
										74
									
								
								plugin/notes/notes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								plugin/notes/notes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| /** | ||||
|  * Handles opening of and synchronization with the reveal.js | ||||
|  * notes window. | ||||
|  */ | ||||
| var RevealNotes = (function() { | ||||
|  | ||||
| 	function openNotes() { | ||||
| 		var notesPopup = window.open( 'plugin/notes/notes.html', 'reveal.js - Notes', 'width=1120,height=850' ); | ||||
|  | ||||
| 		Reveal.addEventListener( 'slidechanged', post ); | ||||
|  | ||||
| 		// Posts the current slide data to the notes window | ||||
| 		function post() { | ||||
| 			var slideElement = Reveal.getCurrentSlide(), | ||||
| 				indexh = Reveal.getIndices().h, | ||||
| 				indexv = Reveal.getIndices().v, | ||||
| 				nextindexh, | ||||
| 				nextindexv; | ||||
|  | ||||
| 			if( slideElement.nextElementSibling && slideElement.parentNode.nodeName == 'SECTION' ) { | ||||
| 				nextindexh = indexh; | ||||
| 				nextindexv = indexv + 1; | ||||
| 			} else { | ||||
| 				nextindexh = indexh + 1; | ||||
| 				nextindexv = 0; | ||||
| 			} | ||||
|  | ||||
| 			var notes = slideElement.querySelector( 'aside.notes' ); | ||||
|  | ||||
| 			var slideData = { | ||||
| 				notes : notes ? notes.innerHTML : '', | ||||
| 				indexh : indexh, | ||||
| 				indexv : indexv, | ||||
| 				nextindexh : nextindexh, | ||||
| 				nextindexv : nextindexv, | ||||
| 				markdown : notes ? typeof notes.getAttribute( 'data-markdown' ) === 'string' : false | ||||
| 			}; | ||||
|  | ||||
| 			notesPopup.postMessage( JSON.stringify( slideData ), '*' ); | ||||
| 		} | ||||
|  | ||||
| 		// The main presentation is kept in sync when navigating the  | ||||
| 		// note slides so that the popup may be used as a remote | ||||
| 		window.addEventListener( 'message', function( event ) { | ||||
| 			var data = JSON.parse( event.data ); | ||||
|  | ||||
| 			if( data && typeof data.indexh === 'number' && typeof data.indexv === 'number' ) { | ||||
| 				Reveal.slide( data.indexh, data.indexv ); | ||||
| 			} | ||||
| 		} ); | ||||
|  | ||||
| 		// Navigate to the current slide when the notes are loaded | ||||
| 		notesPopup.addEventListener( 'load', post, false ); | ||||
| 	} | ||||
|  | ||||
| 	// If the there's a 'notes' query set, open directly | ||||
| 	if( window.location.search.match(/(\?|\&)notes/gi ) !== null ) { | ||||
| 		openNotes(); | ||||
| 	} | ||||
|  | ||||
| 	// Open the notes when the 's' key is hit | ||||
| 	document.addEventListener( 'keydown', function( event ) { | ||||
| 		// Disregard the event if the target is editable or a  | ||||
| 		// modifier is present | ||||
| 		if ( document.querySelector( ':focus' ) !== null || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return; | ||||
|  | ||||
| 		if( event.keyCode === 83 ) { | ||||
| 			event.preventDefault(); | ||||
| 			openNotes(); | ||||
| 		} | ||||
| 	}, false ); | ||||
|  | ||||
| 	return { open: openNotes } | ||||
| })(); | ||||
		Reference in New Issue
	
	Block a user