diff --git a/js/reveal.js b/js/reveal.js index 230d0010..091372e1 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -3901,6 +3901,20 @@ } + function getSlidesMetaInfo() { + + var slides = getSlides(); + return slides.map( function (slide) { + var meta = {}; + for( var i = 0; i < slide.attributes.length; i++ ) { + var attribute = slide.attributes[ i ]; + meta[ attribute.name ] = attribute.value; + } + return meta; + } ); + + } + /** * Retrieves the total number of slides in this presentation. * @@ -5252,6 +5266,8 @@ // Returns an Array of all slides getSlides: getSlides, + getSlidesMetaInfo: getSlidesMetaInfo, + // Returns the total number of slides getTotalSlides: getTotalSlides, diff --git a/plugin/notes/notes.html b/plugin/notes/notes.html index 5b75d736..eff12750 100644 --- a/plugin/notes/notes.html +++ b/plugin/notes/notes.html @@ -329,6 +329,8 @@ upcomingSlide, layoutLabel, layoutDropdown, + pendingCalls = {}, + lastRevealApiCallId = 0, connected = false; var SPEAKER_LAYOUTS = { @@ -356,6 +358,10 @@ else if( data.type === 'state' ) { handleStateMessage( data ); } + else if( data.type === 'return' ) { + pendingCalls[data.callId](data.result); + delete pendingCalls[data.callId]; + } } // Messages sent by the reveal.js inside of the current slide preview else if( data && data.namespace === 'reveal' ) { @@ -372,6 +378,18 @@ } ); + function callRevealApi( methodName, methodArguments, callback ) { + var callId = ++lastRevealApiCallId; + pendingCalls[callId] = callback; + window.opener.postMessage( JSON.stringify( { + namespace: 'reveal-notes', + type: 'call', + callId: callId, + methodName: methodName, + arguments: methodArguments + } ), '*' ); + } + /** * Called when the main window is trying to establish a * connection. @@ -486,28 +504,34 @@ } - function getTimings() { + function getTimings( callback ) { - var slides = Reveal.getSlides(); - var defaultTiming = Reveal.getConfig().defaultTiming; - if (defaultTiming == null) { - return null; - } - var timings = []; - for ( var i in slides ) { - var slide = slides[i]; - var timing = defaultTiming; - if( slide.hasAttribute( 'data-timing' )) { - var t = slide.getAttribute( 'data-timing' ); - timing = parseInt(t); - if( isNaN(timing) ) { - console.warn("Could not parse timing '" + t + "' of slide " + i + "; using default of " + defaultTiming); - timing = defaultTiming; + callRevealApi( 'getSlidesMetaInfo', [], function ( slides ) { + callRevealApi( 'getConfig', [], function ( config ) { + var defaultTiming = config.defaultTiming; + if (defaultTiming == null) { + callback(null); + return; } - } - timings.push(timing); - } - return timings; + + var timings = []; + for ( var i in slides ) { + var slide = slides[ i ]; + var timing = defaultTiming; + if( slide.hasOwnProperty( 'data-timing' )) { + var t = slide[ 'data-timing' ]; + timing = parseInt(t); + if( isNaN(timing) ) { + console.warn("Could not parse timing '" + t + "' of slide " + i + "; using default of " + defaultTiming); + timing = defaultTiming; + } + } + timings.push(timing); + } + + callback( timings ); + } ); + } ); } @@ -515,15 +539,15 @@ * Return the number of seconds allocated for presenting * all slides up to and including this one. */ - function getTimeAllocated(timings) { + function getTimeAllocated( timings, callback ) { - var slides = Reveal.getSlides(); - var allocated = 0; - var currentSlide = Reveal.getSlidePastCount(); - for (var i in slides.slice(0, currentSlide + 1)) { - allocated += timings[i]; - } - return allocated; + callRevealApi( 'getSlidePastCount', [], function ( currentSlide ) { + var allocated = 0; + for (var i in timings.slice(0, currentSlide + 1)) { + allocated += timings[i]; + } + callback( allocated ); + } ); } @@ -545,12 +569,51 @@ pacingMinutesEl = pacingEl.querySelector( '.minutes-value' ), pacingSecondsEl = pacingEl.querySelector( '.seconds-value' ); - var timings = getTimings(); - if (timings !== null) { - pacingTitleEl.style.removeProperty('display'); - pacingEl.style.removeProperty('display'); + var timings = null; + getTimings( function ( _timings ) { + + timings = _timings; + if (_timings !== null) { + pacingTitleEl.style.removeProperty('display'); + pacingEl.style.removeProperty('display'); + } + + // Update once directly + _updateTimer(); + + // Then update every second + setInterval( _updateTimer, 1000 ); + + } ); + + + function _resetTimer() { + + if (timings == null) { + start = new Date(); + _updateTimer(); + } + else { + // Reset timer to beginning of current slide + getTimeAllocated( timings, function ( slideEndTimingSeconds ) { + var slideEndTiming = slideEndTimingSeconds * 1000; + callRevealApi( 'getSlidePastCount', [], function ( currentSlide ) { + var currentSlideTiming = timings[currentSlide] * 1000; + var previousSlidesTiming = slideEndTiming - currentSlideTiming; + var now = new Date(); + start = new Date(now.getTime() - previousSlidesTiming); + _updateTimer(); + } ); + } ); + } + } + timeEl.addEventListener( 'click', function() { + _resetTimer(); + return false; + } ); + function _displayTime( hrEl, minEl, secEl, time) { var sign = Math.sign(time) == -1 ? "-" : ""; @@ -592,52 +655,26 @@ function _updatePacing(diff) { - var slideEndTiming = getTimeAllocated(timings) * 1000; - var currentSlide = Reveal.getSlidePastCount(); - var currentSlideTiming = timings[currentSlide] * 1000; - var timeLeftCurrentSlide = slideEndTiming - diff; - if (timeLeftCurrentSlide < 0) { - pacingEl.className = 'pacing behind'; - } - else if (timeLeftCurrentSlide < currentSlideTiming) { - pacingEl.className = 'pacing on-track'; - } - else { - pacingEl.className = 'pacing ahead'; - } - _displayTime( pacingHoursEl, pacingMinutesEl, pacingSecondsEl, timeLeftCurrentSlide ); + getTimeAllocated( timings, function ( slideEndTimingSeconds ) { + var slideEndTiming = slideEndTimingSeconds * 1000; + callRevealApi( 'getSlidePastCount', [], function ( currentSlide ) { + var currentSlideTiming = timings[currentSlide] * 1000; + var timeLeftCurrentSlide = slideEndTiming - diff; + if (timeLeftCurrentSlide < 0) { + pacingEl.className = 'pacing behind'; + } + else if (timeLeftCurrentSlide < currentSlideTiming) { + pacingEl.className = 'pacing on-track'; + } + else { + pacingEl.className = 'pacing ahead'; + } + _displayTime( pacingHoursEl, pacingMinutesEl, pacingSecondsEl, timeLeftCurrentSlide ); + } ); + } ); } - // Update once directly - _updateTimer(); - - // Then update every second - setInterval( _updateTimer, 1000 ); - - function _resetTimer() { - - if (timings == null) { - start = new Date(); - } - else { - // Reset timer to beginning of current slide - var slideEndTiming = getTimeAllocated(timings) * 1000; - var currentSlide = Reveal.getSlidePastCount(); - var currentSlideTiming = timings[currentSlide] * 1000; - var previousSlidesTiming = slideEndTiming - currentSlideTiming; - var now = new Date(); - start = new Date(now.getTime() - previousSlidesTiming); - } - _updateTimer(); - - } - - timeEl.addEventListener( 'click', function() { - _resetTimer(); - return false; - } ); - } /** diff --git a/plugin/notes/notes.js b/plugin/notes/notes.js index 3f00eb6b..dd7df8ec 100644 --- a/plugin/notes/notes.js +++ b/plugin/notes/notes.js @@ -21,8 +21,6 @@ var RevealNotes = (function() { var notesPopup = window.open( notesFilePath, 'reveal.js - Notes', 'width=1100,height=700' ); - // Allow popup window access to Reveal API - notesPopup.Reveal = this.Reveal; /** * Connect to the notes window through a postmessage handshake. @@ -47,9 +45,22 @@ var RevealNotes = (function() { clearInterval( connectInterval ); onConnected(); } + if( data && data.namespace === 'reveal-notes' && data.type === 'call' ) { + callRevealApi( data.methodName, data.arguments, data.callId ); + } } ); } + function callRevealApi( methodName, methodArguments, callId ) { + var result = Reveal[methodName].call(Reveal, methodArguments); + notesPopup.postMessage( JSON.stringify( { + namespace: 'reveal-notes', + type: 'return', + result: result, + callId: callId + } ), '*' ); + } + /** * Posts the current slide data to the notes window */