scateu.me-jekyll-theme 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/css/main.scss +56 -0
  3. data/feed.xml +30 -0
  4. data/index.html +22 -0
  5. data/js/.DS_Store +0 -0
  6. data/js/flowchart-latest.js +991 -0
  7. data/js/jquery-3.1.1.min.js +4 -0
  8. data/js/qrcode.min.js +1 -0
  9. data/js/raphael-min.js +11 -0
  10. data/js/reveal.js/.gitignore +13 -0
  11. data/js/reveal.js/.travis.yml +5 -0
  12. data/js/reveal.js/CONTRIBUTING.md +23 -0
  13. data/js/reveal.js/Gruntfile.js +176 -0
  14. data/js/reveal.js/LICENSE +19 -0
  15. data/js/reveal.js/README.md +1148 -0
  16. data/js/reveal.js/bower.json +27 -0
  17. data/js/reveal.js/css/print/paper.css +202 -0
  18. data/js/reveal.js/css/print/pdf.css +160 -0
  19. data/js/reveal.js/css/reveal.css +1344 -0
  20. data/js/reveal.js/css/reveal.scss +1412 -0
  21. data/js/reveal.js/css/theme/README.md +21 -0
  22. data/js/reveal.js/css/theme/beige.css +291 -0
  23. data/js/reveal.js/css/theme/black.css +287 -0
  24. data/js/reveal.js/css/theme/blood.css +310 -0
  25. data/js/reveal.js/css/theme/league.css +293 -0
  26. data/js/reveal.js/css/theme/moon.css +291 -0
  27. data/js/reveal.js/css/theme/night.css +285 -0
  28. data/js/reveal.js/css/theme/serif.css +287 -0
  29. data/js/reveal.js/css/theme/simple.css +287 -0
  30. data/js/reveal.js/css/theme/sky.css +294 -0
  31. data/js/reveal.js/css/theme/solarized.css +291 -0
  32. data/js/reveal.js/css/theme/source/beige.scss +39 -0
  33. data/js/reveal.js/css/theme/source/black.scss +49 -0
  34. data/js/reveal.js/css/theme/source/blood.scss +79 -0
  35. data/js/reveal.js/css/theme/source/league.scss +34 -0
  36. data/js/reveal.js/css/theme/source/moon.scss +57 -0
  37. data/js/reveal.js/css/theme/source/night.scss +35 -0
  38. data/js/reveal.js/css/theme/source/serif.scss +35 -0
  39. data/js/reveal.js/css/theme/source/simple.scss +38 -0
  40. data/js/reveal.js/css/theme/source/sky.scss +46 -0
  41. data/js/reveal.js/css/theme/source/solarized.scss +63 -0
  42. data/js/reveal.js/css/theme/source/white.scss +49 -0
  43. data/js/reveal.js/css/theme/template/mixins.scss +29 -0
  44. data/js/reveal.js/css/theme/template/settings.scss +43 -0
  45. data/js/reveal.js/css/theme/template/theme.scss +346 -0
  46. data/js/reveal.js/css/theme/white.css +287 -0
  47. data/js/reveal.js/demo.html +410 -0
  48. data/js/reveal.js/index.html +50 -0
  49. data/js/reveal.js/js/reveal.js +4744 -0
  50. data/js/reveal.js/lib/css/zenburn.css +80 -0
  51. data/js/reveal.js/lib/font/league-gothic/LICENSE +2 -0
  52. data/js/reveal.js/lib/font/league-gothic/league-gothic.css +10 -0
  53. data/js/reveal.js/lib/font/league-gothic/league-gothic.eot +0 -0
  54. data/js/reveal.js/lib/font/league-gothic/league-gothic.ttf +0 -0
  55. data/js/reveal.js/lib/font/league-gothic/league-gothic.woff +0 -0
  56. data/js/reveal.js/lib/font/source-sans-pro/LICENSE +45 -0
  57. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.eot +0 -0
  58. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.ttf +0 -0
  59. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.woff +0 -0
  60. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.eot +0 -0
  61. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.ttf +0 -0
  62. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.woff +0 -0
  63. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.eot +0 -0
  64. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.ttf +0 -0
  65. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.woff +0 -0
  66. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.eot +0 -0
  67. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.ttf +0 -0
  68. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.woff +0 -0
  69. data/js/reveal.js/lib/font/source-sans-pro/source-sans-pro.css +39 -0
  70. data/js/reveal.js/lib/js/classList.js +2 -0
  71. data/js/reveal.js/lib/js/head.min.js +9 -0
  72. data/js/reveal.js/lib/js/html5shiv.js +7 -0
  73. data/js/reveal.js/package.json +44 -0
  74. data/js/reveal.js/plugin/highlight/highlight.js +31 -0
  75. data/js/reveal.js/plugin/markdown/example.html +129 -0
  76. data/js/reveal.js/plugin/markdown/markdown.js +405 -0
  77. data/js/reveal.js/plugin/markdown/marked.js +6 -0
  78. data/js/reveal.js/plugin/math/math.js +67 -0
  79. data/js/reveal.js/plugin/multiplex/client.js +13 -0
  80. data/js/reveal.js/plugin/multiplex/index.js +64 -0
  81. data/js/reveal.js/plugin/multiplex/master.js +31 -0
  82. data/js/reveal.js/plugin/multiplex/package.json +19 -0
  83. data/js/reveal.js/plugin/notes-server/client.js +65 -0
  84. data/js/reveal.js/plugin/notes-server/index.js +69 -0
  85. data/js/reveal.js/plugin/notes-server/notes.html +407 -0
  86. data/js/reveal.js/plugin/notes/notes.html +414 -0
  87. data/js/reveal.js/plugin/notes/notes.js +136 -0
  88. data/js/reveal.js/plugin/print-pdf/print-pdf.js +48 -0
  89. data/js/reveal.js/plugin/search/search.js +196 -0
  90. data/js/reveal.js/plugin/zoom-js/zoom.js +278 -0
  91. data/js/reveal.js/test/examples/assets/image1.png +0 -0
  92. data/js/reveal.js/test/examples/assets/image2.png +0 -0
  93. data/js/reveal.js/test/examples/barebones.html +41 -0
  94. data/js/reveal.js/test/examples/embedded-media.html +49 -0
  95. data/js/reveal.js/test/examples/math.html +185 -0
  96. data/js/reveal.js/test/examples/slide-backgrounds.html +144 -0
  97. data/js/reveal.js/test/examples/slide-transitions.html +101 -0
  98. data/js/reveal.js/test/qunit-1.12.0.css +244 -0
  99. data/js/reveal.js/test/qunit-1.12.0.js +2212 -0
  100. data/js/reveal.js/test/test-markdown-element-attributes.html +134 -0
  101. data/js/reveal.js/test/test-markdown-element-attributes.js +46 -0
  102. data/js/reveal.js/test/test-markdown-slide-attributes.html +128 -0
  103. data/js/reveal.js/test/test-markdown-slide-attributes.js +47 -0
  104. data/js/reveal.js/test/test-markdown.html +52 -0
  105. data/js/reveal.js/test/test-markdown.js +15 -0
  106. data/js/reveal.js/test/test-pdf.html +83 -0
  107. data/js/reveal.js/test/test-pdf.js +15 -0
  108. data/js/reveal.js/test/test.html +86 -0
  109. data/js/reveal.js/test/test.js +597 -0
  110. data/js/sequence-diagram-min.js +8 -0
  111. data/js/underscore-min.js +1 -0
  112. metadata +111 -1
