slidemgr 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +13 -0
  6. data/LICENCE +674 -0
  7. data/README.md +153 -0
  8. data/Rakefile +3 -0
  9. data/bin/setup +7 -0
  10. data/bin/slidemgr +10 -0
  11. data/config.yml +0 -0
  12. data/lib/command_router.rb +27 -0
  13. data/lib/commands/create.rb +61 -0
  14. data/lib/commands/init.rb +78 -0
  15. data/lib/commands/list.rb +12 -0
  16. data/lib/commands/refresh.rb +49 -0
  17. data/lib/commands/remove.rb +32 -0
  18. data/lib/commands/rename.rb +31 -0
  19. data/lib/commands/start.rb +36 -0
  20. data/lib/commands/sync.rb +31 -0
  21. data/lib/template/config.yml.erb +4 -0
  22. data/lib/template/content.md.erb +2 -0
  23. data/lib/template/index.erb +103 -0
  24. data/lib/template/overview_index.erb +9 -0
  25. data/lib/template/reveal.js-3.0.0/.DS_Store +0 -0
  26. data/lib/template/reveal.js-3.0.0/Gruntfile.js +174 -0
  27. data/lib/template/reveal.js-3.0.0/LICENSE +19 -0
  28. data/lib/template/reveal.js-3.0.0/css/print/paper.css +202 -0
  29. data/lib/template/reveal.js-3.0.0/css/print/pdf.css +157 -0
  30. data/lib/template/reveal.js-3.0.0/css/reveal.css +1141 -0
  31. data/lib/template/reveal.js-3.0.0/css/reveal.scss +1316 -0
  32. data/lib/template/reveal.js-3.0.0/css/theme/README.md +25 -0
  33. data/lib/template/reveal.js-3.0.0/css/theme/beige.css +265 -0
  34. data/lib/template/reveal.js-3.0.0/css/theme/black.css +261 -0
  35. data/lib/template/reveal.js-3.0.0/css/theme/blood.css +291 -0
  36. data/lib/template/reveal.js-3.0.0/css/theme/league.css +267 -0
  37. data/lib/template/reveal.js-3.0.0/css/theme/moon.css +265 -0
  38. data/lib/template/reveal.js-3.0.0/css/theme/night.css +259 -0
  39. data/lib/template/reveal.js-3.0.0/css/theme/serif.css +261 -0
  40. data/lib/template/reveal.js-3.0.0/css/theme/simple.css +261 -0
  41. data/lib/template/reveal.js-3.0.0/css/theme/sky.css +268 -0
  42. data/lib/template/reveal.js-3.0.0/css/theme/solarized.css +265 -0
  43. data/lib/template/reveal.js-3.0.0/css/theme/source/beige.scss +39 -0
  44. data/lib/template/reveal.js-3.0.0/css/theme/source/black.scss +49 -0
  45. data/lib/template/reveal.js-3.0.0/css/theme/source/blood.scss +91 -0
  46. data/lib/template/reveal.js-3.0.0/css/theme/source/league.scss +34 -0
  47. data/lib/template/reveal.js-3.0.0/css/theme/source/moon.scss +57 -0
  48. data/lib/template/reveal.js-3.0.0/css/theme/source/night.scss +35 -0
  49. data/lib/template/reveal.js-3.0.0/css/theme/source/serif.scss +35 -0
  50. data/lib/template/reveal.js-3.0.0/css/theme/source/simple.scss +38 -0
  51. data/lib/template/reveal.js-3.0.0/css/theme/source/sky.scss +46 -0
  52. data/lib/template/reveal.js-3.0.0/css/theme/source/solarized.scss +63 -0
  53. data/lib/template/reveal.js-3.0.0/css/theme/source/white.scss +49 -0
  54. data/lib/template/reveal.js-3.0.0/css/theme/template/mixins.scss +29 -0
  55. data/lib/template/reveal.js-3.0.0/css/theme/template/settings.scss +43 -0
  56. data/lib/template/reveal.js-3.0.0/css/theme/template/theme.scss +339 -0
  57. data/lib/template/reveal.js-3.0.0/css/theme/white.css +261 -0
  58. data/lib/template/reveal.js-3.0.0/js/reveal.js +4276 -0
  59. data/lib/template/reveal.js-3.0.0/lib/css/zenburn.css +117 -0
  60. data/lib/template/reveal.js-3.0.0/lib/font/league-gothic/LICENSE +2 -0
  61. data/lib/template/reveal.js-3.0.0/lib/font/league-gothic/league-gothic.css +10 -0
  62. data/lib/template/reveal.js-3.0.0/lib/font/league-gothic/league-gothic.eot +0 -0
  63. data/lib/template/reveal.js-3.0.0/lib/font/league-gothic/league-gothic.ttf +0 -0
  64. data/lib/template/reveal.js-3.0.0/lib/font/league-gothic/league-gothic.woff +0 -0
  65. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/LICENSE +45 -0
  66. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-italic.eot +0 -0
  67. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-italic.ttf +0 -0
  68. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-italic.woff +0 -0
  69. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-regular.eot +0 -0
  70. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-regular.ttf +0 -0
  71. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-regular.woff +0 -0
  72. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-semibold.eot +0 -0
  73. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-semibold.ttf +0 -0
  74. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-semibold.woff +0 -0
  75. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-semibolditalic.eot +0 -0
  76. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-semibolditalic.ttf +0 -0
  77. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro-semibolditalic.woff +0 -0
  78. data/lib/template/reveal.js-3.0.0/lib/font/source-sans-pro/source-sans-pro.css +39 -0
  79. data/lib/template/reveal.js-3.0.0/lib/js/classList.js +2 -0
  80. data/lib/template/reveal.js-3.0.0/lib/js/head.min.js +8 -0
  81. data/lib/template/reveal.js-3.0.0/lib/js/html5shiv.js +7 -0
  82. data/lib/template/reveal.js-3.0.0/plugin/highlight/highlight.js +30 -0
  83. data/lib/template/reveal.js-3.0.0/plugin/leap/leap.js +159 -0
  84. data/lib/template/reveal.js-3.0.0/plugin/markdown/example.html +129 -0
  85. data/lib/template/reveal.js-3.0.0/plugin/markdown/example.md +31 -0
  86. data/lib/template/reveal.js-3.0.0/plugin/markdown/markdown.js +393 -0
  87. data/lib/template/reveal.js-3.0.0/plugin/markdown/marked.js +37 -0
  88. data/lib/template/reveal.js-3.0.0/plugin/math/math.js +64 -0
  89. data/lib/template/reveal.js-3.0.0/plugin/multiplex/client.js +13 -0
  90. data/lib/template/reveal.js-3.0.0/plugin/multiplex/index.js +56 -0
  91. data/lib/template/reveal.js-3.0.0/plugin/multiplex/master.js +51 -0
  92. data/lib/template/reveal.js-3.0.0/plugin/notes/notes.html +406 -0
  93. data/lib/template/reveal.js-3.0.0/plugin/notes/notes.js +122 -0
  94. data/lib/template/reveal.js-3.0.0/plugin/notes-server/client.js +60 -0
  95. data/lib/template/reveal.js-3.0.0/plugin/notes-server/index.js +66 -0
  96. data/lib/template/reveal.js-3.0.0/plugin/notes-server/notes.html +396 -0
  97. data/lib/template/reveal.js-3.0.0/plugin/print-pdf/print-pdf.js +48 -0
  98. data/lib/template/reveal.js-3.0.0/plugin/remotes/remotes.js +39 -0
  99. data/lib/template/reveal.js-3.0.0/plugin/search/search.js +196 -0
  100. data/lib/template/reveal.js-3.0.0/plugin/zoom-js/zoom.js +278 -0
  101. data/lib/template/reveal.js-3.0.0/test/examples/assets/image1.png +0 -0
  102. data/lib/template/reveal.js-3.0.0/test/examples/assets/image2.png +0 -0
  103. data/lib/template/reveal.js-3.0.0/test/examples/barebones.html +41 -0
  104. data/lib/template/reveal.js-3.0.0/test/examples/embedded-media.html +49 -0
  105. data/lib/template/reveal.js-3.0.0/test/examples/math.html +185 -0
  106. data/lib/template/reveal.js-3.0.0/test/examples/slide-backgrounds.html +144 -0
  107. data/lib/template/reveal.js-3.0.0/test/qunit-1.12.0.css +244 -0
  108. data/lib/template/reveal.js-3.0.0/test/qunit-1.12.0.js +2212 -0
  109. data/lib/template/reveal.js-3.0.0/test/test-markdown-element-attributes.html +134 -0
  110. data/lib/template/reveal.js-3.0.0/test/test-markdown-element-attributes.js +46 -0
  111. data/lib/template/reveal.js-3.0.0/test/test-markdown-slide-attributes.html +128 -0
  112. data/lib/template/reveal.js-3.0.0/test/test-markdown-slide-attributes.js +47 -0
  113. data/lib/template/reveal.js-3.0.0/test/test-markdown.html +52 -0
  114. data/lib/template/reveal.js-3.0.0/test/test-markdown.js +15 -0
  115. data/lib/template/reveal.js-3.0.0/test/test-pdf.html +83 -0
  116. data/lib/template/reveal.js-3.0.0/test/test-pdf.js +15 -0
  117. data/lib/template/reveal.js-3.0.0/test/test.html +82 -0
  118. data/lib/template/reveal.js-3.0.0/test/test.js +572 -0
  119. data/lib/util.rb +99 -0
  120. data/lib/version.rb +3 -0
  121. data/slidemgr.gemspec +24 -0
  122. metadata +193 -0
