@@ -171,37 +158,112 @@
diff --git a/plugin/notes/notes.js b/plugin/notes/notes.js
index 3f68b5d..31efd81 100644
--- a/plugin/notes/notes.js
+++ b/plugin/notes/notes.js
@@ -1,6 +1,13 @@
/**
* Handles opening of and synchronization with the reveal.js
* notes window.
+ *
+ * Handshake process:
+ * 1. This window posts 'connect' to notes window
+ * - Includes URL of presentation to show
+ * 2. Notes window responds with 'connected' when it is available
+ * 3. This window proceeds to send the current presentation state
+ * to the notes window
*/
var RevealNotes = (function() {
@@ -9,41 +16,46 @@ var RevealNotes = (function() {
jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path
var notesPopup = window.open( jsFileLocation + 'notes.html', 'reveal.js - Notes', 'width=1120,height=850' );
- // Fires when slide is changed
- Reveal.addEventListener( 'slidechanged', post );
-
- // Fires when a fragment is shown
- Reveal.addEventListener( 'fragmentshown', post );
+ /**
+ * Connect to the notes window through a postmessage handshake.
+ * Using postmessage enables us to work in situations where the
+ * origins differ, such as a presentation being opened from the
+ * file system.
+ */
+ function connect() {
+ // Keep trying to connect until we get a 'connected' message back
+ var connectInterval = setInterval( function() {
+ notesPopup.postMessage( JSON.stringify( {
+ namespace: 'reveal-notes',
+ type: 'connect',
+ url: window.location.protocol + '//' + window.location.host + window.location.pathname,
+ state: Reveal.getState()
+ } ), '*' );
+ }, 500 );
- // Fires when a fragment is hidden
- Reveal.addEventListener( 'fragmenthidden', post );
+ window.addEventListener( 'message', function( event ) {
+ var data = JSON.parse( event.data );
+ if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) {
+ clearInterval( connectInterval );
+ onConnected();
+ }
+ } );
+ }
/**
* Posts the current slide data to the notes window
*/
function post() {
+
var slideElement = Reveal.getCurrentSlide(),
- slideIndices = Reveal.getIndices(),
- notesElement = slideElement.querySelector( 'aside.notes' ),
- nextindexh,
- nextindexv;
-
- if( slideElement.nextElementSibling && slideElement.parentNode.nodeName == 'SECTION' ) {
- nextindexh = slideIndices.h;
- nextindexv = slideIndices.v + 1;
- } else {
- nextindexh = slideIndices.h + 1;
- nextindexv = 0;
- }
+ notesElement = slideElement.querySelector( 'aside.notes' );
var messageData = {
- notes : '',
- indexh : slideIndices.h,
- indexv : slideIndices.v,
- indexf : slideIndices.f,
- nextindexh : nextindexh,
- nextindexv : nextindexv,
- markdown : false
+ namespace: 'reveal-notes',
+ type: 'state',
+ notes: '',
+ markdown: false,
+ state: Reveal.getState()
};
// Look for notes defined in a slide attribute
@@ -58,12 +70,30 @@ var RevealNotes = (function() {
}
notesPopup.postMessage( JSON.stringify( messageData ), '*' );
+
}
- // Navigate to the current slide when the notes are loaded
- notesPopup.addEventListener( 'load', function( event ) {
+ /**
+ * Called once we have established a connection to the notes
+ * window.
+ */
+ function onConnected() {
+
+ // Monitor events that trigger a change in state
+ Reveal.addEventListener( 'slidechanged', post );
+ Reveal.addEventListener( 'fragmentshown', post );
+ Reveal.addEventListener( 'fragmenthidden', post );
+ Reveal.addEventListener( 'overviewhidden', post );
+ Reveal.addEventListener( 'overviewshown', post );
+ Reveal.addEventListener( 'paused', post );
+ Reveal.addEventListener( 'resumed', post );
+
+ // Post the initial state
post();
- }, false );
+
+ }
+
+ connect();
}
// If the there's a 'notes' query set, open directly
--
cgit v1.2.3
From 3795ef1599cae8debe161c13a530ad565a767291 Mon Sep 17 00:00:00 2001
From: Hakim El Hattab
Date: Sun, 20 Apr 2014 10:26:00 +0200
Subject: update style of notes plugin to match Slides
---
plugin/notes/notes.html | 283 ++++++++++++++++++++++++++----------------------
1 file changed, 152 insertions(+), 131 deletions(-)
(limited to 'plugin/notes')
diff --git a/plugin/notes/notes.html b/plugin/notes/notes.html
index 3e9e8b7..15c7ae9 100644
--- a/plugin/notes/notes.html
+++ b/plugin/notes/notes.html
@@ -10,128 +10,129 @@
font-family: Helvetica;
}
- #notes {
- font-size: 24px;
- width: 640px;
- margin-top: 5px;
- clear: left;
+ #current-slide,
+ #next-slide,
+ #speaker-controls {
+ padding: 6px;
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
}
- #wrap-current-slide {
- width: 640px;
- height: 512px;
- float: left;
- overflow: hidden;
+ #current-slide iframe,
+ #next-slide iframe {
+ width: 100%;
+ height: 100%;
+ border: 1px solid #ddd;
}
- #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);
+ #current-slide .label,
+ #next-slide .label {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ font-weight: bold;
+ font-size: 14px;
+ z-index: 2;
+ color: rgba( 255, 255, 255, 0.9 );
}
- #wrap-next-slide {
- width: 448px;
- height: 358px;
- float: left;
- margin: 0 0 0 10px;
- overflow: hidden;
+ #current-slide {
+ position: absolute;
+ width: 65%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ padding-right: 0;
}
#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);
+ position: absolute;
+ width: 35%;
+ height: 40%;
+ right: 0;
+ top: 0;
}
- .slides span {
+ #speaker-controls {
position: absolute;
- top: 3px;
- left: 3px;
- font-weight: bold;
- font-size: 14px;
- z-index: 2;
- color: rgba( 255, 255, 255, 0.9 );
- }
+ top: 40%;
+ right: 0;
+ width: 35%;
+ height: 60%;
- .error {
- font-weight: bold;
- color: red;
- font-size: 1.5em;
- text-align: center;
- margin-top: 10%;
+ font-size: 18px;
}
- .error code {
- font-family: monospace;
- }
+ .speaker-controls-time.hidden,
+ .speaker-controls-notes.hidden {
+ display: none;
+ }
+
+ .speaker-controls-time .label,
+ .speaker-controls-notes .label {
+ text-transform: uppercase;
+ font-weight: normal;
+ font-size: 0.66em;
+ color: #666;
+ margin: 0;
+ }
+
+ .speaker-controls-time {
+ border-bottom: 1px solid rgba( 200, 200, 200, 0.5 );
+ margin-bottom: 10px;
+ padding: 10px 16px;
+ padding-bottom: 20px;
+ }
+
+ .speaker-controls-time .timer,
+ .speaker-controls-time .clock {
+ width: 50%;
+ font-size: 1.9em;
+ }
+
+ .speaker-controls-time .timer {
+ float: left;
+ }
- .time {
- width: 448px;
- margin: 30px 0 0 10px;
- float: left;
- text-align: center;
- opacity: 0;
-
- -webkit-transition: opacity 0.4s;
- -moz-transition: opacity 0.4s;
- -o-transition: opacity 0.4s;
- transition: opacity 0.4s;
+ .speaker-controls-time .clock {
+ float: right;
+ text-align: right;
+ }
+
+ .speaker-controls-time span.mute {
+ color: #bbb;
+ }
+
+ .speaker-controls-notes {
+ padding: 10px 16px;
+ }
+
+ .speaker-controls-notes .value {
+ margin-top: 5px;
+ line-height: 1.4;
+ font-size: 1.2em;
+ }
+
+ .clear {
+ clear: both;
}
- .elapsed,
- .clock {
- color: #333;
- font-size: 2em;
- text-align: center;
- display: inline-block;
- padding: 0.5em;
- background-color: #eee;
- border-radius: 10px;
+ @media screen and (max-width: 1080px) {
+ #speaker-controls {
+ font-size: 16px;
+ }
}
- .elapsed h2,
- .clock h2 {
- font-size: 0.8em;
- line-height: 100%;
- margin: 0;
- color: #aaa;
+ @media screen and (max-width: 900px) {
+ #speaker-controls {
+ font-size: 14px;
+ }
}
- .elapsed .mute {
- color: #ddd;
+ @media screen and (max-width: 800px) {
+ #speaker-controls {
+ font-size: 12px;
+ }
}
@@ -139,28 +140,33 @@
-
-
UPCOMING:
-
-
-
-
Time
-
0:00:00 AM
+
+
UPCOMING:
+
+
+
Time
+
+ 0:00 AM
+
+
+ 00:00:00
+
+
-
-
-
--
cgit v1.2.3
From 37ebe0732c411bee812852e80294bd36d75cd76c Mon Sep 17 00:00:00 2001
From: Hakim El Hattab
Date: Tue, 22 Apr 2014 15:05:06 +0200
Subject: skip transitions in notes window for better main window performance
---
plugin/notes/notes.html | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
(limited to 'plugin/notes')
diff --git a/plugin/notes/notes.html b/plugin/notes/notes.html
index 9e9dfb5..e488075 100644
--- a/plugin/notes/notes.html
+++ b/plugin/notes/notes.html
@@ -252,25 +252,17 @@
*/
function setupIframes( data ) {
- var currentParams = [
+ var params = [
'receiver',
'progress=false',
'history=false',
- 'postMessageEvents=true'
- ].join( '&' );
-
- var upcomingParams = [
- 'receiver',
- 'progress=false',
- 'history=false',
- 'controls=false',
'transition=none',
'backgroundTransition=none'
].join( '&' );
var hash = '#/' + data.state.indexh + '/' + data.state.indexv;
- var currentURL = data.url + '?' + currentParams + hash;
- var upcomingURL = data.url + '?' + upcomingParams + hash;
+ var currentURL = data.url + '?' + params + '&postMessageEvents=true' + hash;
+ var upcomingURL = data.url + '?' + params + '&controls=false' + hash;
currentSlide = document.createElement( 'iframe' );
currentSlide.setAttribute( 'width', 1280 );
--
cgit v1.2.3
From 1e5ca748a49b35ec698fc73d0420bb63534b9ae7 Mon Sep 17 00:00:00 2001
From: Hakim El Hattab
Date: Sat, 26 Apr 2014 11:35:55 +0200
Subject: enable reveal.js keyboard shortcuts anywhere in notes window
---
js/reveal.js | 5 +++++
plugin/notes/notes.html | 14 ++++++++++++++
2 files changed, 19 insertions(+)
(limited to 'plugin/notes')
diff --git a/js/reveal.js b/js/reveal.js
index 7a032d0..d81a19d 100644
--- a/js/reveal.js
+++ b/js/reveal.js
@@ -3702,6 +3702,11 @@ var Reveal = (function(){
if( 'addEventListener' in window ) {
( dom.wrapper || document.querySelector( '.reveal' ) ).removeEventListener( type, listener, useCapture );
}
+ },
+
+ // Programatically triggers a keyboard event
+ triggerKey: function( keyCode ) {
+ onDocumentKeyDown( { keyCode: keyCode } );
}
};
diff --git a/plugin/notes/notes.html b/plugin/notes/notes.html
index e488075..30e1669 100644
--- a/plugin/notes/notes.html
+++ b/plugin/notes/notes.html
@@ -208,6 +208,7 @@
connected = true;
setupIframes( data );
+ setupKeyboard();
setupNotes();
setupTimer();
}
@@ -247,6 +248,19 @@
// Limit to max one state update per X ms
handleStateMessage = debounce( handleStateMessage, 200 );
+ /**
+ * Forward keyboard events to the current slide window.
+ * This enables keyboard events to work even if focus
+ * isn't set on the current slide iframe.
+ */
+ function setupKeyboard() {
+
+ document.addEventListener( 'keydown', function( event ) {
+ currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'triggerKey', args: [ event.keyCode ] }), '*' );
+ } );
+
+ }
+
/**
* Creates the preview iframes.
*/
--
cgit v1.2.3
From fa6187072e70ed8c8f08df6a4a6bd4d68db8074e Mon Sep 17 00:00:00 2001
From: Hakim El Hattab
Date: Sun, 4 May 2014 08:13:03 +0200
Subject: clicking on notes timer now resets it #779
---
plugin/notes/notes.html | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
(limited to 'plugin/notes')
diff --git a/plugin/notes/notes.html b/plugin/notes/notes.html
index 30e1669..43385bf 100644
--- a/plugin/notes/notes.html
+++ b/plugin/notes/notes.html
@@ -82,6 +82,17 @@
margin-bottom: 10px;
padding: 10px 16px;
padding-bottom: 20px;
+ cursor: pointer;
+ }
+
+ .speaker-controls-time .reset-button {
+ opacity: 0;
+ float: right;
+ color: #666;
+ text-decoration: none;
+ }
+ .speaker-controls-time:hover .reset-button {
+ opacity: 1;
}
.speaker-controls-time .timer,
@@ -144,7 +155,7 @@
UPCOMING:
-
Time
+
Time Click to Reset
0:00 AM
@@ -340,6 +351,12 @@
// Then update every second
setInterval( _updateTimer, 1000 );
+ timeEl.addEventListener( 'click', function() {
+ start = new Date();
+ _updateTimer();
+ return false;
+ } );
+
}
function zeroPadInteger( num ) {
--
cgit v1.2.3