reveal.rb 0.4.0 → 0.5.0
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.
- checksums.yaml +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +2 -1
- data/Dockerfile +4 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +7 -1
- data/README.md +1 -1
- data/lib/reveal/command.rb +9 -3
- data/lib/reveal/templates/revealjs/css/print/paper.css +4 -3
- data/lib/reveal/templates/revealjs/css/print/pdf.css +59 -38
- data/lib/reveal/templates/revealjs/css/reveal.css +654 -274
- data/lib/reveal/templates/revealjs/css/theme/beige.css +65 -68
- data/lib/reveal/templates/revealjs/css/theme/black.css +58 -61
- data/lib/reveal/templates/revealjs/css/theme/blood.css +64 -62
- data/lib/reveal/templates/revealjs/css/theme/league.css +59 -62
- data/lib/reveal/templates/revealjs/css/theme/moon.css +59 -62
- data/lib/reveal/templates/revealjs/css/theme/night.css +58 -61
- data/lib/reveal/templates/revealjs/css/theme/serif.css +56 -59
- data/lib/reveal/templates/revealjs/css/theme/simple.css +60 -60
- data/lib/reveal/templates/revealjs/css/theme/sky.css +59 -62
- data/lib/reveal/templates/revealjs/css/theme/solarized.css +59 -62
- data/lib/reveal/templates/revealjs/css/theme/white.css +59 -62
- data/lib/reveal/templates/revealjs/index.html +14 -376
- data/lib/reveal/templates/revealjs/js/reveal.js +1073 -342
- data/lib/reveal/templates/revealjs/lib/css/zenburn.css +41 -78
- data/lib/reveal/templates/revealjs/lib/js/head.min.js +9 -8
- data/lib/reveal/templates/revealjs/plugin/highlight/highlight.js +51 -4
- data/lib/reveal/templates/revealjs/plugin/markdown/markdown.js +38 -19
- data/lib/reveal/templates/revealjs/plugin/markdown/marked.js +1 -1
- data/lib/reveal/templates/revealjs/plugin/math/math.js +5 -2
- data/lib/reveal/templates/revealjs/plugin/multiplex/client.js +1 -1
- data/lib/reveal/templates/revealjs/plugin/multiplex/index.js +24 -16
- data/lib/reveal/templates/revealjs/plugin/multiplex/master.js +26 -43
- data/lib/reveal/templates/revealjs/plugin/multiplex/package.json +19 -0
- data/lib/reveal/templates/revealjs/plugin/notes/notes.html +385 -32
- data/lib/reveal/templates/revealjs/plugin/notes/notes.js +39 -6
- data/lib/reveal/templates/revealjs/plugin/notes-server/client.js +6 -1
- data/lib/reveal/templates/revealjs/plugin/notes-server/index.js +17 -14
- data/lib/reveal/templates/revealjs/plugin/notes-server/notes.html +215 -26
- data/lib/reveal/templates/revealjs/plugin/print-pdf/print-pdf.js +48 -27
- data/lib/reveal/templates/revealjs/plugin/search/search.js +41 -31
- data/lib/reveal/templates/revealjs/plugin/zoom-js/zoom.js +17 -23
- data/lib/reveal/templates/template.html +12 -41
- data/lib/reveal/version.rb +1 -1
- data/spec/lib/reveal/command_spec.rb +37 -0
- metadata +14 -16
- data/lib/reveal/templates/revealjs/lib/font/league-gothic/LICENSE +0 -2
- data/lib/reveal/templates/revealjs/lib/font/source-sans-pro/LICENSE +0 -45
- data/lib/reveal/templates/revealjs/plugin/leap/leap.js +0 -159
- data/lib/reveal/templates/revealjs/plugin/remotes/remotes.js +0 -39
@@ -8,6 +8,7 @@
|
|
8
8
|
<style>
|
9
9
|
body {
|
10
10
|
font-family: Helvetica;
|
11
|
+
font-size: 18px;
|
11
12
|
}
|
12
13
|
|
13
14
|
#current-slide,
|
@@ -30,15 +31,26 @@
|
|
30
31
|
position: absolute;
|
31
32
|
top: 10px;
|
32
33
|
left: 10px;
|
33
|
-
font-weight: bold;
|
34
|
-
font-size: 14px;
|
35
34
|
z-index: 2;
|
36
|
-
|
35
|
+
}
|
36
|
+
|
37
|
+
.overlay-element {
|
38
|
+
height: 34px;
|
39
|
+
line-height: 34px;
|
40
|
+
padding: 0 10px;
|
41
|
+
text-shadow: none;
|
42
|
+
background: rgba( 220, 220, 220, 0.8 );
|
43
|
+
color: #222;
|
44
|
+
font-size: 14px;
|
45
|
+
}
|
46
|
+
|
47
|
+
.overlay-element.interactive:hover {
|
48
|
+
background: rgba( 220, 220, 220, 1 );
|
37
49
|
}
|
38
50
|
|
39
51
|
#current-slide {
|
40
52
|
position: absolute;
|
41
|
-
width:
|
53
|
+
width: 60%;
|
42
54
|
height: 100%;
|
43
55
|
top: 0;
|
44
56
|
left: 0;
|
@@ -47,20 +59,20 @@
|
|
47
59
|
|
48
60
|
#upcoming-slide {
|
49
61
|
position: absolute;
|
50
|
-
width:
|
62
|
+
width: 40%;
|
51
63
|
height: 40%;
|
52
64
|
right: 0;
|
53
65
|
top: 0;
|
54
66
|
}
|
55
67
|
|
68
|
+
/* Speaker controls */
|
56
69
|
#speaker-controls {
|
57
70
|
position: absolute;
|
58
71
|
top: 40%;
|
59
72
|
right: 0;
|
60
|
-
width:
|
73
|
+
width: 40%;
|
61
74
|
height: 60%;
|
62
75
|
overflow: auto;
|
63
|
-
|
64
76
|
font-size: 18px;
|
65
77
|
}
|
66
78
|
|
@@ -70,6 +82,7 @@
|
|
70
82
|
}
|
71
83
|
|
72
84
|
.speaker-controls-time .label,
|
85
|
+
.speaker-controls-pace .label,
|
73
86
|
.speaker-controls-notes .label {
|
74
87
|
text-transform: uppercase;
|
75
88
|
font-weight: normal;
|
@@ -78,7 +91,7 @@
|
|
78
91
|
margin: 0;
|
79
92
|
}
|
80
93
|
|
81
|
-
.speaker-controls-time {
|
94
|
+
.speaker-controls-time, .speaker-controls-pace {
|
82
95
|
border-bottom: 1px solid rgba( 200, 200, 200, 0.5 );
|
83
96
|
margin-bottom: 10px;
|
84
97
|
padding: 10px 16px;
|
@@ -99,6 +112,13 @@
|
|
99
112
|
.speaker-controls-time .timer,
|
100
113
|
.speaker-controls-time .clock {
|
101
114
|
width: 50%;
|
115
|
+
}
|
116
|
+
|
117
|
+
.speaker-controls-time .timer,
|
118
|
+
.speaker-controls-time .clock,
|
119
|
+
.speaker-controls-time .pacing .hours-value,
|
120
|
+
.speaker-controls-time .pacing .minutes-value,
|
121
|
+
.speaker-controls-time .pacing .seconds-value {
|
102
122
|
font-size: 1.9em;
|
103
123
|
}
|
104
124
|
|
@@ -112,7 +132,23 @@
|
|
112
132
|
}
|
113
133
|
|
114
134
|
.speaker-controls-time span.mute {
|
115
|
-
|
135
|
+
opacity: 0.3;
|
136
|
+
}
|
137
|
+
|
138
|
+
.speaker-controls-time .pacing-title {
|
139
|
+
margin-top: 5px;
|
140
|
+
}
|
141
|
+
|
142
|
+
.speaker-controls-time .pacing.ahead {
|
143
|
+
color: blue;
|
144
|
+
}
|
145
|
+
|
146
|
+
.speaker-controls-time .pacing.on-track {
|
147
|
+
color: green;
|
148
|
+
}
|
149
|
+
|
150
|
+
.speaker-controls-time .pacing.behind {
|
151
|
+
color: red;
|
116
152
|
}
|
117
153
|
|
118
154
|
.speaker-controls-notes {
|
@@ -125,24 +161,124 @@
|
|
125
161
|
font-size: 1.2em;
|
126
162
|
}
|
127
163
|
|
164
|
+
/* Layout selector */
|
165
|
+
#speaker-layout {
|
166
|
+
position: absolute;
|
167
|
+
top: 10px;
|
168
|
+
right: 10px;
|
169
|
+
color: #222;
|
170
|
+
z-index: 10;
|
171
|
+
}
|
172
|
+
#speaker-layout select {
|
173
|
+
position: absolute;
|
174
|
+
width: 100%;
|
175
|
+
height: 100%;
|
176
|
+
top: 0;
|
177
|
+
left: 0;
|
178
|
+
border: 0;
|
179
|
+
box-shadow: 0;
|
180
|
+
cursor: pointer;
|
181
|
+
opacity: 0;
|
182
|
+
|
183
|
+
font-size: 1em;
|
184
|
+
background-color: transparent;
|
185
|
+
|
186
|
+
-moz-appearance: none;
|
187
|
+
-webkit-appearance: none;
|
188
|
+
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
189
|
+
}
|
190
|
+
|
191
|
+
#speaker-layout select:focus {
|
192
|
+
outline: none;
|
193
|
+
box-shadow: none;
|
194
|
+
}
|
195
|
+
|
128
196
|
.clear {
|
129
197
|
clear: both;
|
130
198
|
}
|
131
199
|
|
200
|
+
/* Speaker layout: Wide */
|
201
|
+
body[data-speaker-layout="wide"] #current-slide,
|
202
|
+
body[data-speaker-layout="wide"] #upcoming-slide {
|
203
|
+
width: 50%;
|
204
|
+
height: 45%;
|
205
|
+
padding: 6px;
|
206
|
+
}
|
207
|
+
|
208
|
+
body[data-speaker-layout="wide"] #current-slide {
|
209
|
+
top: 0;
|
210
|
+
left: 0;
|
211
|
+
}
|
212
|
+
|
213
|
+
body[data-speaker-layout="wide"] #upcoming-slide {
|
214
|
+
top: 0;
|
215
|
+
left: 50%;
|
216
|
+
}
|
217
|
+
|
218
|
+
body[data-speaker-layout="wide"] #speaker-controls {
|
219
|
+
top: 45%;
|
220
|
+
left: 0;
|
221
|
+
width: 100%;
|
222
|
+
height: 50%;
|
223
|
+
font-size: 1.25em;
|
224
|
+
}
|
225
|
+
|
226
|
+
/* Speaker layout: Tall */
|
227
|
+
body[data-speaker-layout="tall"] #current-slide,
|
228
|
+
body[data-speaker-layout="tall"] #upcoming-slide {
|
229
|
+
width: 45%;
|
230
|
+
height: 50%;
|
231
|
+
padding: 6px;
|
232
|
+
}
|
233
|
+
|
234
|
+
body[data-speaker-layout="tall"] #current-slide {
|
235
|
+
top: 0;
|
236
|
+
left: 0;
|
237
|
+
}
|
238
|
+
|
239
|
+
body[data-speaker-layout="tall"] #upcoming-slide {
|
240
|
+
top: 50%;
|
241
|
+
left: 0;
|
242
|
+
}
|
243
|
+
|
244
|
+
body[data-speaker-layout="tall"] #speaker-controls {
|
245
|
+
padding-top: 40px;
|
246
|
+
top: 0;
|
247
|
+
left: 45%;
|
248
|
+
width: 55%;
|
249
|
+
height: 100%;
|
250
|
+
font-size: 1.25em;
|
251
|
+
}
|
252
|
+
|
253
|
+
/* Speaker layout: Notes only */
|
254
|
+
body[data-speaker-layout="notes-only"] #current-slide,
|
255
|
+
body[data-speaker-layout="notes-only"] #upcoming-slide {
|
256
|
+
display: none;
|
257
|
+
}
|
258
|
+
|
259
|
+
body[data-speaker-layout="notes-only"] #speaker-controls {
|
260
|
+
padding-top: 40px;
|
261
|
+
top: 0;
|
262
|
+
left: 0;
|
263
|
+
width: 100%;
|
264
|
+
height: 100%;
|
265
|
+
font-size: 1.25em;
|
266
|
+
}
|
267
|
+
|
132
268
|
@media screen and (max-width: 1080px) {
|
133
|
-
#speaker-controls {
|
269
|
+
body[data-speaker-layout="default"] #speaker-controls {
|
134
270
|
font-size: 16px;
|
135
271
|
}
|
136
272
|
}
|
137
273
|
|
138
274
|
@media screen and (max-width: 900px) {
|
139
|
-
#speaker-controls {
|
275
|
+
body[data-speaker-layout="default"] #speaker-controls {
|
140
276
|
font-size: 14px;
|
141
277
|
}
|
142
278
|
}
|
143
279
|
|
144
280
|
@media screen and (max-width: 800px) {
|
145
|
-
#speaker-controls {
|
281
|
+
body[data-speaker-layout="default"] #speaker-controls {
|
146
282
|
font-size: 12px;
|
147
283
|
}
|
148
284
|
}
|
@@ -153,7 +289,7 @@
|
|
153
289
|
<body>
|
154
290
|
|
155
291
|
<div id="current-slide"></div>
|
156
|
-
<div id="upcoming-slide"><span class="label">
|
292
|
+
<div id="upcoming-slide"><span class="overlay-element label">Upcoming</span></div>
|
157
293
|
<div id="speaker-controls">
|
158
294
|
<div class="speaker-controls-time">
|
159
295
|
<h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
|
@@ -164,6 +300,11 @@
|
|
164
300
|
<span class="hours-value">00</span><span class="minutes-value">:00</span><span class="seconds-value">:00</span>
|
165
301
|
</div>
|
166
302
|
<div class="clear"></div>
|
303
|
+
|
304
|
+
<h4 class="label pacing-title" style="display: none">Pacing – Time to finish current slide</h4>
|
305
|
+
<div class="pacing" style="display: none">
|
306
|
+
<span class="hours-value">00</span><span class="minutes-value">:00</span><span class="seconds-value">:00</span>
|
307
|
+
</div>
|
167
308
|
</div>
|
168
309
|
|
169
310
|
<div class="speaker-controls-notes hidden">
|
@@ -171,6 +312,10 @@
|
|
171
312
|
<div class="value"></div>
|
172
313
|
</div>
|
173
314
|
</div>
|
315
|
+
<div id="speaker-layout" class="overlay-element interactive">
|
316
|
+
<span class="speaker-layout-label"></span>
|
317
|
+
<select class="speaker-layout-dropdown"></select>
|
318
|
+
</div>
|
174
319
|
|
175
320
|
<script src="../../plugin/markdown/marked.js"></script>
|
176
321
|
<script>
|
@@ -182,12 +327,27 @@
|
|
182
327
|
currentState,
|
183
328
|
currentSlide,
|
184
329
|
upcomingSlide,
|
330
|
+
layoutLabel,
|
331
|
+
layoutDropdown,
|
185
332
|
connected = false;
|
186
333
|
|
334
|
+
var SPEAKER_LAYOUTS = {
|
335
|
+
'default': 'Default',
|
336
|
+
'wide': 'Wide',
|
337
|
+
'tall': 'Tall',
|
338
|
+
'notes-only': 'Notes only'
|
339
|
+
};
|
340
|
+
|
341
|
+
setupLayout();
|
342
|
+
|
187
343
|
window.addEventListener( 'message', function( event ) {
|
188
344
|
|
189
345
|
var data = JSON.parse( event.data );
|
190
346
|
|
347
|
+
// The overview mode is only useful to the reveal.js instance
|
348
|
+
// where navigation occurs so we don't sync it
|
349
|
+
if( data.state ) delete data.state.overview;
|
350
|
+
|
191
351
|
// Messages sent by the notes plugin inside of the main window
|
192
352
|
if( data && data.namespace === 'reveal-notes' ) {
|
193
353
|
if( data.type === 'connect' ) {
|
@@ -203,8 +363,10 @@
|
|
203
363
|
// Send a message back to notify that the handshake is complete
|
204
364
|
window.opener.postMessage( JSON.stringify({ namespace: 'reveal-notes', type: 'connected'} ), '*' );
|
205
365
|
}
|
206
|
-
else if( /slidechanged|fragmentshown|fragmenthidden|
|
366
|
+
else if( /slidechanged|fragmentshown|fragmenthidden|paused|resumed/.test( data.eventName ) && currentState !== JSON.stringify( data.state ) ) {
|
367
|
+
|
207
368
|
window.opener.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ]} ), '*' );
|
369
|
+
|
208
370
|
}
|
209
371
|
}
|
210
372
|
|
@@ -239,6 +401,7 @@
|
|
239
401
|
// No need for updating the notes in case of fragment changes
|
240
402
|
if ( data.notes ) {
|
241
403
|
notes.classList.remove( 'hidden' );
|
404
|
+
notesValue.style.whiteSpace = data.whitespace;
|
242
405
|
if( data.markdown ) {
|
243
406
|
notesValue.innerHTML = marked( data.notes );
|
244
407
|
}
|
@@ -287,9 +450,10 @@
|
|
287
450
|
'backgroundTransition=none'
|
288
451
|
].join( '&' );
|
289
452
|
|
453
|
+
var urlSeparator = /\?/.test(data.url) ? '&' : '?';
|
290
454
|
var hash = '#/' + data.state.indexh + '/' + data.state.indexv;
|
291
|
-
var currentURL = data.url +
|
292
|
-
var upcomingURL = data.url +
|
455
|
+
var currentURL = data.url + urlSeparator + params + '&postMessageEvents=true' + hash;
|
456
|
+
var upcomingURL = data.url + urlSeparator + params + '&controls=false' + hash;
|
293
457
|
|
294
458
|
currentSlide = document.createElement( 'iframe' );
|
295
459
|
currentSlide.setAttribute( 'width', 1280 );
|
@@ -315,6 +479,47 @@
|
|
315
479
|
|
316
480
|
}
|
317
481
|
|
482
|
+
function getTimings() {
|
483
|
+
|
484
|
+
var slides = Reveal.getSlides();
|
485
|
+
var defaultTiming = Reveal.getConfig().defaultTiming;
|
486
|
+
if (defaultTiming == null) {
|
487
|
+
return null;
|
488
|
+
}
|
489
|
+
var timings = [];
|
490
|
+
for ( var i in slides ) {
|
491
|
+
var slide = slides[i];
|
492
|
+
var timing = defaultTiming;
|
493
|
+
if( slide.hasAttribute( 'data-timing' )) {
|
494
|
+
var t = slide.getAttribute( 'data-timing' );
|
495
|
+
timing = parseInt(t);
|
496
|
+
if( isNaN(timing) ) {
|
497
|
+
console.warn("Could not parse timing '" + t + "' of slide " + i + "; using default of " + defaultTiming);
|
498
|
+
timing = defaultTiming;
|
499
|
+
}
|
500
|
+
}
|
501
|
+
timings.push(timing);
|
502
|
+
}
|
503
|
+
return timings;
|
504
|
+
|
505
|
+
}
|
506
|
+
|
507
|
+
/**
|
508
|
+
* Return the number of seconds allocated for presenting
|
509
|
+
* all slides up to and including this one.
|
510
|
+
*/
|
511
|
+
function getTimeAllocated(timings) {
|
512
|
+
|
513
|
+
var slides = Reveal.getSlides();
|
514
|
+
var allocated = 0;
|
515
|
+
var currentSlide = Reveal.getSlidePastCount();
|
516
|
+
for (var i in slides.slice(0, currentSlide + 1)) {
|
517
|
+
allocated += timings[i];
|
518
|
+
}
|
519
|
+
return allocated;
|
520
|
+
|
521
|
+
}
|
522
|
+
|
318
523
|
/**
|
319
524
|
* Create the timer and clock and start updating them
|
320
525
|
* at an interval.
|
@@ -322,28 +527,78 @@
|
|
322
527
|
function setupTimer() {
|
323
528
|
|
324
529
|
var start = new Date(),
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
530
|
+
timeEl = document.querySelector( '.speaker-controls-time' ),
|
531
|
+
clockEl = timeEl.querySelector( '.clock-value' ),
|
532
|
+
hoursEl = timeEl.querySelector( '.hours-value' ),
|
533
|
+
minutesEl = timeEl.querySelector( '.minutes-value' ),
|
534
|
+
secondsEl = timeEl.querySelector( '.seconds-value' ),
|
535
|
+
pacingTitleEl = timeEl.querySelector( '.pacing-title' ),
|
536
|
+
pacingEl = timeEl.querySelector( '.pacing' ),
|
537
|
+
pacingHoursEl = pacingEl.querySelector( '.hours-value' ),
|
538
|
+
pacingMinutesEl = pacingEl.querySelector( '.minutes-value' ),
|
539
|
+
pacingSecondsEl = pacingEl.querySelector( '.seconds-value' );
|
540
|
+
|
541
|
+
var timings = getTimings();
|
542
|
+
if (timings !== null) {
|
543
|
+
pacingTitleEl.style.removeProperty('display');
|
544
|
+
pacingEl.style.removeProperty('display');
|
545
|
+
}
|
546
|
+
|
547
|
+
function _displayTime( hrEl, minEl, secEl, time) {
|
548
|
+
|
549
|
+
var sign = Math.sign(time) == -1 ? "-" : "";
|
550
|
+
time = Math.abs(Math.round(time / 1000));
|
551
|
+
var seconds = time % 60;
|
552
|
+
var minutes = Math.floor( time / 60 ) % 60 ;
|
553
|
+
var hours = Math.floor( time / ( 60 * 60 )) ;
|
554
|
+
hrEl.innerHTML = sign + zeroPadInteger( hours );
|
555
|
+
if (hours == 0) {
|
556
|
+
hrEl.classList.add( 'mute' );
|
557
|
+
}
|
558
|
+
else {
|
559
|
+
hrEl.classList.remove( 'mute' );
|
560
|
+
}
|
561
|
+
minEl.innerHTML = ':' + zeroPadInteger( minutes );
|
562
|
+
if (hours == 0 && minutes == 0) {
|
563
|
+
minEl.classList.add( 'mute' );
|
564
|
+
}
|
565
|
+
else {
|
566
|
+
minEl.classList.remove( 'mute' );
|
567
|
+
}
|
568
|
+
secEl.innerHTML = ':' + zeroPadInteger( seconds );
|
569
|
+
}
|
330
570
|
|
331
571
|
function _updateTimer() {
|
332
572
|
|
333
573
|
var diff, hours, minutes, seconds,
|
334
|
-
|
574
|
+
now = new Date();
|
335
575
|
|
336
576
|
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
577
|
|
341
578
|
clockEl.innerHTML = now.toLocaleTimeString( 'en-US', { hour12: true, hour: '2-digit', minute:'2-digit' } );
|
342
|
-
hoursEl
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
579
|
+
_displayTime( hoursEl, minutesEl, secondsEl, diff );
|
580
|
+
if (timings !== null) {
|
581
|
+
_updatePacing(diff);
|
582
|
+
}
|
583
|
+
|
584
|
+
}
|
585
|
+
|
586
|
+
function _updatePacing(diff) {
|
587
|
+
|
588
|
+
var slideEndTiming = getTimeAllocated(timings) * 1000;
|
589
|
+
var currentSlide = Reveal.getSlidePastCount();
|
590
|
+
var currentSlideTiming = timings[currentSlide] * 1000;
|
591
|
+
var timeLeftCurrentSlide = slideEndTiming - diff;
|
592
|
+
if (timeLeftCurrentSlide < 0) {
|
593
|
+
pacingEl.className = 'pacing behind';
|
594
|
+
}
|
595
|
+
else if (timeLeftCurrentSlide < currentSlideTiming) {
|
596
|
+
pacingEl.className = 'pacing on-track';
|
597
|
+
}
|
598
|
+
else {
|
599
|
+
pacingEl.className = 'pacing ahead';
|
600
|
+
}
|
601
|
+
_displayTime( pacingHoursEl, pacingMinutesEl, pacingSecondsEl, timeLeftCurrentSlide );
|
347
602
|
|
348
603
|
}
|
349
604
|
|
@@ -353,14 +608,112 @@
|
|
353
608
|
// Then update every second
|
354
609
|
setInterval( _updateTimer, 1000 );
|
355
610
|
|
356
|
-
|
357
|
-
|
611
|
+
function _resetTimer() {
|
612
|
+
|
613
|
+
if (timings == null) {
|
614
|
+
start = new Date();
|
615
|
+
}
|
616
|
+
else {
|
617
|
+
// Reset timer to beginning of current slide
|
618
|
+
var slideEndTiming = getTimeAllocated(timings) * 1000;
|
619
|
+
var currentSlide = Reveal.getSlidePastCount();
|
620
|
+
var currentSlideTiming = timings[currentSlide] * 1000;
|
621
|
+
var previousSlidesTiming = slideEndTiming - currentSlideTiming;
|
622
|
+
var now = new Date();
|
623
|
+
start = new Date(now.getTime() - previousSlidesTiming);
|
624
|
+
}
|
358
625
|
_updateTimer();
|
626
|
+
|
627
|
+
}
|
628
|
+
|
629
|
+
timeEl.addEventListener( 'click', function() {
|
630
|
+
_resetTimer();
|
359
631
|
return false;
|
360
632
|
} );
|
361
633
|
|
362
634
|
}
|
363
635
|
|
636
|
+
/**
|
637
|
+
* Sets up the speaker view layout and layout selector.
|
638
|
+
*/
|
639
|
+
function setupLayout() {
|
640
|
+
|
641
|
+
layoutDropdown = document.querySelector( '.speaker-layout-dropdown' );
|
642
|
+
layoutLabel = document.querySelector( '.speaker-layout-label' );
|
643
|
+
|
644
|
+
// Render the list of available layouts
|
645
|
+
for( var id in SPEAKER_LAYOUTS ) {
|
646
|
+
var option = document.createElement( 'option' );
|
647
|
+
option.setAttribute( 'value', id );
|
648
|
+
option.textContent = SPEAKER_LAYOUTS[ id ];
|
649
|
+
layoutDropdown.appendChild( option );
|
650
|
+
}
|
651
|
+
|
652
|
+
// Monitor the dropdown for changes
|
653
|
+
layoutDropdown.addEventListener( 'change', function( event ) {
|
654
|
+
|
655
|
+
setLayout( layoutDropdown.value );
|
656
|
+
|
657
|
+
}, false );
|
658
|
+
|
659
|
+
// Restore any currently persisted layout
|
660
|
+
setLayout( getLayout() );
|
661
|
+
|
662
|
+
}
|
663
|
+
|
664
|
+
/**
|
665
|
+
* Sets a new speaker view layout. The layout is persisted
|
666
|
+
* in local storage.
|
667
|
+
*/
|
668
|
+
function setLayout( value ) {
|
669
|
+
|
670
|
+
var title = SPEAKER_LAYOUTS[ value ];
|
671
|
+
|
672
|
+
layoutLabel.innerHTML = 'Layout' + ( title ? ( ': ' + title ) : '' );
|
673
|
+
layoutDropdown.value = value;
|
674
|
+
|
675
|
+
document.body.setAttribute( 'data-speaker-layout', value );
|
676
|
+
|
677
|
+
// Persist locally
|
678
|
+
if( supportsLocalStorage() ) {
|
679
|
+
window.localStorage.setItem( 'reveal-speaker-layout', value );
|
680
|
+
}
|
681
|
+
|
682
|
+
}
|
683
|
+
|
684
|
+
/**
|
685
|
+
* Returns the ID of the most recently set speaker layout
|
686
|
+
* or our default layout if none has been set.
|
687
|
+
*/
|
688
|
+
function getLayout() {
|
689
|
+
|
690
|
+
if( supportsLocalStorage() ) {
|
691
|
+
var layout = window.localStorage.getItem( 'reveal-speaker-layout' );
|
692
|
+
if( layout ) {
|
693
|
+
return layout;
|
694
|
+
}
|
695
|
+
}
|
696
|
+
|
697
|
+
// Default to the first record in the layouts hash
|
698
|
+
for( var id in SPEAKER_LAYOUTS ) {
|
699
|
+
return id;
|
700
|
+
}
|
701
|
+
|
702
|
+
}
|
703
|
+
|
704
|
+
function supportsLocalStorage() {
|
705
|
+
|
706
|
+
try {
|
707
|
+
localStorage.setItem('test', 'test');
|
708
|
+
localStorage.removeItem('test');
|
709
|
+
return true;
|
710
|
+
}
|
711
|
+
catch( e ) {
|
712
|
+
return false;
|
713
|
+
}
|
714
|
+
|
715
|
+
}
|
716
|
+
|
364
717
|
function zeroPadInteger( num ) {
|
365
718
|
|
366
719
|
var str = '00' + parseInt( num );
|
@@ -11,10 +11,18 @@
|
|
11
11
|
*/
|
12
12
|
var RevealNotes = (function() {
|
13
13
|
|
14
|
-
function openNotes() {
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
function openNotes( notesFilePath ) {
|
15
|
+
|
16
|
+
if( !notesFilePath ) {
|
17
|
+
var jsFileLocation = document.querySelector('script[src$="notes.js"]').src; // this js file path
|
18
|
+
jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path
|
19
|
+
notesFilePath = jsFileLocation + 'notes.html';
|
20
|
+
}
|
21
|
+
|
22
|
+
var notesPopup = window.open( notesFilePath, 'reveal.js - Notes', 'width=1100,height=700' );
|
23
|
+
|
24
|
+
// Allow popup window access to Reveal API
|
25
|
+
notesPopup.Reveal = this.Reveal;
|
18
26
|
|
19
27
|
/**
|
20
28
|
* Connect to the notes window through a postmessage handshake.
|
@@ -45,22 +53,40 @@ var RevealNotes = (function() {
|
|
45
53
|
/**
|
46
54
|
* Posts the current slide data to the notes window
|
47
55
|
*/
|
48
|
-
function post() {
|
56
|
+
function post( event ) {
|
49
57
|
|
50
58
|
var slideElement = Reveal.getCurrentSlide(),
|
51
|
-
notesElement = slideElement.querySelector( 'aside.notes' )
|
59
|
+
notesElement = slideElement.querySelector( 'aside.notes' ),
|
60
|
+
fragmentElement = slideElement.querySelector( '.current-fragment' );
|
52
61
|
|
53
62
|
var messageData = {
|
54
63
|
namespace: 'reveal-notes',
|
55
64
|
type: 'state',
|
56
65
|
notes: '',
|
57
66
|
markdown: false,
|
67
|
+
whitespace: 'normal',
|
58
68
|
state: Reveal.getState()
|
59
69
|
};
|
60
70
|
|
61
71
|
// Look for notes defined in a slide attribute
|
62
72
|
if( slideElement.hasAttribute( 'data-notes' ) ) {
|
63
73
|
messageData.notes = slideElement.getAttribute( 'data-notes' );
|
74
|
+
messageData.whitespace = 'pre-wrap';
|
75
|
+
}
|
76
|
+
|
77
|
+
// Look for notes defined in a fragment
|
78
|
+
if( fragmentElement ) {
|
79
|
+
var fragmentNotes = fragmentElement.querySelector( 'aside.notes' );
|
80
|
+
if( fragmentNotes ) {
|
81
|
+
notesElement = fragmentNotes;
|
82
|
+
}
|
83
|
+
else if( fragmentElement.hasAttribute( 'data-notes' ) ) {
|
84
|
+
messageData.notes = fragmentElement.getAttribute( 'data-notes' );
|
85
|
+
messageData.whitespace = 'pre-wrap';
|
86
|
+
|
87
|
+
// In case there are slide notes
|
88
|
+
notesElement = null;
|
89
|
+
}
|
64
90
|
}
|
65
91
|
|
66
92
|
// Look for notes defined in an aside element
|
@@ -94,6 +120,7 @@ var RevealNotes = (function() {
|
|
94
120
|
}
|
95
121
|
|
96
122
|
connect();
|
123
|
+
|
97
124
|
}
|
98
125
|
|
99
126
|
if( !/receiver/i.test( window.location.search ) ) {
|
@@ -109,12 +136,18 @@ var RevealNotes = (function() {
|
|
109
136
|
// modifier is present
|
110
137
|
if ( document.querySelector( ':focus' ) !== null || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return;
|
111
138
|
|
139
|
+
// Disregard the event if keyboard is disabled
|
140
|
+
if ( Reveal.getConfig().keyboard === false ) return;
|
141
|
+
|
112
142
|
if( event.keyCode === 83 ) {
|
113
143
|
event.preventDefault();
|
114
144
|
openNotes();
|
115
145
|
}
|
116
146
|
}, false );
|
117
147
|
|
148
|
+
// Show our keyboard shortcut in the reveal.js help overlay
|
149
|
+
if( window.Reveal ) Reveal.registerKeyboardShortcut( 'S', 'Speaker notes view' );
|
150
|
+
|
118
151
|
}
|
119
152
|
|
120
153
|
return { open: openNotes };
|
@@ -41,10 +41,15 @@
|
|
41
41
|
}
|
42
42
|
|
43
43
|
// When a new notes window connects, post our current state
|
44
|
-
socket.on( '
|
44
|
+
socket.on( 'new-subscriber', function( data ) {
|
45
45
|
post();
|
46
46
|
} );
|
47
47
|
|
48
|
+
// When the state changes from inside of the speaker view
|
49
|
+
socket.on( 'statechanged-speaker', function( data ) {
|
50
|
+
Reveal.setState( data.state );
|
51
|
+
} );
|
52
|
+
|
48
53
|
// Monitor events that trigger a change in state
|
49
54
|
Reveal.addEventListener( 'slidechanged', post );
|
50
55
|
Reveal.addEventListener( 'fragmentshown', post );
|