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.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +2 -1
  4. data/Dockerfile +4 -0
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +7 -1
  7. data/README.md +1 -1
  8. data/lib/reveal/command.rb +9 -3
  9. data/lib/reveal/templates/revealjs/css/print/paper.css +4 -3
  10. data/lib/reveal/templates/revealjs/css/print/pdf.css +59 -38
  11. data/lib/reveal/templates/revealjs/css/reveal.css +654 -274
  12. data/lib/reveal/templates/revealjs/css/theme/beige.css +65 -68
  13. data/lib/reveal/templates/revealjs/css/theme/black.css +58 -61
  14. data/lib/reveal/templates/revealjs/css/theme/blood.css +64 -62
  15. data/lib/reveal/templates/revealjs/css/theme/league.css +59 -62
  16. data/lib/reveal/templates/revealjs/css/theme/moon.css +59 -62
  17. data/lib/reveal/templates/revealjs/css/theme/night.css +58 -61
  18. data/lib/reveal/templates/revealjs/css/theme/serif.css +56 -59
  19. data/lib/reveal/templates/revealjs/css/theme/simple.css +60 -60
  20. data/lib/reveal/templates/revealjs/css/theme/sky.css +59 -62
  21. data/lib/reveal/templates/revealjs/css/theme/solarized.css +59 -62
  22. data/lib/reveal/templates/revealjs/css/theme/white.css +59 -62
  23. data/lib/reveal/templates/revealjs/index.html +14 -376
  24. data/lib/reveal/templates/revealjs/js/reveal.js +1073 -342
  25. data/lib/reveal/templates/revealjs/lib/css/zenburn.css +41 -78
  26. data/lib/reveal/templates/revealjs/lib/js/head.min.js +9 -8
  27. data/lib/reveal/templates/revealjs/plugin/highlight/highlight.js +51 -4
  28. data/lib/reveal/templates/revealjs/plugin/markdown/markdown.js +38 -19
  29. data/lib/reveal/templates/revealjs/plugin/markdown/marked.js +1 -1
  30. data/lib/reveal/templates/revealjs/plugin/math/math.js +5 -2
  31. data/lib/reveal/templates/revealjs/plugin/multiplex/client.js +1 -1
  32. data/lib/reveal/templates/revealjs/plugin/multiplex/index.js +24 -16
  33. data/lib/reveal/templates/revealjs/plugin/multiplex/master.js +26 -43
  34. data/lib/reveal/templates/revealjs/plugin/multiplex/package.json +19 -0
  35. data/lib/reveal/templates/revealjs/plugin/notes/notes.html +385 -32
  36. data/lib/reveal/templates/revealjs/plugin/notes/notes.js +39 -6
  37. data/lib/reveal/templates/revealjs/plugin/notes-server/client.js +6 -1
  38. data/lib/reveal/templates/revealjs/plugin/notes-server/index.js +17 -14
  39. data/lib/reveal/templates/revealjs/plugin/notes-server/notes.html +215 -26
  40. data/lib/reveal/templates/revealjs/plugin/print-pdf/print-pdf.js +48 -27
  41. data/lib/reveal/templates/revealjs/plugin/search/search.js +41 -31
  42. data/lib/reveal/templates/revealjs/plugin/zoom-js/zoom.js +17 -23
  43. data/lib/reveal/templates/template.html +12 -41
  44. data/lib/reveal/version.rb +1 -1
  45. data/spec/lib/reveal/command_spec.rb +37 -0
  46. metadata +14 -16
  47. data/lib/reveal/templates/revealjs/lib/font/league-gothic/LICENSE +0 -2
  48. data/lib/reveal/templates/revealjs/lib/font/source-sans-pro/LICENSE +0 -45
  49. data/lib/reveal/templates/revealjs/plugin/leap/leap.js +0 -159
  50. data/lib/reveal/templates/revealjs/plugin/remotes/remotes.js +0 -39
@@ -1,39 +1,42 @@
1
+ var http = require('http');
1
2
  var express = require('express');
2
3
  var fs = require('fs');
3
4
  var io = require('socket.io');
4
- var _ = require('underscore');
5
5
  var Mustache = require('mustache');
6
6
 
7
- var app = express.createServer();
7
+ var app = express();
8
8
  var staticDir = express.static;