@@ -0,0 +1,406 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+
6
+ <title>reveal.js - Slide Notes</title>
7
+
8
+ <style>
9
+ body {
10
+ font-family: Helvetica;
11
+ }
12
+
13
+ #current-slide,
14
+ #upcoming-slide,
15
+ #speaker-controls {
16
+ padding: 6px;
17
+ box-sizing: border-box;
18
+ -moz-box-sizing: border-box;
19
+ }
20
+
21
+ #current-slide iframe,
22
+ #upcoming-slide iframe {
23
+ width: 100%;
24
+ height: 100%;
25
+ border: 1px solid #ddd;
26
+ }
27
+
28
+ #current-slide .label,
29
+ #upcoming-slide .label {
30
+ position: absolute;
31
+ top: 10px;
32
+ left: 10px;
33
+ font-weight: bold;
34
+ font-size: 14px;
35
+ z-index: 2;
36
+ color: rgba( 255, 255, 255, 0.9 );
37
+ }
38
+
39
+ #current-slide {
40
+ position: absolute;
41
+ width: 65%;
42
+ height: 100%;
43
+ top: 0;
44
+ left: 0;
45
+ padding-right: 0;
46
+ }
47
+
48
+ #upcoming-slide {
49
+ position: absolute;
50
+ width: 35%;
51
+ height: 40%;
52
+ right: 0;
53
+ top: 0;
54
+ }
55
+
56
+ #speaker-controls {
57
+ position: absolute;
58
+ top: 40%;
59
+ right: 0;
60
+ width: 35%;
61
+ height: 60%;
62
+ overflow: auto;
63
+
64
+ font-size: 18px;
65
+ }
66
+
67
+ .speaker-controls-time.hidden,
68
+ .speaker-controls-notes.hidden {
69
+ display: none;
70
+ }
71
+
72
+ .speaker-controls-time .label,
73
+ .speaker-controls-notes .label {
74
+ text-transform: uppercase;
75
+ font-weight: normal;
76
+ font-size: 0.66em;
77
+ color: #666;
78
+ margin: 0;
79
+ }
80
+
81
+ .speaker-controls-time {
82
+ border-bottom: 1px solid rgba( 200, 200, 200, 0.5 );
83
+ margin-bottom: 10px;
84
+ padding: 10px 16px;
85
+ padding-bottom: 20px;
86
+ cursor: pointer;
87
+ }
88
+
89
+ .speaker-controls-time .reset-button {
90
+ opacity: 0;
91
+ float: right;
92
+ color: #666;
93
+ text-decoration: none;
94
+ }
95
+ .speaker-controls-time:hover .reset-button {
96
+ opacity: 1;
97
+ }
98
+
99
+ .speaker-controls-time .timer,
100
+ .speaker-controls-time .clock {
101
+ width: 50%;
102
+ font-size: 1.9em;
103
+ }
104
+
105
+ .speaker-controls-time .timer {
106
+ float: left;
107
+ }
108
+
109
+ .speaker-controls-time .clock {
110
+ float: right;
111
+ text-align: right;
112
+ }
113
+
114
+ .speaker-controls-time span.mute {
115
+ color: #bbb;
116
+ }
117
+
118
+ .speaker-controls-notes {
119
+ padding: 10px 16px;
120
+ }
121
+
122
+ .speaker-controls-notes .value {
123
+ margin-top: 5px;
124
+ line-height: 1.4;
125
+ font-size: 1.2em;
126
+ }
127
+
128
+ .clear {
129
+ clear: both;
130
+ }
131
+
132
+ @media screen and (max-width: 1080px) {
133
+ #speaker-controls {
134
+ font-size: 16px;
135
+ }
136
+ }
137
+
138
+ @media screen and (max-width: 900px) {
139
+ #speaker-controls {
140
+ font-size: 14px;
141
+ }
142
+ }
143
+
144
+ @media screen and (max-width: 800px) {
145
+ #speaker-controls {
146
+ font-size: 12px;
147
+ }
148
+ }
149
+
150
+ </style>
151
+ </head>
152
+
153
+ <body>
154
+
155
+ <div id="current-slide"></div>
156
+ <div id="upcoming-slide"><span class="label">UPCOMING:</span></div>
157
+ <div id="speaker-controls">
158
+ <div class="speaker-controls-time">
159
+ <h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
160
+ <div class="clock">
161
+ <span class="clock-value">0:00 AM</span>
162
+ </div>
163
+ <div class="timer">
164
+ <span class="hours-value">00</span><span class="minutes-value">:00</span><span class="seconds-value">:00</span>
165
+ </div>
166
+ <div class="clear"></div>
167
+ </div>
168
+
169
+ <div class="speaker-controls-notes hidden">
170
+ <h4 class="label">Notes</h4>
171
+ <div class="value"></div>
172
+ </div>
173
+ </div>
174
+
175
+ <script src="../../plugin/markdown/marked.js"></script>
176
+ <script>
177
+
178
+ (function() {
179
+
180
+ var notes,
181
+ notesValue,
182
+ currentState,
183
+ currentSlide,
184
+ upcomingSlide,
185
+ connected = false;
186
+
187
+ window.addEventListener( 'message', function( event ) {
188
+
189
+ var data = JSON.parse( event.data );
190
+
191
+ // Messages sent by the notes plugin inside of the main window
192
+ if( data && data.namespace === 'reveal-notes' ) {
193
+ if( data.type === 'connect' ) {
194
+ handleConnectMessage( data );
195
+ }
196
+ else if( data.type === 'state' ) {
197
+ handleStateMessage( data );
198
+ }
199
+ }
200
+ // Messages sent by the reveal.js inside of the current slide preview
201
+ else if( data && data.namespace === 'reveal' ) {
202
+ if( /ready/.test( data.eventName ) ) {
203
+ // Send a message back to notify that the handshake is complete
204
+ window.opener.postMessage( JSON.stringify({ namespace: 'reveal-notes', type: 'connected'} ), '*' );
205
+ }
206
+ else if( /slidechanged|fragmentshown|fragmenthidden|overviewshown|overviewhidden|paused|resumed/.test( data.eventName ) && currentState !== JSON.stringify( data.state ) ) {
207
+ window.opener.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ]} ), '*' );
208
+ }
209
+ }
210
+
211
+ } );
212
+
213
+ /**
214
+ * Called when the main window is trying to establish a
215
+ * connection.
216
+ */
217
+ function handleConnectMessage( data ) {
218
+
219
+ if( connected === false ) {
220
+ connected = true;
221
+
222
+ setupIframes( data );
223
+ setupKeyboard();
224
+ setupNotes();
225
+ setupTimer();
226
+ }
227
+
228
+ }
229
+
230
+ /**
231
+ * Called when the main window sends an updated state.
232
+ */
233
+ function handleStateMessage( data ) {
234
+
235
+ // Store the most recently set state to avoid circular loops
236
+ // applying the same state
237
+ currentState = JSON.stringify( data.state );
238
+
239
+ // No need for updating the notes in case of fragment changes
240
+ if ( data.notes ) {
241
+ notes.classList.remove( 'hidden' );
242
+ if( data.markdown ) {
243
+ notesValue.innerHTML = marked( data.notes );
244
+ }
245
+ else {
246
+ notesValue.innerHTML = data.notes;
247
+ }
248
+ }
249
+ else {
250
+ notes.classList.add( 'hidden' );
251
+ }
252
+
253
+ // Update the note slides
254
+ currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
255
+ upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
256
+ upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'next' }), '*' );
257
+
258
+ }
259
+
260
+ // Limit to max one state update per X ms
261
+ handleStateMessage = debounce( handleStateMessage, 200 );
262
+
263
+ /**
264
+ * Forward keyboard events to the current slide window.
265
+ * This enables keyboard events to work even if focus
266
+ * isn't set on the current slide iframe.
267
+ */
268
+ function setupKeyboard() {
269
+
270
+ document.addEventListener( 'keydown', function( event ) {
271
+ currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'triggerKey', args: [ event.keyCode ] }), '*' );
272
+ } );
273
+
274
+ }
275
+
276
+ /**
277
+ * Creates the preview iframes.
278
+ */
279
+ function setupIframes( data ) {
280
+
281
+ var params = [
282
+ 'receiver',
283
+ 'progress=false',
284
+ 'history=false',
285
+ 'transition=none',
286
+ 'autoSlide=0',
287
+ 'backgroundTransition=none'
288
+ ].join( '&' );
289
+
290
+ var hash = '#/' + data.state.indexh + '/' + data.state.indexv;
291
+ var currentURL = data.url + '?' + params + '&postMessageEvents=true' + hash;
292
+ var upcomingURL = data.url + '?' + params + '&controls=false' + hash;
293
+
294
+ currentSlide = document.createElement( 'iframe' );
295
+ currentSlide.setAttribute( 'width', 1280 );
296
+ currentSlide.setAttribute( 'height', 1024 );
297
+ currentSlide.setAttribute( 'src', currentURL );
298
+ document.querySelector( '#current-slide' ).appendChild( currentSlide );
299
+
300
+ upcomingSlide = document.createElement( 'iframe' );
301
+ upcomingSlide.setAttribute( 'width', 640 );
302
+ upcomingSlide.setAttribute( 'height', 512 );
303
+ upcomingSlide.setAttribute( 'src', upcomingURL );
304
+ document.querySelector( '#upcoming-slide' ).appendChild( upcomingSlide );
305
+
306
+ }
307
+
308
+ /**
309
+ * Setup the notes UI.
310
+ */
311
+ function setupNotes() {
312
+
313
+ notes = document.querySelector( '.speaker-controls-notes' );
314
+ notesValue = document.querySelector( '.speaker-controls-notes .value' );
315
+
316
+ }
317
+
318
+ /**
319
+ * Create the timer and clock and start updating them
320
+ * at an interval.
321
+ */
322
+ function setupTimer() {
323
+
324
+ var start = new Date(),
325
+ timeEl = document.querySelector( '.speaker-controls-time' ),
326
+ clockEl = timeEl.querySelector( '.clock-value' ),
327
+ hoursEl = timeEl.querySelector( '.hours-value' ),
328
+ minutesEl = timeEl.querySelector( '.minutes-value' ),
329
+ secondsEl = timeEl.querySelector( '.seconds-value' );
330
+
331
+ function _updateTimer() {
332
+
333
+ var diff, hours, minutes, seconds,
334
+ now = new Date();
335
+
336
+ diff = now.getTime() - start.getTime();
337
+ hours = Math.floor( diff / ( 1000 * 60 * 60 ) );
338
+ minutes = Math.floor( ( diff / ( 1000 * 60 ) ) % 60 );
339
+ seconds = Math.floor( ( diff / 1000 ) % 60 );
340
+
341
+ clockEl.innerHTML = now.toLocaleTimeString( 'en-US', { hour12: true, hour: '2-digit', minute:'2-digit' } );
342
+ hoursEl.innerHTML = zeroPadInteger( hours );
343
+ hoursEl.className = hours > 0 ? '' : 'mute';
344
+ minutesEl.innerHTML = ':' + zeroPadInteger( minutes );
345
+ minutesEl.className = minutes > 0 ? '' : 'mute';
346
+ secondsEl.innerHTML = ':' + zeroPadInteger( seconds );
347
+
348
+ }
349
+
350
+ // Update once directly
351
+ _updateTimer();
352
+
353
+ // Then update every second
354
+ setInterval( _updateTimer, 1000 );
355
+
356
+ timeEl.addEventListener( 'click', function() {
357
+ start = new Date();
358
+ _updateTimer();
359
+ return false;
360
+ } );
361
+
362
+ }
363
+
364
+ function zeroPadInteger( num ) {
365
+
366
+ var str = '00' + parseInt( num );
367
+ return str.substring( str.length - 2 );
368
+
369
+ }
370
+
371
+ /**
372
+ * Limits the frequency at which a function can be called.
373
+ */
374
+ function debounce( fn, ms ) {
375
+
376
+ var lastTime = 0,
377
+ timeout;
378
+
379
+ return function() {
380
+
381
+ var args = arguments;
382
+ var context = this;
383
+
384
+ clearTimeout( timeout );
385
+
386
+ var timeSinceLastCall = Date.now() - lastTime;
387
+ if( timeSinceLastCall > ms ) {
388
+ fn.apply( context, args );
389
+ lastTime = Date.now();
390
+ }
391
+ else {
392
+ timeout = setTimeout( function() {
393
+ fn.apply( context, args );
394
+ lastTime = Date.now();
395
+ }, ms - timeSinceLastCall );
396
+ }
397
+
398
+ }
399
+
400
+ }
401
+
402
+ })();
403
+
404
+ </script>
405
+ </body>
406
+ </html>
@@ -0,0 +1,122 @@
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
+ function openNotes() {
15
+ var jsFileLocation = document.querySelector('script[src$="notes.js"]').src; // this js file path
16
+ jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path
17
+ var notesPopup = window.open( jsFileLocation + 'notes.html', 'reveal.js - Notes', 'width=1100,height=700' );
18
+
19
+ /**
20
+ * Connect to the notes window through a postmessage handshake.
21
+ * Using postmessage enables us to work in situations where the
22
+ * origins differ, such as a presentation being opened from the
23
+ * file system.
24
+ */
25
+ function connect() {
26
+ // Keep trying to connect until we get a 'connected' message back
27
+ var connectInterval = setInterval( function() {
28
+ notesPopup.postMessage( JSON.stringify( {
29
+ namespace: 'reveal-notes',
30
+ type: 'connect',
31
+ url: window.location.protocol + '//' + window.location.host + window.location.pathname,
32
+ state: Reveal.getState()
33
+ } ), '*' );
34
+ }, 500 );
35
+
36
+ window.addEventListener( 'message', function( event ) {
37
+ var data = JSON.parse( event.data );
38
+ if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) {
39
+ clearInterval( connectInterval );
40
+ onConnected();
41
+ }
42
+ } );
43
+ }
44
+
45
+ /**
46
+ * Posts the current slide data to the notes window
47
+ */
48
+ function post() {
49
+
50
+ var slideElement = Reveal.getCurrentSlide(),
51
+ notesElement = slideElement.querySelector( 'aside.notes' );
52
+
53
+ var messageData = {
54
+ namespace: 'reveal-notes',
55
+ type: 'state',
56
+ notes: '',
57
+ markdown: false,
58
+ state: Reveal.getState()
59
+ };
60
+
61
+ // Look for notes defined in a slide attribute
62
+ if( slideElement.hasAttribute( 'data-notes' ) ) {
63
+ messageData.notes = slideElement.getAttribute( 'data-notes' );
64
+ }
65
+
66
+ // Look for notes defined in an aside element
67
+ if( notesElement ) {
68
+ messageData.notes = notesElement.innerHTML;
69
+ messageData.markdown = typeof notesElement.getAttribute( 'data-markdown' ) === 'string';
70
+ }
71
+
72
+ notesPopup.postMessage( JSON.stringify( messageData ), '*' );
73
+
74
+ }
75
+
76
+ /**
77
+ * Called once we have established a connection to the notes
78
+ * window.
79
+ */
80
+ function onConnected() {
81
+
82
+ // Monitor events that trigger a change in state
83
+ Reveal.addEventListener( 'slidechanged', post );
84
+ Reveal.addEventListener( 'fragmentshown', post );
85
+ Reveal.addEventListener( 'fragmenthidden', post );
86
+ Reveal.addEventListener( 'overviewhidden', post );
87
+ Reveal.addEventListener( 'overviewshown', post );
88
+ Reveal.addEventListener( 'paused', post );
89
+ Reveal.addEventListener( 'resumed', post );
90
+
91
+ // Post the initial state
92
+ post();
93
+
94
+ }
95
+
96
+ connect();
97
+ }
98
+
99
+ if( !/receiver/i.test( window.location.search ) ) {
100
+
101
+ // If the there's a 'notes' query set, open directly
102
+ if( window.location.search.match( /(\?|\&)notes/gi ) !== null ) {
103
+ openNotes();
104
+ }
105
+
106
+ // Open the notes when the 's' key is hit
107
+ document.addEventListener( 'keydown', function( event ) {
108
+ // Disregard the event if the target is editable or a
109
+ // modifier is present
110
+ if ( document.querySelector( ':focus' ) !== null || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return;
111
+
112
+ if( event.keyCode === 83 ) {
113
+ event.preventDefault();
114
+ openNotes();
115
+ }
116
+ }, false );
117
+
118
+ }
119
+
120
+ return { open: openNotes };
121
+
122
+ })();
@@ -0,0 +1,60 @@
1
+ (function() {
2
+
3
+ // don't emit events from inside the previews themselves
4
+ if( window.location.search.match( /receiver/gi ) ) { return; }
5
+
6
+ var socket = io.connect( window.location.origin ),
7
+ socketId = Math.random().toString().slice( 2 );
8
+
9
+ console.log( 'View slide notes at ' + window.location.origin + '/notes/' + socketId );
10
+
11
+ window.open( window.location.origin + '/notes/' + socketId, 'notes-' + socketId );
12
+
13
+ /**
14
+ * Posts the current slide data to the notes window
15
+ */
16
+ function post() {
17
+
18
+ var slideElement = Reveal.getCurrentSlide(),
19
+ notesElement = slideElement.querySelector( 'aside.notes' );
20
+
21
+ var messageData = {
22
+ notes: '',
23
+ markdown: false,
24
+ socketId: socketId,
25
+ state: Reveal.getState()
26
+ };
27
+
28
+ // Look for notes defined in a slide attribute
29
+ if( slideElement.hasAttribute( 'data-notes' ) ) {
30
+ messageData.notes = slideElement.getAttribute( 'data-notes' );
31
+ }
32
+
33
+ // Look for notes defined in an aside element
34
+ if( notesElement ) {
35
+ messageData.notes = notesElement.innerHTML;
36
+ messageData.markdown = typeof notesElement.getAttribute( 'data-markdown' ) === 'string';
37
+ }
38
+
39
+ socket.emit( 'statechanged', messageData );
40
+
41
+ }
42
+
43
+ // When a new notes window connects, post our current state
44
+ socket.on( 'connect', function( data ) {
45
+ post();
46
+ } );
47
+
48
+ // Monitor events that trigger a change in state
49
+ Reveal.addEventListener( 'slidechanged', post );
50
+ Reveal.addEventListener( 'fragmentshown', post );
51
+ Reveal.addEventListener( 'fragmenthidden', post );
52
+ Reveal.addEventListener( 'overviewhidden', post );
53
+ Reveal.addEventListener( 'overviewshown', post );
54
+ Reveal.addEventListener( 'paused', post );
55
+ Reveal.addEventListener( 'resumed', post );
56
+
57
+ // Post the initial state
58
+ post();
59
+
60
+ }());
@@ -0,0 +1,66 @@
1
+ var express = require('express');
2
+ var fs = require('fs');
3
+ var io = require('socket.io');
4
+ var _ = require('underscore');
5
+ var Mustache = require('mustache');
6
+
7
+ var app = express.createServer();
8
+ var staticDir = express.static;
9
+
10
+ io = io.listen(app);
11
+
12
+ var opts = {
13
+ port : 1947,
14
+ baseDir : __dirname + '/../../'
15
+ };
16
+
17
+ io.sockets.on( 'connection', function( socket ) {
18
+
19
+ socket.on( 'connect', function( data ) {
20
+ socket.broadcast.emit( 'connect', data );
21
+ });
22
+
23
+ socket.on( 'statechanged', function( data ) {
24
+ socket.broadcast.emit( 'statechanged', data );
25
+ });
26
+
27
+ });
28
+
29
+ app.configure( function() {
30
+
31
+ [ 'css', 'js', 'images', 'plugin', 'lib' ].forEach( function( dir ) {
32
+ app.use( '/' + dir, staticDir( opts.baseDir + dir ) );
33
+ });
34
+
35
+ });
36
+
37
+ app.get('/', function( req, res ) {
38
+
39
+ res.writeHead( 200, { 'Content-Type': 'text/html' } );
40
+ fs.createReadStream( opts.baseDir + '/index.html' ).pipe( res );
41
+
42
+ });
43
+
44
+ app.get( '/notes/:socketId', function( req, res ) {
45
+
46
+ fs.readFile( opts.baseDir + 'plugin/notes-server/notes.html', function( err, data ) {
47
+ res.send( Mustache.to_html( data.toString(), {
48
+ socketId : req.params.socketId
49
+ }));
50
+ });
51
+
52
+ });
53
+
54
+ // Actually listen
55
+ app.listen( opts.port || null );
56
+
57
+ var brown = '\033[33m',
58
+ green = '\033[32m',
59
+ reset = '\033[0m';
60
+
61
+ var slidesLocation = 'http://localhost' + ( opts.port ? ( ':' + opts.port ) : '' );
62
+
63
+ console.log( brown + 'reveal.js - Speaker Notes' + reset );
64
+ console.log( '1. Open the slides at ' + green + slidesLocation + reset );
65
+ console.log( '2. Click on the link your JS console to go to the notes page' );
66
+ console.log( '3. Advance through your slides and your notes will advance automatically' );