slide_hero 0.0.8 → 0.0.9

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/README.md +1 -1
  4. data/lib/slide_hero/version.rb +1 -1
  5. data/lib/slide_hero/views/layout.html.erb +2 -2
  6. data/vendor/reveal.js/.gitignore +3 -1
  7. data/vendor/reveal.js/.travis.yml +1 -1
  8. data/vendor/reveal.js/CONTRIBUTING.md +19 -0
  9. data/vendor/reveal.js/Gruntfile.js +58 -21
  10. data/vendor/reveal.js/LICENSE +1 -1
  11. data/vendor/reveal.js/README.md +154 -74
  12. data/vendor/reveal.js/css/print/paper.css +193 -167
  13. data/vendor/reveal.js/css/print/pdf.css +20 -53
  14. data/vendor/reveal.js/css/reveal.css +912 -1651
  15. data/vendor/reveal.js/css/reveal.scss +1316 -0
  16. data/vendor/reveal.js/css/theme/README.md +1 -1
  17. data/vendor/reveal.js/css/theme/beige.css +177 -60
  18. data/vendor/reveal.js/css/theme/black.css +261 -0
  19. data/vendor/reveal.js/css/theme/blood.css +191 -75
  20. data/vendor/reveal.js/css/theme/league.css +267 -0
  21. data/vendor/reveal.js/css/theme/moon.css +168 -51
  22. data/vendor/reveal.js/css/theme/night.css +165 -42
  23. data/vendor/reveal.js/css/theme/serif.css +181 -58
  24. data/vendor/reveal.js/css/theme/simple.css +173 -50
  25. data/vendor/reveal.js/css/theme/sky.css +170 -47
  26. data/vendor/reveal.js/css/theme/solarized.css +168 -51
  27. data/vendor/reveal.js/css/theme/source/beige.scss +1 -12
  28. data/vendor/reveal.js/css/theme/source/black.scss +49 -0
  29. data/vendor/reveal.js/css/theme/source/blood.scss +4 -4
  30. data/vendor/reveal.js/css/theme/source/{default.scss → league.scss} +5 -13
  31. data/vendor/reveal.js/css/theme/source/moon.scss +1 -12
  32. data/vendor/reveal.js/css/theme/source/serif.scss +1 -1
  33. data/vendor/reveal.js/css/theme/source/sky.scss +1 -1
  34. data/vendor/reveal.js/css/theme/source/solarized.scss +1 -12
  35. data/vendor/reveal.js/css/theme/source/white.scss +49 -0
  36. data/vendor/reveal.js/css/theme/template/settings.scss +13 -4
  37. data/vendor/reveal.js/css/theme/template/theme.scss +182 -13
  38. data/vendor/reveal.js/css/theme/white.css +261 -0
  39. data/vendor/reveal.js/index.html +198 -178
  40. data/vendor/reveal.js/js/reveal.js +1286 -392
  41. data/vendor/reveal.js/lib/css/zenburn.css +74 -71
  42. data/vendor/reveal.js/lib/font/{league_gothic_license → league-gothic/LICENSE} +0 -0
  43. data/vendor/reveal.js/lib/font/league-gothic/league-gothic.css +10 -0
  44. data/vendor/reveal.js/lib/font/league-gothic/league-gothic.eot +0 -0
  45. data/vendor/reveal.js/lib/font/league-gothic/league-gothic.ttf +0 -0
  46. data/vendor/reveal.js/lib/font/league-gothic/league-gothic.woff +0 -0
  47. data/vendor/reveal.js/lib/font/source-sans-pro/LICENSE +45 -0
  48. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.eot +0 -0
  49. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.ttf +0 -0
  50. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.woff +0 -0
  51. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.eot +0 -0
  52. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.ttf +0 -0
  53. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.woff +0 -0
  54. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.eot +0 -0
  55. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.ttf +0 -0
  56. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.woff +0 -0
  57. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.eot +0 -0
  58. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.ttf +0 -0
  59. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.woff +0 -0
  60. data/vendor/reveal.js/lib/font/source-sans-pro/source-sans-pro.css +39 -0
  61. data/vendor/reveal.js/package.json +9 -7
  62. data/vendor/reveal.js/plugin/highlight/highlight.js +2 -4
  63. data/vendor/reveal.js/plugin/leap/leap.js +4 -2
  64. data/vendor/reveal.js/plugin/markdown/example.html +2 -2
  65. data/vendor/reveal.js/plugin/markdown/markdown.js +8 -7
  66. data/vendor/reveal.js/plugin/notes/notes.html +321 -182
  67. data/vendor/reveal.js/plugin/notes/notes.js +89 -45
  68. data/vendor/reveal.js/plugin/notes-server/client.js +49 -46
  69. data/vendor/reveal.js/plugin/notes-server/index.js +28 -21
  70. data/vendor/reveal.js/plugin/notes-server/notes.html +351 -97
  71. data/vendor/reveal.js/plugin/print-pdf/print-pdf.js +24 -20
  72. data/vendor/reveal.js/plugin/zoom-js/zoom.js +77 -57
  73. data/vendor/reveal.js/test/examples/barebones.html +2 -2
  74. data/vendor/reveal.js/test/examples/embedded-media.html +2 -2
  75. data/vendor/reveal.js/test/examples/math.html +2 -2
  76. data/vendor/reveal.js/test/examples/slide-backgrounds.html +29 -7
  77. data/vendor/reveal.js/test/test-markdown-element-attributes.html +6 -6
  78. data/vendor/reveal.js/test/test-markdown-slide-attributes.html +7 -7
  79. data/vendor/reveal.js/test/test-markdown.html +4 -4
  80. data/vendor/reveal.js/test/test-pdf.html +83 -0
  81. data/vendor/reveal.js/test/test-pdf.js +15 -0
  82. data/vendor/reveal.js/test/test.html +5 -4
  83. data/vendor/reveal.js/test/test.js +143 -9
  84. metadata +31 -13
  85. data/vendor/reveal.js/css/reveal.min.css +0 -7
  86. data/vendor/reveal.js/css/theme/default.css +0 -148
  87. data/vendor/reveal.js/js/reveal.min.js +0 -9
  88. data/vendor/reveal.js/lib/font/league_gothic-webfont.eot +0 -0
  89. data/vendor/reveal.js/lib/font/league_gothic-webfont.svg +0 -230
  90. data/vendor/reveal.js/lib/font/league_gothic-webfont.ttf +0 -0
  91. data/vendor/reveal.js/lib/font/league_gothic-webfont.woff +0 -0
  92. data/vendor/reveal.js/plugin/postmessage/example.html +0 -39
  93. data/vendor/reveal.js/plugin/postmessage/postmessage.js +0 -42
