presentations

Presentations
Log | Files | Refs

notes.js (5095B)


      1 /**
      2  * Handles opening of and synchronization with the reveal.js
      3  * notes window.
      4  *
      5  * Handshake process:
      6  * 1. This window posts 'connect' to notes window
      7  *    - Includes URL of presentation to show
      8  * 2. Notes window responds with 'connected' when it is available
      9  * 3. This window proceeds to send the current presentation state
     10  *    to the notes window
     11  */
     12 var RevealNotes = (function() {
     13 
     14     var notesPopup = null;
     15 
     16 	function openNotes( notesFilePath ) {
     17 
     18         if (notesPopup && !notesPopup.closed) {
     19             notesPopup.focus();
     20             return;
     21         }
     22 
     23 		if( !notesFilePath ) {
     24 			var jsFileLocation = document.querySelector('script[src$="notes.js"]').src;  // this js file path
     25 			jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, '');   // the js folder path
     26 			notesFilePath = jsFileLocation + 'notes.html';
     27 		}
     28 
     29 		notesPopup = window.open( notesFilePath, 'reveal.js - Notes', 'width=1100,height=700' );
     30 
     31 		if( !notesPopup ) {
     32 			alert( 'Speaker view popup failed to open. Please make sure popups are allowed and reopen the speaker view.' );
     33 			return;
     34 		}
     35 
     36 		/**
     37 		 * Connect to the notes window through a postmessage handshake.
     38 		 * Using postmessage enables us to work in situations where the
     39 		 * origins differ, such as a presentation being opened from the
     40 		 * file system.
     41 		 */
     42 		function connect() {
     43 			// Keep trying to connect until we get a 'connected' message back
     44 			var connectInterval = setInterval( function() {
     45 				notesPopup.postMessage( JSON.stringify( {
     46 					namespace: 'reveal-notes',
     47 					type: 'connect',
     48 					url: window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search,
     49 					state: Reveal.getState()
     50 				} ), '*' );
     51 			}, 500 );
     52 
     53 			window.addEventListener( 'message', function( event ) {
     54 				var data = JSON.parse( event.data );
     55 				if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) {
     56 					clearInterval( connectInterval );
     57 					onConnected();
     58 				}
     59 				if( data && data.namespace === 'reveal-notes' && data.type === 'call' ) {
     60 					callRevealApi( data.methodName, data.arguments, data.callId );
     61 				}
     62 			} );
     63 		}
     64 
     65 		/**
     66 		 * Calls the specified Reveal.js method with the provided argument
     67 		 * and then pushes the result to the notes frame.
     68 		 */
     69 		function callRevealApi( methodName, methodArguments, callId ) {
     70 
     71 			var result = Reveal[methodName].apply( Reveal, methodArguments );
     72 			notesPopup.postMessage( JSON.stringify( {
     73 				namespace: 'reveal-notes',
     74 				type: 'return',
     75 				result: result,
     76 				callId: callId
     77 			} ), '*' );
     78 
     79 		}
     80 
     81 		/**
     82 		 * Posts the current slide data to the notes window
     83 		 */
     84 		function post( event ) {
     85 
     86 			var slideElement = Reveal.getCurrentSlide(),
     87 				notesElement = slideElement.querySelector( 'aside.notes' ),
     88 				fragmentElement = slideElement.querySelector( '.current-fragment' );
     89 
     90 			var messageData = {
     91 				namespace: 'reveal-notes',
     92 				type: 'state',
     93 				notes: '',
     94 				markdown: false,
     95 				whitespace: 'normal',
     96 				state: Reveal.getState()
     97 			};
     98 
     99 			// Look for notes defined in a slide attribute
    100 			if( slideElement.hasAttribute( 'data-notes' ) ) {
    101 				messageData.notes = slideElement.getAttribute( 'data-notes' );
    102 				messageData.whitespace = 'pre-wrap';
    103 			}
    104 
    105 			// Look for notes defined in a fragment
    106 			if( fragmentElement ) {
    107 				var fragmentNotes = fragmentElement.querySelector( 'aside.notes' );
    108 				if( fragmentNotes ) {
    109 					notesElement = fragmentNotes;
    110 				}
    111 				else if( fragmentElement.hasAttribute( 'data-notes' ) ) {
    112 					messageData.notes = fragmentElement.getAttribute( 'data-notes' );
    113 					messageData.whitespace = 'pre-wrap';
    114 
    115 					// In case there are slide notes
    116 					notesElement = null;
    117 				}
    118 			}
    119 
    120 			// Look for notes defined in an aside element
    121 			if( notesElement ) {
    122 				messageData.notes = notesElement.innerHTML;
    123 				messageData.markdown = typeof notesElement.getAttribute( 'data-markdown' ) === 'string';
    124 			}
    125 
    126 			notesPopup.postMessage( JSON.stringify( messageData ), '*' );
    127 
    128 		}
    129 
    130 		/**
    131 		 * Called once we have established a connection to the notes
    132 		 * window.
    133 		 */
    134 		function onConnected() {
    135 
    136 			// Monitor events that trigger a change in state
    137 			Reveal.addEventListener( 'slidechanged', post );
    138 			Reveal.addEventListener( 'fragmentshown', post );
    139 			Reveal.addEventListener( 'fragmenthidden', post );
    140 			Reveal.addEventListener( 'overviewhidden', post );
    141 			Reveal.addEventListener( 'overviewshown', post );
    142 			Reveal.addEventListener( 'paused', post );
    143 			Reveal.addEventListener( 'resumed', post );
    144 
    145 			// Post the initial state
    146 			post();
    147 
    148 		}
    149 
    150 		connect();
    151 
    152 	}
    153 
    154 	return {
    155 		init: function() {
    156 
    157 			if( !/receiver/i.test( window.location.search ) ) {
    158 
    159 				// If the there's a 'notes' query set, open directly
    160 				if( window.location.search.match( /(\?|\&)notes/gi ) !== null ) {
    161 					openNotes();
    162 				}
    163 
    164 				// Open the notes when the 's' key is hit
    165 				Reveal.addKeyBinding({keyCode: 83, key: 'S', description: 'Speaker notes view'}, function() {
    166 					openNotes();
    167 				} );
    168 
    169 			}
    170 
    171 		},
    172 
    173 		open: openNotes
    174 	};
    175 
    176 })();
    177 
    178 Reveal.registerPlugin( 'notes', RevealNotes );