9
+ var server = http.createServer(app);
9
10
 
10
- io = io.listen(app);
11
+ io = io(server);
11
12
 
12
13
  var opts = {
13
14
  port : 1947,
14
15
  baseDir : __dirname + '/../../'
15
16
  };
16
17
 
17
- io.sockets.on( 'connection', function( socket ) {
18
+ io.on( 'connection', function( socket ) {
18
19
 
19
- socket.on( 'connect', function( data ) {
20
- socket.broadcast.emit( 'connect', data );
20
+ socket.on( 'new-subscriber', function( data ) {
21
+ socket.broadcast.emit( 'new-subscriber', data );
21
22
  });
22
23
 
23
24
  socket.on( 'statechanged', function( data ) {
25
+ delete data.state.overview;
24
26
  socket.broadcast.emit( 'statechanged', data );
25
27
  });
26
28
 
27
- });
28
-
29
- app.configure( function() {
30
-
31
- [ 'css', 'js', 'images', 'plugin', 'lib' ].forEach( function( dir ) {
32
- app.use( '/' + dir, staticDir( opts.baseDir + dir ) );
29
+ socket.on( 'statechanged-speaker', function( data ) {
30
+ delete data.state.overview;
31
+ socket.broadcast.emit( 'statechanged-speaker', data );
33
32
  });
34
33
 
35
34
  });
36
35
 
36
+ [ 'css', 'js', 'images', 'plugin', 'lib' ].forEach( function( dir ) {
37
+ app.use( '/' + dir, staticDir( opts.baseDir + dir ) );
38
+ });
39
+
37
40
  app.get('/', function( req, res ) {
38
41
 
39
42
  res.writeHead( 200, { 'Content-Type': 'text/html' } );
@@ -52,7 +55,7 @@ app.get( '/notes/:socketId', function( req, res ) {
52
55
  });
53
56
 
54
57
  // Actually listen
55
- app.listen( opts.port || null );
58
+ server.listen( opts.port || null );
56
59
 
57
60
  var brown = '\033[33m',
58
61
  green = '\033[32m',
@@ -62,5 +65,5 @@ var slidesLocation = 'http://localhost' + ( opts.port ? ( ':' + opts.port ) : ''
62
65
 
63
66
  console.log( brown + 'reveal.js - Speaker Notes' + reset );
64
67
  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' );
68
+ console.log( '2. Click on the link in your JS console to go to the notes page' );
66
69
  console.log( '3. Advance through your slides and your notes will advance automatically' );
@@ -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
- color: rgba( 255, 255, 255, 0.9 );
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: 65%;
53
+ width: 60%;
42
54
  height: 100%;
43
55
  top: 0;
44
56
  left: 0;
@@ -47,19 +59,20 @@
47
59
 
48
60
  #upcoming-slide {
49
61
  position: absolute;
50
- width: 35%;
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: 35%;
73
+ width: 40%;
61
74
  height: 60%;
62
-
75
+ overflow: auto;
63
76
  font-size: 18px;
64
77
  }
65
78
 
@@ -124,26 +137,108 @@
124
137
  font-size: 1.2em;
125
138
  }
126
139
 
140
+ /* Layout selector */
141
+ #speaker-layout {
142
+ position: absolute;
143
+ top: 10px;
144
+ right: 10px;
145
+ color: #222;
146
+ z-index: 10;
147
+ }
148
+ #speaker-layout select {
149
+ position: absolute;
150
+ width: 100%;
151
+ height: 100%;
152
+ top: 0;
153
+ left: 0;
154
+ border: 0;
155
+ box-shadow: 0;
156
+ cursor: pointer;
157
+ opacity: 0;
158
+
159
+ font-size: 1em;
160
+ background-color: transparent;
161
+
162
+ -moz-appearance: none;
163
+ -webkit-appearance: none;
164
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
165
+ }
166
+
167
+ #speaker-layout select:focus {
168
+ outline: none;
169
+ box-shadow: none;
170
+ }
171
+
127
172
  .clear {
128
173
  clear: both;
129
174
  }
130
175
 
131
- @media screen and (max-width: 1080px) {
132
- #speaker-controls {
133
- font-size: 16px;
134
- }
176
+ /* Speaker layout: Wide */
177
+ body[data-speaker-layout="wide"] #current-slide,
178
+ body[data-speaker-layout="wide"] #upcoming-slide {
179
+ width: 50%;
180
+ height: 45%;
181
+ padding: 6px;
135
182
  }
136
183
 
137
- @media screen and (max-width: 900px) {
138
- #speaker-controls {
139
- font-size: 14px;
140
- }
184
+ body[data-speaker-layout="wide"] #current-slide {
185
+ top: 0;
186
+ left: 0;
141
187
  }
142
188
 
143
- @media screen and (max-width: 800px) {
144
- #speaker-controls {
145
- font-size: 12px;
146
- }
189
+ body[data-speaker-layout="wide"] #upcoming-slide {
190
+ top: 0;
191
+ left: 50%;
192
+ }
193
+
194
+ body[data-speaker-layout="wide"] #speaker-controls {
195
+ top: 45%;
196
+ left: 0;
197
+ width: 100%;
198
+ height: 50%;
199
+ font-size: 1.25em;
200
+ }
201
+
202
+ /* Speaker layout: Tall */
203
+ body[data-speaker-layout="tall"] #current-slide,
204
+ body[data-speaker-layout="tall"] #upcoming-slide {
205
+ width: 45%;
206
+ height: 50%;
207
+ padding: 6px;
208
+ }
209
+
210
+ body[data-speaker-layout="tall"] #current-slide {
211
+ top: 0;
212
+ left: 0;
213
+ }
214
+
215
+ body[data-speaker-layout="tall"] #upcoming-slide {
216
+ top: 50%;
217
+ left: 0;
218
+ }
219
+
220
+ body[data-speaker-layout="tall"] #speaker-controls {
221
+ padding-top: 40px;
222
+ top: 0;
223
+ left: 45%;
224
+ width: 55%;
225
+ height: 100%;
226
+ font-size: 1.25em;
227
+ }
228
+
229
+ /* Speaker layout: Notes only */
230
+ body[data-speaker-layout="notes-only"] #current-slide,
231
+ body[data-speaker-layout="notes-only"] #upcoming-slide {
232
+ display: none;
233
+ }
234
+
235
+ body[data-speaker-layout="notes-only"] #speaker-controls {
236
+ padding-top: 40px;
237
+ top: 0;
238
+ left: 0;
239
+ width: 100%;
240
+ height: 100%;
241
+ font-size: 1.25em;
147
242
  }