@@ -76,8 +76,10 @@ var b=right.criteria;if(a!==b){if(a>b||a===void 0)return 1;if(a<b||b===void 0)re
76
76
  pointer.style.borderRadius = size - 5 + 'px';
77
77
  pointer.style.visibility = 'visible';
78
78
 
79
+ tipPosition = frame.fingers[0].tipPosition;
80
+
79
81
  if( config.autoCenter ) {
80
- tipPosition = frame.fingers[0].tipPosition;
82
+
81
83
 
82
84
  // Check whether the finger has entered the z range of the Leap Motion. Used for the autoCenter option.
83
85
  if( !entered ) {
@@ -144,7 +146,7 @@ var b=right.criteria;if(a!==b){if(a>b||a===void 0)return 1;if(a<b||b===void 0)re
144
146
  // Two hand gestures
145
147
  else if( frame.hands.length === 2 ) {
146
148
  // Upward two hand swipe gesture
147
- if( gesture.direction[1] > 0 && gesture.type === 'swipe' ) {
149
+ if( gesture.type === 'swipe' && gesture.direction[1] > 0 ) {
148
150
  Reveal.toggleOverview();
149
151
  }
150
152
 
@@ -19,7 +19,7 @@
19
19
  <div class="slides">
20
20
 
21
21
  <!-- Use external markdown resource, separate slides by three newlines; vertical slides by two newlines -->
22
- <section data-markdown="example.md" data-separator="^\n\n\n" data-vertical="^\n\n"></section>
22
+ <section data-markdown="example.md" data-separator="^\n\n\n" data-separator-vertical="^\n\n"></section>
23
23
 
24
24
  <!-- Slides are separated by three dashes (quick 'n dirty regular expression) -->
25
25
  <section data-markdown data-separator="---">
@@ -36,7 +36,7 @@
36
36
  </section>
37
37
 
38
38
  <!-- Slides are separated by newline + three dashes + newline, vertical slides identical but two dashes -->
39
- <section data-markdown data-separator="^\n---\n$" data-vertical="^\n--\n$">
39
+ <section data-markdown data-separator="^\n---\n$" data-separator-vertical="^\n--\n$">
40
40
  <script type="text/template">
41
41
  ## Demo 2
42
42
  Slide 1.1
@@ -50,7 +50,7 @@
50
50
  text = text.replace( new RegExp('\\n?\\t{' + leadingTabs + '}','g'), '\n' );
51
51
  }
52
52
  else if( leadingWs > 1 ) {
53
- text = text.replace( new RegExp('\\n? {' + leadingWs + '}','g'), '\n' );
53
+ text = text.replace( new RegExp('\\n? {' + leadingWs + '}'), '\n' );
54
54
  }
55
55
 
56
56
  return text;
@@ -219,12 +219,13 @@
219
219
 
220
220
  xhr.onreadystatechange = function() {
221
221
  if( xhr.readyState === 4 ) {
222
- if ( xhr.status >= 200 && xhr.status < 300 ) {
222
+ // file protocol yields status code 0 (useful for local debug, mobile applications etc.)
223
+ if ( ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status === 0 ) {
223
224
 
224
225
  section.outerHTML = slidify( xhr.responseText, {
225
226
  separator: section.getAttribute( 'data-separator' ),
226
- verticalSeparator: section.getAttribute( 'data-vertical' ),
227
- notesSeparator: section.getAttribute( 'data-notes' ),
227
+ verticalSeparator: section.getAttribute( 'data-separator-vertical' ),
228
+ notesSeparator: section.getAttribute( 'data-separator-notes' ),
228
229
  attributes: getForwardedAttributes( section )
229
230
  });
230
231
 
@@ -251,12 +252,12 @@
251
252
  }
252
253
 
253
254
  }
254
- else if( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-vertical' ) || section.getAttribute( 'data-notes' ) ) {
255
+ else if( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-separator-vertical' ) || section.getAttribute( 'data-separator-notes' ) ) {
255
256
 
256
257
  section.outerHTML = slidify( getMarkdownFromSlide( section ), {
257
258
  separator: section.getAttribute( 'data-separator' ),
258
- verticalSeparator: section.getAttribute( 'data-vertical' ),
259
- notesSeparator: section.getAttribute( 'data-notes' ),
259
+ verticalSeparator: section.getAttribute( 'data-separator-vertical' ),
260
+ notesSeparator: section.getAttribute( 'data-separator-notes' ),
260
261
  attributes: getForwardedAttributes( section )
261
262
  });
262
263
 
@@ -10,127 +10,141 @@
10
10
  font-family: Helvetica;
11
11
  }
12
12
 
13
- #notes {
14
- font-size: 24px;
15
- width: 640px;
16
- margin-top: 5px;
17
- clear: left;
13
+ #current-slide,
14
+ #upcoming-slide,
15
+ #speaker-controls {
16
+ padding: 6px;
17
+ box-sizing: border-box;
18
+ -moz-box-sizing: border-box;
18
19
  }
19
20
 
20
- #wrap-current-slide {
21
- width: 640px;
22
- height: 512px;
23
- float: left;
24
- overflow: hidden;
21
+ #current-slide iframe,
22
+ #upcoming-slide iframe {
23
+ width: 100%;
24
+ height: 100%;
25
+ border: 1px solid #ddd;
25
26
  }
26
27
 
27
- #current-slide {
28
- width: 1280px;
29
- height: 1024px;
30
- border: none;
31
-
32
- -webkit-transform-origin: 0 0;
33
- -moz-transform-origin: 0 0;
34
- -ms-transform-origin: 0 0;
35
- -o-transform-origin: 0 0;
36
- transform-origin: 0 0;
37
-
38
- -webkit-transform: scale(0.5);
39
- -moz-transform: scale(0.5);
40
- -ms-transform: scale(0.5);
41
- -o-transform: scale(0.5);
42
- transform: scale(0.5);
43
- }
44
-
45
- #wrap-next-slide {
46
- width: 448px;
47
- height: 358px;
48
- float: left;
49
- margin: 0 0 0 10px;
50
- overflow: hidden;
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 );
51
37
  }
52
38
 
53
- #next-slide {
54
- width: 1280px;
55
- height: 1024px;
56
- border: none;
57
-
58
- -webkit-transform-origin: 0 0;
59
- -moz-transform-origin: 0 0;
60
- -ms-transform-origin: 0 0;
61
- -o-transform-origin: 0 0;
62
- transform-origin: 0 0;
63
-
64
- -webkit-transform: scale(0.35);
65
- -moz-transform: scale(0.35);
66
- -ms-transform: scale(0.35);
67
- -o-transform: scale(0.35);
68
- transform: scale(0.35);
39
+ #current-slide {
40
+ position: absolute;
41
+ width: 65%;
42
+ height: 100%;
43
+ top: 0;
44
+ left: 0;
45
+ padding-right: 0;
69
46
  }
70
47
 
71
- .slides {
72
- position: relative;
73
- margin-bottom: 10px;
74
- border: 1px solid black;
75
- border-radius: 2px;
76
- background: rgb(28, 30, 32);
48
+ #upcoming-slide {
49
+ position: absolute;
50
+ width: 35%;
51
+ height: 40%;
52
+ right: 0;
53
+ top: 0;
77
54
  }
78
55
 
79
- .slides span {
56
+ #speaker-controls {
80
57
  position: absolute;
81
- top: 3px;
82
- left: 3px;
83
- font-weight: bold;
84
- font-size: 14px;
85
- color: rgba( 255, 255, 255, 0.9 );
86
- }
58
+ top: 40%;
59
+ right: 0;
60
+ width: 35%;
61
+ height: 60%;
62
+ overflow: auto;
87
63
 
88
- .error {
89
- font-weight: bold;
90
- color: red;
91
- font-size: 1.5em;
92
- text-align: center;
93
- margin-top: 10%;
64
+ font-size: 18px;
94
65
  }
95
66
 
96
- .error code {
97
- font-family: monospace;
98
- }
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
+ }
99
80
 
100
- .time {
101
- width: 448px;
102
- margin: 30px 0 0 10px;
103
- float: left;
104
- text-align: center;
105
- opacity: 0;
106
-
107
- -webkit-transition: opacity 0.4s;
108
- -moz-transition: opacity 0.4s;
109
- -o-transition: opacity 0.4s;
110
- transition: opacity 0.4s;
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;
111
130
  }
112
131
 
113
- .elapsed,
114
- .clock {
115
- color: #333;
116
- font-size: 2em;
117
- text-align: center;
118
- display: inline-block;
119
- padding: 0.5em;
120
- background-color: #eee;
121
- border-radius: 10px;
132
+ @media screen and (max-width: 1080px) {
133
+ #speaker-controls {
134
+ font-size: 16px;
135
+ }
122
136
  }
123
137
 
124
- .elapsed h2,
125
- .clock h2 {
126
- font-size: 0.8em;
127
- line-height: 100%;
128
- margin: 0;
129
- color: #aaa;
138
+ @media screen and (max-width: 900px) {
139
+ #speaker-controls {
140
+ font-size: 14px;
141
+ }
130
142
  }
131
143
 
132
- .elapsed .mute {
133
- color: #ddd;
144
+ @media screen and (max-width: 800px) {
145
+ #speaker-controls {
146
+ font-size: 12px;
147
+ }
134
148
  }
135
149
 
136
150
  </style>
@@ -138,81 +152,183 @@
138
152
 
139
153
  <body>
140
154
 
141
- <script>
142
- function getNotesURL( controls ) {
143
- return window.opener.location.protocol + '//' + window.opener.location.host + window.opener.location.pathname + '?receiver&controls='+ ( controls || 'false' ) +'&progress=false&overview=false' + window.opener.location.hash;
144
- }
145
- var notesCurrentSlideURL = getNotesURL( true );
146
- var notesNextSlideURL = getNotesURL( false );
147
- </script>
148
-
149
- <div id="wrap-current-slide" class="slides">
150
- <script>document.write( '<iframe width="1280" height="1024" id="current-slide" src="'+ notesCurrentSlideURL +'"></iframe>' );</script>
151
- </div>
152
-
153
- <div id="wrap-next-slide" class="slides">
154
- <script>document.write( '<iframe width="640" height="512" id="next-slide" src="'+ notesNextSlideURL +'"></iframe>' );</script>
155
- <span>UPCOMING:</span>
156
- </div>
157
-
158
- <div class="time">
159
- <div class="clock">
160
- <h2>Time</h2>
161
- <span id="clock">0:00:00 AM</span>
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>
162
167
  </div>
163
- <div class="elapsed">
164
- <h2>Elapsed</h2>
165
- <span id="hours">00</span><span id="minutes">:00</span><span id="seconds">:00</span>
168
+
169
+ <div class="speaker-controls-notes hidden">
170
+ <h4 class="label">Notes</h4>
171
+ <div class="value"></div>
166
172
  </div>
167
173
  </div>
168
174
 
169
- <div id="notes"></div>
170
-
171
175
  <script src="../../plugin/markdown/marked.js"></script>
172
176
  <script>
173
177
 
174
- window.addEventListener( 'load', function() {
178
+ (function() {
175
179
 
176
- if( window.opener && window.opener.location && window.opener.location.href ) {
180
+ var notes,
181
+ notesValue,
182
+ currentState,
183
+ currentSlide,
184
+ upcomingSlide,
185
+ connected = false;
177
186
 
178
- var notes = document.getElementById( 'notes' ),
179
- currentSlide = document.getElementById( 'current-slide' ),
180
- nextSlide = document.getElementById( 'next-slide' ),
181
- silenced = false;
187
+ window.addEventListener( 'message', function( event ) {
182
188
 
183
- window.addEventListener( 'message', function( event ) {
184
- var data = JSON.parse( event.data );
189
+ var data = JSON.parse( event.data );
185
190
 
186
- // No need for updating the notes in case of fragment changes
187
- if ( data.notes !== undefined) {
188
- if( data.markdown ) {
189
- notes.innerHTML = marked( data.notes );
190
- }
191
- else {
192
- notes.innerHTML = data.notes;
193
- }
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 );
194
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
+ } );
195
212
 
196
- silenced = true;
213
+ /**
214
+ * Called when the main window is trying to establish a
215
+ * connection.
216
+ */
217
+ function handleConnectMessage( data ) {
197
218
 
198
- // Update the note slides
199
- currentSlide.contentWindow.Reveal.slide( data.indexh, data.indexv, data.indexf );
200
- nextSlide.contentWindow.Reveal.slide( data.nextindexh, data.nextindexv );
219
+ if( connected === false ) {
220
+ connected = true;
201
221
 
202
- silenced = false;
222
+ setupIframes( data );
223
+ setupKeyboard();
224
+ setupNotes();
225
+ setupTimer();
226
+ }
203
227
 
204
- }, false );
228
+ }
205
229
 
206
- var start = new Date(),
207
- timeEl = document.querySelector( '.time' ),
208
- clockEl = document.getElementById( 'clock' ),
209
- hoursEl = document.getElementById( 'hours' ),
210
- minutesEl = document.getElementById( 'minutes' ),
211
- secondsEl = document.getElementById( 'seconds' );
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 );
212
305
 
213
- setInterval( function() {
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() {
214
323
 
215
- timeEl.style.opacity = 1;
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() {
216
332
 
217
333
  var diff, hours, minutes, seconds,
218
334
  now = new Date();
@@ -222,45 +338,68 @@
222
338
  minutes = Math.floor( ( diff / ( 1000 * 60 ) ) % 60 );
223
339
  seconds = Math.floor( ( diff / 1000 ) % 60 );
224
340
 
225
- clockEl.innerHTML = now.toLocaleTimeString();
341
+ clockEl.innerHTML = now.toLocaleTimeString( 'en-US', { hour12: true, hour: '2-digit', minute:'2-digit' } );
226
342
  hoursEl.innerHTML = zeroPadInteger( hours );
227
- hoursEl.className = hours > 0 ? "" : "mute";
228
- minutesEl.innerHTML = ":" + zeroPadInteger( minutes );
229
- minutesEl.className = minutes > 0 ? "" : "mute";
230
- secondsEl.innerHTML = ":" + zeroPadInteger( seconds );
231
-
232
- }, 1000 );
343
+ hoursEl.className = hours > 0 ? '' : 'mute';
344
+ minutesEl.innerHTML = ':' + zeroPadInteger( minutes );
345
+ minutesEl.className = minutes > 0 ? '' : 'mute';
346
+ secondsEl.innerHTML = ':' + zeroPadInteger( seconds );
233
347
 
234
- // Broadcasts the state of the notes window to synchronize
235
- // the main window
236
- function synchronizeMainWindow() {
348
+ }
237
349
 
238
- if( !silenced ) {
239
- var indices = currentSlide.contentWindow.Reveal.getIndices();
240
- window.opener.Reveal.slide( indices.h, indices.v, indices.f );
241
- }
350
+ // Update once directly
351
+ _updateTimer();
242
352
 
243
- }
353
+ // Then update every second
354
+ setInterval( _updateTimer, 1000 );
244
355
 
245
- // Navigate the main window when the notes slide changes
246
- currentSlide.contentWindow.Reveal.addEventListener( 'slidechanged', synchronizeMainWindow );
247
- currentSlide.contentWindow.Reveal.addEventListener( 'fragmentshown', synchronizeMainWindow );
248
- currentSlide.contentWindow.Reveal.addEventListener( 'fragmenthidden', synchronizeMainWindow );
356
+ timeEl.addEventListener( 'click', function() {
357
+ start = new Date();
358
+ _updateTimer();
359
+ return false;
360
+ } );
249
361
 
250
362
  }
251
- else {
252
363
 
253
- document.body.innerHTML = '<p class="error">Unable to access <code>window.opener.location</code>.<br>Make sure the presentation is running on a web server.</p>';
364
+ function zeroPadInteger( num ) {
365
+
366
+ var str = '00' + parseInt( num );
367
+ return str.substring( str.length - 2 );
254
368
 
255
369
  }
256
370
 
371
+ /**
372
+ * Limits the frequency at which a function can be called.
373
+ */
374
+ function debounce( fn, ms ) {
257
375
 
258
- }, false );
376
+ var lastTime = 0,
377
+ timeout;
259
378
 
260
- function zeroPadInteger( num ) {
261
- var str = "00" + parseInt( num );
262
- return str.substring( str.length - 2 );
263
- }
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
+ })();
264
403
 
265
404
  </script>
266
405
  </body>