@@ -0,0 +1,13 @@
1
+ (function() {
2
+ var multiplex = Reveal.getConfig().multiplex;
3
+ var socketId = multiplex.id;
4
+ var socket = io.connect(multiplex.url);
5
+
6
+ socket.on(multiplex.id, function(data) {
7
+ // ignore data from sockets that aren't ours
8
+ if (data.socketId !== socketId) { return; }
9
+ if( window.location.host === 'localhost:1947' ) return;
10
+
11
+ Reveal.setState(data.state);
12
+ });
13
+ }());
@@ -0,0 +1,64 @@
1
+ var http = require('http');
2
+ var express = require('express');
3
+ var fs = require('fs');
4
+ var io = require('socket.io');
5
+ var crypto = require('crypto');
6
+
7
+ var app = express();
8
+ var staticDir = express.static;
9
+ var server = http.createServer(app);
10
+
11
+ io = io(server);
12
+
13
+ var opts = {
14
+ port: process.env.PORT || 1948,
15
+ baseDir : __dirname + '/../../'
16
+ };
17
+
18
+ io.on( 'connection', function( socket ) {
19
+ socket.on('multiplex-statechanged', function(data) {
20
+ if (typeof data.secret == 'undefined' || data.secret == null || data.secret === '') return;
21
+ if (createHash(data.secret) === data.socketId) {
22
+ data.secret = null;
23
+ socket.broadcast.emit(data.socketId, data);
24
+ };
25
+ });
26
+ });
27
+
28
+ [ 'css', 'js', 'plugin', 'lib' ].forEach(function(dir) {
29
+ app.use('/' + dir, staticDir(opts.baseDir + dir));
30
+ });
31
+
32
+ app.get("/", function(req, res) {
33
+ res.writeHead(200, {'Content-Type': 'text/html'});
34
+
35
+ var stream = fs.createReadStream(opts.baseDir + '/index.html');
36
+ stream.on('error', function( error ) {
37
+ res.write('<style>body{font-family: sans-serif;}</style><h2>reveal.js multiplex server.</h2><a href="/token">Generate token</a>');
38
+ res.end();
39
+ });
40
+ stream.on('readable', function() {
41
+ stream.pipe(res);
42
+ });
43
+ });
44
+
45
+ app.get("/token", function(req,res) {
46
+ var ts = new Date().getTime();
47
+ var rand = Math.floor(Math.random()*9999999);
48
+ var secret = ts.toString() + rand.toString();
49
+ res.send({secret: secret, socketId: createHash(secret)});
50
+ });
51
+
52
+ var createHash = function(secret) {
53
+ var cipher = crypto.createCipher('blowfish', secret);
54
+ return(cipher.final('hex'));
55
+ };
56
+
57
+ // Actually listen
58
+ server.listen( opts.port || null );
59
+
60
+ var brown = '\033[33m',
61
+ green = '\033[32m',
62
+ reset = '\033[0m';
63
+
64
+ console.log( brown + "reveal.js:" + reset + " Multiplex running on port " + green + opts.port + reset );
@@ -0,0 +1,31 @@
1
+ (function() {
2
+
3
+ // Don't emit events from inside of notes windows
4
+ if ( window.location.search.match( /receiver/gi ) ) { return; }
5
+
6
+ var multiplex = Reveal.getConfig().multiplex;
7
+
8
+ var socket = io.connect( multiplex.url );
9
+
10
+ function post() {
11
+
12
+ var messageData = {
13
+ state: Reveal.getState(),
14
+ secret: multiplex.secret,
15
+ socketId: multiplex.id
16
+ };
17
+
18
+ socket.emit( 'multiplex-statechanged', messageData );
19
+
20
+ };
21
+
22
+ // Monitor events that trigger a change in state
23
+ Reveal.addEventListener( 'slidechanged', post );
24
+ Reveal.addEventListener( 'fragmentshown', post );
25
+ Reveal.addEventListener( 'fragmenthidden', post );
26
+ Reveal.addEventListener( 'overviewhidden', post );
27
+ Reveal.addEventListener( 'overviewshown', post );
28
+ Reveal.addEventListener( 'paused', post );
29
+ Reveal.addEventListener( 'resumed', post );
30
+
31
+ }());
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "reveal-js-multiplex",
3
+ "version": "1.0.0",
4
+ "description": "reveal.js multiplex server",
5
+ "homepage": "http://lab.hakim.se/reveal-js",
6
+ "scripts": {
7
+ "start": "node index.js"
8
+ },
9
+ "engines": {
10
+ "node": "~4.1.1"
11
+ },
12
+ "dependencies": {
13
+ "express": "~4.13.3",
14
+ "grunt-cli": "~0.1.13",
15
+ "mustache": "~2.2.1",
16
+ "socket.io": "~1.3.7"
17
+ },
18
+ "license": "MIT"
19
+ }
@@ -0,0 +1,65 @@
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( 'new-subscriber', function( data ) {
45
+ post();
46
+ } );
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
+
53
+ // Monitor events that trigger a change in state
54
+ Reveal.addEventListener( 'slidechanged', post );
55
+ Reveal.addEventListener( 'fragmentshown', post );
56
+ Reveal.addEventListener( 'fragmenthidden', post );
57
+ Reveal.addEventListener( 'overviewhidden', post );
58
+ Reveal.addEventListener( 'overviewshown', post );
59
+ Reveal.addEventListener( 'paused', post );
60
+ Reveal.addEventListener( 'resumed', post );
61
+
62
+ // Post the initial state
63
+ post();
64
+
65
+ }());
@@ -0,0 +1,69 @@
1
+ var http = require('http');
2
+ var express = require('express');
3
+ var fs = require('fs');
4
+ var io = require('socket.io');
5
+ var Mustache = require('mustache');
6
+
7
+ var app = express();
8
+ var staticDir = express.static;
9
+ var server = http.createServer(app);
10
+
11
+ io = io(server);
12
+
13
+ var opts = {
14
+ port : 1947,
15
+ baseDir : __dirname + '/../../'
16
+ };
17
+
18
+ io.on( 'connection', function( socket ) {
19
+
20
+ socket.on( 'new-subscriber', function( data ) {
21
+ socket.broadcast.emit( 'new-subscriber', data );
22
+ });
23
+
24
+ socket.on( 'statechanged', function( data ) {
25
+ delete data.state.overview;
26
+ socket.broadcast.emit( 'statechanged', data );
27
+ });
28
+
29
+ socket.on( 'statechanged-speaker', function( data ) {
30
+ delete data.state.overview;
31
+ socket.broadcast.emit( 'statechanged-speaker', data );
32
+ });
33
+
34
+ });
35
+
36
+ [ 'css', 'js', 'images', 'plugin', 'lib' ].forEach( function( dir ) {
37
+ app.use( '/' + dir, staticDir( opts.baseDir + dir ) );
38
+ });
39
+
40
+ app.get('/', function( req, res ) {
41
+
42
+ res.writeHead( 200, { 'Content-Type': 'text/html' } );
43
+ fs.createReadStream( opts.baseDir + '/index.html' ).pipe( res );
44
+
45
+ });
46
+
47
+ app.get( '/notes/:socketId', function( req, res ) {
48
+
49
+ fs.readFile( opts.baseDir + 'plugin/notes-server/notes.html', function( err, data ) {
50
+ res.send( Mustache.to_html( data.toString(), {
51
+ socketId : req.params.socketId
52
+ }));
53
+ });
54
+
55
+ });
56
+
57
+ // Actually listen
58
+ server.listen( opts.port || null );
59
+
60
+ var brown = '\033[33m',
61
+ green = '\033[32m',
62
+ reset = '\033[0m';
63
+
64
+ var slidesLocation = 'http://localhost' + ( opts.port ? ( ':' + opts.port ) : '' );
65
+
66
+ console.log( brown + 'reveal.js - Speaker Notes' + reset );
67
+ console.log( '1. Open the slides at ' + green + slidesLocation + reset );
68
+ console.log( '2. Click on the link in your JS console to go to the notes page' );
69
+ console.log( '3. Advance through your slides and your notes will advance automatically' );
@@ -0,0 +1,407 @@
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
+
63
+ font-size: 18px;
64
+ }
65
+
66
+ .speaker-controls-time.hidden,
67
+ .speaker-controls-notes.hidden {
68
+ display: none;
69
+ }
70
+
71
+ .speaker-controls-time .label,
72
+ .speaker-controls-notes .label {
73
+ text-transform: uppercase;
74
+ font-weight: normal;
75
+ font-size: 0.66em;
76
+ color: #666;
77
+ margin: 0;
78
+ }
79
+
80
+ .speaker-controls-time {
81
+ border-bottom: 1px solid rgba( 200, 200, 200, 0.5 );
82
+ margin-bottom: 10px;
83
+ padding: 10px 16px;
84
+ padding-bottom: 20px;
85
+ cursor: pointer;
86
+ }
87
+
88
+ .speaker-controls-time .reset-button {
89
+ opacity: 0;
90
+ float: right;
91
+ color: #666;
92
+ text-decoration: none;
93
+ }
94
+ .speaker-controls-time:hover .reset-button {
95
+ opacity: 1;
96
+ }
97
+
98
+ .speaker-controls-time .timer,
99
+ .speaker-controls-time .clock {
100
+ width: 50%;
101
+ font-size: 1.9em;
102
+ }
103
+
104
+ .speaker-controls-time .timer {
105
+ float: left;
106
+ }
107
+
108
+ .speaker-controls-time .clock {
109
+ float: right;
110
+ text-align: right;
111
+ }
112
+
113
+ .speaker-controls-time span.mute {
114
+ color: #bbb;
115
+ }
116
+
117
+ .speaker-controls-notes {
118
+ padding: 10px 16px;
119
+ }
120
+
121
+ .speaker-controls-notes .value {
122
+ margin-top: 5px;
123
+ line-height: 1.4;
124
+ font-size: 1.2em;
125
+ }
126
+
127
+ .clear {
128
+ clear: both;
129
+ }
130
+
131
+ @media screen and (max-width: 1080px) {
132
+ #speaker-controls {
133
+ font-size: 16px;
134
+ }
135
+ }
136
+
137
+ @media screen and (max-width: 900px) {
138
+ #speaker-controls {
139
+ font-size: 14px;
140
+ }
141
+ }
142
+
143
+ @media screen and (max-width: 800px) {
144
+ #speaker-controls {
145
+ font-size: 12px;
146
+ }
147
+ }
148
+
149
+ </style>
150
+ </head>
151
+
152
+ <body>
153
+
154
+ <div id="current-slide"></div>
155
+ <div id="upcoming-slide"><span class="label">UPCOMING:</span></div>
156
+ <div id="speaker-controls">
157
+ <div class="speaker-controls-time">
158
+ <h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
159
+ <div class="clock">
160
+ <span class="clock-value">0:00 AM</span>
161
+ </div>
162
+ <div class="timer">
163
+ <span class="hours-value">00</span><span class="minutes-value">:00</span><span class="seconds-value">:00</span>
164
+ </div>
165
+ <div class="clear"></div>
166
+ </div>
167
+
168
+ <div class="speaker-controls-notes hidden">
169
+ <h4 class="label">Notes</h4>
170
+ <div class="value"></div>
171
+ </div>
172
+ </div>
173
+
174
+ <script src="/socket.io/socket.io.js"></script>
175
+ <script src="/plugin/markdown/marked.js"></script>
176
+
177
+ <script>
178
+ (function() {
179
+
180
+ var notes,
181
+ notesValue,
182
+ currentState,
183
+ currentSlide,
184
+ upcomingSlide,
185
+ connected = false;
186
+
187
+ var socket = io.connect( window.location.origin ),
188
+ socketId = '{{socketId}}';
189
+
190
+ socket.on( 'statechanged', function( data ) {
191
+
192
+ // ignore data from sockets that aren't ours
193
+ if( data.socketId !== socketId ) { return; }
194
+
195
+ if( connected === false ) {
196
+ connected = true;
197
+
198
+ setupKeyboard();
199
+ setupNotes();
200
+ setupTimer();
201
+
202
+ }
203
+
204
+ handleStateMessage( data );
205
+
206
+ } );
207
+
208
+ // Load our presentation iframes
209
+ setupIframes();
210
+
211
+ // Once the iframes have loaded, emit a signal saying there's
212
+ // a new subscriber which will trigger a 'statechanged'
213
+ // message to be sent back
214
+ window.addEventListener( 'message', function( event ) {
215
+
216
+ var data = JSON.parse( event.data );
217
+
218
+ if( data && data.namespace === 'reveal' ) {
219
+ if( /ready/.test( data.eventName ) ) {
220
+ socket.emit( 'new-subscriber', { socketId: socketId } );
221
+ }
222
+ }
223
+
224
+ // Messages sent by reveal.js inside of the current slide preview
225
+ if( data && data.namespace === 'reveal' ) {
226
+ if( /slidechanged|fragmentshown|fragmenthidden|overviewshown|overviewhidden|paused|resumed/.test( data.eventName ) && currentState !== JSON.stringify( data.state ) ) {
227
+ socket.emit( 'statechanged-speaker', { state: data.state } );
228
+ }
229
+ }
230
+
231
+ } );
232
+
233
+ /**
234
+ * Called when the main window sends an updated state.
235
+ */
236
+ function handleStateMessage( data ) {
237
+
238
+ // Store the most recently set state to avoid circular loops
239
+ // applying the same state
240
+ currentState = JSON.stringify( data.state );
241
+
242
+ // No need for updating the notes in case of fragment changes
243
+ if ( data.notes ) {
244
+ notes.classList.remove( 'hidden' );
245
+ if( data.markdown ) {
246
+ notesValue.innerHTML = marked( data.notes );
247
+ }
248
+ else {
249
+ notesValue.innerHTML = data.notes;
250
+ }
251
+ }
252
+ else {
253
+ notes.classList.add( 'hidden' );
254
+ }
255
+
256
+ // Update the note slides
257
+ currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
258
+ upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
259
+ upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'next' }), '*' );
260
+
261
+ }
262
+
263
+ // Limit to max one state update per X ms
264
+ handleStateMessage = debounce( handleStateMessage, 200 );
265
+
266
+ /**
267
+ * Forward keyboard events to the current slide window.
268
+ * This enables keyboard events to work even if focus
269
+ * isn't set on the current slide iframe.
270
+ */
271
+ function setupKeyboard() {
272
+
273
+ document.addEventListener( 'keydown', function( event ) {
274
+ currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'triggerKey', args: [ event.keyCode ] }), '*' );
275
+ } );
276
+
277
+ }
278
+
279
+ /**
280
+ * Creates the preview iframes.
281
+ */
282
+ function setupIframes() {
283
+
284
+ var params = [
285
+ 'receiver',
286
+ 'progress=false',
287
+ 'history=false',
288
+ 'transition=none',
289
+ 'backgroundTransition=none'
290
+ ].join( '&' );
291
+
292
+ var currentURL = '/?' + params + '&postMessageEvents=true';
293
+ var upcomingURL = '/?' + params + '&controls=false';
294
+
295
+ currentSlide = document.createElement( 'iframe' );
296
+ currentSlide.setAttribute( 'width', 1280 );
297
+ currentSlide.setAttribute( 'height', 1024 );
298
+ currentSlide.setAttribute( 'src', currentURL );
299
+ document.querySelector( '#current-slide' ).appendChild( currentSlide );
300
+
301
+ upcomingSlide = document.createElement( 'iframe' );
302
+ upcomingSlide.setAttribute( 'width', 640 );
303
+ upcomingSlide.setAttribute( 'height', 512 );
304
+ upcomingSlide.setAttribute( 'src', upcomingURL );
305
+ document.querySelector( '#upcoming-slide' ).appendChild( upcomingSlide );
306
+
307
+ }
308
+
309
+ /**
310
+ * Setup the notes UI.
311
+ */
312
+ function setupNotes() {
313
+
314
+ notes = document.querySelector( '.speaker-controls-notes' );
315
+ notesValue = document.querySelector( '.speaker-controls-notes .value' );
316
+
317
+ }
318
+
319
+ /**
320
+ * Create the timer and clock and start updating them
321
+ * at an interval.
322
+ */
323
+ function setupTimer() {
324
+
325
+ var start = new Date(),
326
+ timeEl = document.querySelector( '.speaker-controls-time' ),
327
+ clockEl = timeEl.querySelector( '.clock-value' ),
328
+ hoursEl = timeEl.querySelector( '.hours-value' ),
329
+ minutesEl = timeEl.querySelector( '.minutes-value' ),
330
+ secondsEl = timeEl.querySelector( '.seconds-value' );
331
+
332
+ function _updateTimer() {
333
+
334
+ var diff, hours, minutes, seconds,
335
+ now = new Date();
336
+
337
+ diff = now.getTime() - start.getTime();
338
+ hours = Math.floor( diff / ( 1000 * 60 * 60 ) );
339
+ minutes = Math.floor( ( diff / ( 1000 * 60 ) ) % 60 );
340
+ seconds = Math.floor( ( diff / 1000 ) % 60 );
341
+
342
+ clockEl.innerHTML = now.toLocaleTimeString( 'en-US', { hour12: true, hour: '2-digit', minute:'2-digit' } );
343
+ hoursEl.innerHTML = zeroPadInteger( hours );
344
+ hoursEl.className = hours > 0 ? '' : 'mute';
345
+ minutesEl.innerHTML = ':' + zeroPadInteger( minutes );
346
+ minutesEl.className = minutes > 0 ? '' : 'mute';
347
+ secondsEl.innerHTML = ':' + zeroPadInteger( seconds );
348
+
349
+ }
350
+
351
+ // Update once directly
352
+ _updateTimer();
353
+
354
+ // Then update every second
355
+ setInterval( _updateTimer, 1000 );
356
+
357
+ timeEl.addEventListener( 'click', function() {
358
+ start = new Date();
359
+ _updateTimer();
360
+ return false;
361
+ } );
362
+
363
+ }
364
+
365
+ function zeroPadInteger( num ) {
366
+
367
+ var str = '00' + parseInt( num );
368
+ return str.substring( str.length - 2 );
369
+
370
+ }
371
+
372
+ /**
373
+ * Limits the frequency at which a function can be called.
374
+ */
375
+ function debounce( fn, ms ) {
376
+
377
+ var lastTime = 0,
378
+ timeout;
379
+
380
+ return function() {
381
+
382
+ var args = arguments;
383
+ var context = this;
384
+
385
+ clearTimeout( timeout );
386
+
387
+ var timeSinceLastCall = Date.now() - lastTime;
388
+ if( timeSinceLastCall > ms ) {
389
+ fn.apply( context, args );
390
+ lastTime = Date.now();
391
+ }
392
+ else {
393
+ timeout = setTimeout( function() {
394
+ fn.apply( context, args );
395
+ lastTime = Date.now();
396
+ }, ms - timeSinceLastCall );
397
+ }
398
+
399
+ }
400
+
401
+ }
402
+
403
+ })();
404
+ </script>
405
+
406
+ </body>
407
+ </html>