148
243
 
149
244
  </style>
@@ -152,7 +247,7 @@
152
247
  <body>
153
248
 
154
249
  <div id="current-slide"></div>
155
- <div id="upcoming-slide"><span class="label">UPCOMING:</span></div>
250
+ <div id="upcoming-slide"><span class="overlay-element label">Upcoming</span></div>
156
251
  <div id="speaker-controls">
157
252
  <div class="speaker-controls-time">
158
253
  <h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
@@ -170,6 +265,10 @@
170
265
  <div class="value"></div>
171
266
  </div>
172
267
  </div>
268
+ <div id="speaker-layout" class="overlay-element interactive">
269
+ <span class="speaker-layout-label"></span>
270
+ <select class="speaker-layout-dropdown"></select>
271
+ </div>
173
272
 
174
273
  <script src="/socket.io/socket.io.js"></script>
175
274
  <script src="/plugin/markdown/marked.js"></script>
@@ -182,11 +281,20 @@
182
281
  currentState,
183
282
  currentSlide,
184
283
  upcomingSlide,
284
+ layoutLabel,
285
+ layoutDropdown,
185
286
  connected = false;
186
287
 
187
288
  var socket = io.connect( window.location.origin ),
188
289
  socketId = '{{socketId}}';
189
290
 
291
+ var SPEAKER_LAYOUTS = {
292
+ 'default': 'Default',
293
+ 'wide': 'Wide',
294
+ 'tall': 'Tall',
295
+ 'notes-only': 'Notes only'
296
+ };
297
+
190
298
  socket.on( 'statechanged', function( data ) {
191
299
 
192
300
  // ignore data from sockets that aren't ours
@@ -195,7 +303,6 @@
195
303
  if( connected === false ) {
196
304
  connected = true;
197
305
 
198
- setupIframes( data );
199
306
  setupKeyboard();
200
307
  setupNotes();
201
308
  setupTimer();
@@ -206,13 +313,28 @@
206
313
 
207
314
  } );
208
315
 
316
+ setupLayout();
317
+
318
+ // Load our presentation iframes
319
+ setupIframes();
320
+
321
+ // Once the iframes have loaded, emit a signal saying there's
322
+ // a new subscriber which will trigger a 'statechanged'
323
+ // message to be sent back
209
324
  window.addEventListener( 'message', function( event ) {
210
325
 
211
326
  var data = JSON.parse( event.data );
212
327
 
213
328
  if( data && data.namespace === 'reveal' ) {
214
329
  if( /ready/.test( data.eventName ) ) {
215
- socket.emit( 'connect', { socketId: socketId } );
330
+ socket.emit( 'new-subscriber', { socketId: socketId } );
331
+ }
332
+ }
333
+
334
+ // Messages sent by reveal.js inside of the current slide preview
335
+ if( data && data.namespace === 'reveal' ) {
336
+ if( /slidechanged|fragmentshown|fragmenthidden|overviewshown|overviewhidden|paused|resumed/.test( data.eventName ) && currentState !== JSON.stringify( data.state ) ) {
337
+ socket.emit( 'statechanged-speaker', { state: data.state } );
216
338
  }
217
339
  }
218
340
 
@@ -267,7 +389,7 @@
267
389
  /**
268
390
  * Creates the preview iframes.
269
391
  */
270
- function setupIframes( data ) {
392
+ function setupIframes() {
271
393
 
272
394
  var params = [
273
395
  'receiver',
@@ -277,9 +399,8 @@
277
399
  'backgroundTransition=none'
278
400
  ].join( '&' );
279
401
 
280
- var hash = '#/' + data.state.indexh + '/' + data.state.indexv;
281
- var currentURL = '/?' + params + '&postMessageEvents=true' + hash;
282
- var upcomingURL = '/?' + params + '&controls=false' + hash;
402
+ var currentURL = '/?' + params + '&postMessageEvents=true';
403
+ var upcomingURL = '/?' + params + '&controls=false';
283
404
 
284
405
  currentSlide = document.createElement( 'iframe' );
285
406
  currentSlide.setAttribute( 'width', 1280 );
@@ -351,6 +472,74 @@
351
472
 
352
473
  }
353
474
 
475
+ /**
476
+ * Sets up the speaker view layout and layout selector.
477
+ */
478
+ function setupLayout() {
479
+
480
+ layoutDropdown = document.querySelector( '.speaker-layout-dropdown' );
481
+ layoutLabel = document.querySelector( '.speaker-layout-label' );
482
+
483
+ // Render the list of available layouts
484
+ for( var id in SPEAKER_LAYOUTS ) {
485
+ var option = document.createElement( 'option' );
486
+ option.setAttribute( 'value', id );
487
+ option.textContent = SPEAKER_LAYOUTS[ id ];
488
+ layoutDropdown.appendChild( option );
489
+ }
490
+
491
+ // Monitor the dropdown for changes
492
+ layoutDropdown.addEventListener( 'change', function( event ) {
493
+
494
+ setLayout( layoutDropdown.value );
495
+
496
+ }, false );
497
+
498
+ // Restore any currently persisted layout
499
+ setLayout( getLayout() );
500
+
501
+ }
502
+
503
+ /**
504
+ * Sets a new speaker view layout. The layout is persisted
505
+ * in local storage.
506
+ */
507
+ function setLayout( value ) {
508
+
509
+ var title = SPEAKER_LAYOUTS[ value ];
510
+
511
+ layoutLabel.innerHTML = 'Layout' + ( title ? ( ': ' + title ) : '' );
512
+ layoutDropdown.value = value;
513
+
514
+ document.body.setAttribute( 'data-speaker-layout', value );
515
+
516
+ // Persist locally
517
+ if( window.localStorage ) {
518
+ window.localStorage.setItem( 'reveal-speaker-layout', value );
519
+ }
520
+
521
+ }
522
+
523
+ /**
524
+ * Returns the ID of the most recently set speaker layout
525
+ * or our default layout if none has been set.
526
+ */
527
+ function getLayout() {
528
+
529
+ if( window.localStorage ) {
530
+ var layout = window.localStorage.getItem( 'reveal-speaker-layout' );
531
+ if( layout ) {
532
+ return layout;
533
+ }
534
+ }
535
+
536
+ // Default to the first record in the layouts hash
537
+ for( var id in SPEAKER_LAYOUTS ) {
538
+ return id;
539
+ }
540
+
541
+ }
542
+
354
543
  function zeroPadInteger( num ) {
355
544
 
356
545
  var str = '00' + parseInt( num );
@@ -2,32 +2,18 @@
2
2
  * phantomjs script for printing presentations to PDF.
3
3
  *
4
4
  * Example:
5
- * phantomjs print-pdf.js "http://lab.hakim.se/reveal-js?print-pdf" reveal-demo.pdf
5
+ * phantomjs print-pdf.js "http://revealjs.com?print-pdf" reveal-demo.pdf
6
6
  *
7
- * By Manuel Bieh (https://github.com/manuelbieh)
7
+ * @author Manuel Bieh (https://github.com/manuelbieh)
8
+ * @author Hakim El Hattab (https://github.com/hakimel)
9
+ * @author Manuel Riezebosch (https://github.com/riezebosch)
8
10
  */
9
11
 
10
12
  // html2pdf.js
11
- var page = new WebPage();
12
13
  var system = require( 'system' );
13
14
 
14
- var slideWidth = system.args[3] ? system.args[3].split( 'x' )[0] : 960;
15
- var slideHeight = system.args[3] ? system.args[3].split( 'x' )[1] : 700;
16
-
17
- page.viewportSize = {
18
- width: slideWidth,
19
- height: slideHeight
20
- };
21
-
22
- // TODO
23
- // Something is wrong with these config values. An input
24
- // paper width of 1920px actually results in a 756px wide
25
- // PDF.
26
- page.paperSize = {
27
- width: Math.round( slideWidth * 2 ),
28
- height: Math.round( slideHeight * 2 ),
29
- border: 0
30
- };
15
+ var probePage = new WebPage();
16
+ var printPage = new WebPage();
31
17
 
32
18
  var inputFile = system.args[1] || 'index.html?print-pdf';
33
19
  var outputFile = system.args[2] || 'slides.pdf';
@@ -36,13 +22,48 @@ if( outputFile.match( /\.pdf$/gi ) === null ) {
36
22
  outputFile += '.pdf';
37
23
  }
38
24
 
39
- console.log( 'Printing PDF (Paper size: '+ page.paperSize.width + 'x' + page.paperSize.height +')' );
25
+ console.log( 'Export PDF: Reading reveal.js config [1/4]' );
26
+
27
+ probePage.open( inputFile, function( status ) {
28
+
29
+ console.log( 'Export PDF: Preparing print layout [2/4]' );
30
+
31
+ var config = probePage.evaluate( function() {
32
+ return Reveal.getConfig();
33
+ } );
34
+
35
+ if( config ) {
40
36
 
41
- page.open( inputFile, function( status ) {
42
- window.setTimeout( function() {
43
- console.log( 'Printed succesfully' );
44
- page.render( outputFile );
45
- phantom.exit();
46
- }, 1000 );
37
+ printPage.paperSize = {
38
+ width: Math.floor( config.width * ( 1 + config.margin ) ),
39
+ height: Math.floor( config.height * ( 1 + config.margin ) ),
40
+ border: 0
41
+ };
42
+
43
+ printPage.open( inputFile, function( status ) {
44
+ console.log( 'Export PDF: Preparing pdf [3/4]')
45
+ printPage.evaluate(function() {
46
+ Reveal.isReady() ? window.callPhantom() : Reveal.addEventListener( 'pdf-ready', window.callPhantom );
47
+ });
48
+ } );
49
+
50
+ printPage.onCallback = function(data) {
51
+ // For some reason we need to "jump the queue" for syntax highlighting to work.
52
+ // See: http://stackoverflow.com/a/3580132/129269
53
+ setTimeout(function() {
54
+ console.log( 'Export PDF: Writing file [4/4]' );
55
+ printPage.render( outputFile );
56
+ console.log( 'Export PDF: Finished successfully!' );
57
+ phantom.exit();
58
+ }, 0);
59
+ };
60
+ }
61
+ else {
62
+
63
+ console.log( 'Export PDF: Unable to read reveal.js config. Make sure the input address points to a reveal.js page.' );
64
+ phantom.exit(1);
65
+
66
+ }
47
67
  } );
48
68
 
69
+
@@ -21,7 +21,7 @@ function Hilitor(id, tag)
21
21
 
22
22
  var targetNode = document.getElementById(id) || document.body;
23
23
  var hiliteTag = tag || "EM";
24
- var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM|SPAN)$");
24
+ var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$");
25
25
  var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"];
26
26
  var wordColor = [];
27
27
  var colorIdx = 0;
@@ -53,11 +53,11 @@ function Hilitor(id, tag)
53
53
  if(node.nodeType == 3) { // NODE_TEXT
54
54
  if((nv = node.nodeValue) && (regs = matchRegex.exec(nv))) {
55
55
  //find the slide's section element and save it in our list of matching slides
56
- var secnode = node.parentNode;
57
- while (secnode.nodeName != 'SECTION') {
56
+ var secnode = node;
57
+ while (secnode != null && secnode.nodeName != 'SECTION') {
58
58
  secnode = secnode.parentNode;
59
59
  }
60
-
60
+
61
61
  var slideIndex = Reveal.getIndices(secnode);
62
62
  var slidelen = matchingSlides.length;
63
63
  var alreadyAdded = false;
@@ -69,7 +69,7 @@ function Hilitor(id, tag)
69
69
  if (! alreadyAdded) {
70
70
  matchingSlides.push(slideIndex);
71
71
  }
72
-
72
+
73
73
  if(!wordColor[regs[0].toLowerCase()]) {
74
74
  wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length];
75
75
  }
@@ -110,20 +110,26 @@ function Hilitor(id, tag)
110
110
 
111
111
  function openSearch() {
112
112
  //ensure the search term input dialog is visible and has focus:
113
+ var inputboxdiv = document.getElementById("searchinputdiv");
113
114
  var inputbox = document.getElementById("searchinput");
114
- inputbox.style.display = "inline";
115
+ inputboxdiv.style.display = "inline";
115
116
  inputbox.focus();
116
117
  inputbox.select();
117
118
  }
118
119
 
120
+ function closeSearch() {
121
+ var inputboxdiv = document.getElementById("searchinputdiv");
122
+ inputboxdiv.style.display = "none";
123
+ if(myHilitor) myHilitor.remove();
124
+ }
125
+
119
126
  function toggleSearch() {
120
- var inputbox = document.getElementById("searchinput");
121
- if (inputbox.style.display !== "inline") {
127
+ var inputboxdiv = document.getElementById("searchinputdiv");
128
+ if (inputboxdiv.style.display !== "inline") {
122
129
  openSearch();
123
130
  }
124
131
  else {
125
- inputbox.style.display = "none";
126
- myHilitor.remove();
132
+ closeSearch();
127
133
  }
128
134
  }
129
135
 
@@ -132,19 +138,27 @@ function Hilitor(id, tag)
132
138
  if (searchboxDirty) {
133
139
  var searchstring = document.getElementById("searchinput").value;
134
140
 
135
- //find the keyword amongst the slides
136
- myHilitor = new Hilitor("slidecontent");
137
- matchedSlides = myHilitor.apply(searchstring);
138
- currentMatchedIndex = 0;
141
+ if (searchstring === '') {
142
+ if(myHilitor) myHilitor.remove();
143
+ matchedSlides = null;
144
+ }
145
+ else {
146
+ //find the keyword amongst the slides
147
+ myHilitor = new Hilitor("slidecontent");
148
+ matchedSlides = myHilitor.apply(searchstring);
149
+ currentMatchedIndex = 0;
150
+ }
139
151
  }
140
152
 
141
- //navigate to the next slide that has the keyword, wrapping to the first if necessary
142
- if (matchedSlides.length && (matchedSlides.length <= currentMatchedIndex)) {
143
- currentMatchedIndex = 0;
144
- }
145
- if (matchedSlides.length > currentMatchedIndex) {
146
- Reveal.slide(matchedSlides[currentMatchedIndex].h, matchedSlides[currentMatchedIndex].v);
147
- currentMatchedIndex++;
153
+ if (matchedSlides) {
154
+ //navigate to the next slide that has the keyword, wrapping to the first if necessary
155
+ if (matchedSlides.length && (matchedSlides.length <= currentMatchedIndex)) {
156
+ currentMatchedIndex = 0;
157
+ }
158
+ if (matchedSlides.length > currentMatchedIndex) {
159
+ Reveal.slide(matchedSlides[currentMatchedIndex].h, matchedSlides[currentMatchedIndex].v);
160
+ currentMatchedIndex++;
161
+ }
148
162
  }
149
163
  }
150
164
 
@@ -157,7 +171,8 @@ function Hilitor(id, tag)
157
171
  searchElement.classList.add( 'searchdiv' );
158
172
  searchElement.style.position = 'absolute';
159
173
  searchElement.style.top = '10px';
160
- searchElement.style.left = '10px';
174
+ searchElement.style.right = '10px';
175
+ searchElement.style.zIndex = 10;
161
176
  //embedded base64 search icon Designed by Sketchdock - http://www.sketchdock.com/:
162
177
  searchElement.innerHTML = '<span><input type="search" id="searchinput" class="searchinput" style="vertical-align: top;"/><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJiSURBVHjatFZNaxNBGH5md+Mmu92NVdKDRipSAyqCghgQD4L4cRe86UUtAQ+eFCxoa4/25EXBFi8eBE+eRPoDhB6KgiiixdAPCEkx2pjvTXadd9yNsflwuyUDD/O+u8PzzDPvzOwyx3EwyCZhwG3gAkp7MnpjgbopjsltcD4gjuXZZKeAR348MYLYTm3LzOs/y3j3JTfZxgXWXmTuwPHIc4VmoOmv5IrI53+AO2DdHLjkDWQ3GoEEVFXtXQOvkSnPWcyUceviLhwbDYv8/XIVj97kse7TodLvZXxYxrPUHkQ1ufXs3FEdybEIxucySOesoNvUgWU1cP3MkCBfTFdw9fGaAMVmRELq7LBw2Q3/FaAxxWIRpw+ZIr/7IouPqzUBiqmdHAv7EuhRAwf1er2Vy4x1jW3b2d5Jfvu5IPp7l2LYbcgCFFNb+FoJ7oBqEAqFMPNqFcmEgVMJDfMT+1tvN0pNjERlMS6QA5pFOKxiKVPFhakPeL3It+WGJUDxt2wFR+JhzI7v5ctkd8DXOZAkCYYxhO+lKm4+Xfqz/rIixBuNBl7eOYzkQQNzqX249mRl6zUgEcYkaJrGhUwBinVdh6IouPzwE6/DL5w4oLkH8y981aDf+uq6hlKpJESiUdNfDZi7/ehG9K6KfiA3pml0PLcsq+cSMTj2NL9ukc4UOmz7AZ3+crkC4mHujFvXNaMFB3bEr8xPS6p5O+jXxq4VZtaen7/PwzrntjcLUE0iHPS1Ud1cdiEJl/8WivZk0wXd7zWOMkeF8s0CcAmkNrC2nvXZDbbbN73ccYnZoH9bfgswAFzAe9/h3dbKAAAAAElFTkSuQmCC" id="searchbutton" class="searchicon" style="vertical-align: top; margin-top: -1px;"/></span>';
163
178
  dom.wrapper.appendChild( searchElement );
@@ -179,18 +194,13 @@ function Hilitor(id, tag)
179
194
  }
180
195
  }, false );
181
196
 
182
- // Open the search when the 's' key is hit (yes, this conflicts with the notes plugin, disabling for now)
183
- /*
184
197
  document.addEventListener( 'keydown', function( event ) {
185
- // Disregard the event if the target is editable or a
186
- // modifier is present
187
- if ( document.querySelector( ':focus' ) !== null || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return;
188
-
189
- if( event.keyCode === 83 ) {
198
+ if( event.key == "F" && (event.ctrlKey || event.metaKey) ) {//Control+Shift+f
190
199
  event.preventDefault();
191
- openSearch();
200
+ toggleSearch();
192
201
  }
193
202
  }, false );
194
- */
203
+ if( window.Reveal ) Reveal.registerKeyboardShortcut( 'Ctrl-Shift-F', 'Search' );
204
+ closeSearch();
195
205
  return { open: openSearch };
196
206
  })();