Ignore rally_conf.json
[functest-xtesting.git] / docs / com / plugin / notes / notes.html
1 <!doctype html>
2 <html lang="en">
3         <head>
4                 <meta charset="utf-8">
5
6                 <title>reveal.js - Slide Notes</title>
7
8                 <style>
9                         body {
10                                 font-family: Helvetica;
11                         }
12
13                         #current-slide,
14                         #upcoming-slide,
15                         #speaker-controls {
16                                 padding: 6px;
17                                 box-sizing: border-box;
18                                 -moz-box-sizing: border-box;
19                         }
20
21                         #current-slide iframe,
22                         #upcoming-slide iframe {
23                                 width: 100%;
24                                 height: 100%;
25                                 border: 1px solid #ddd;
26                         }
27
28                         #current-slide .label,
29                         #upcoming-slide .label {
30                                 position: absolute;
31                                 top: 10px;
32                                 left: 10px;
33                                 font-weight: bold;
34                                 font-size: 14px;
35                                 z-index: 2;
36                                 color: rgba( 255, 255, 255, 0.9 );
37                         }
38
39                         #current-slide {
40                                 position: absolute;
41                                 width: 65%;
42                                 height: 100%;
43                                 top: 0;
44                                 left: 0;
45                                 padding-right: 0;
46                         }
47
48                         #upcoming-slide {
49                                 position: absolute;
50                                 width: 35%;
51                                 height: 40%;
52                                 right: 0;
53                                 top: 0;
54                         }
55
56                         #speaker-controls {
57                                 position: absolute;
58                                 top: 40%;
59                                 right: 0;
60                                 width: 35%;
61                                 height: 60%;
62                                 overflow: auto;
63
64                                 font-size: 18px;
65                         }
66
67                                 .speaker-controls-time.hidden,
68                                 .speaker-controls-notes.hidden {
69                                         display: none;
70                                 }
71
72                                 .speaker-controls-time .label,
73                                 .speaker-controls-notes .label {
74                                         text-transform: uppercase;
75                                         font-weight: normal;
76                                         font-size: 0.66em;
77                                         color: #666;
78                                         margin: 0;
79                                 }
80
81                                 .speaker-controls-time {
82                                         border-bottom: 1px solid rgba( 200, 200, 200, 0.5 );
83                                         margin-bottom: 10px;
84                                         padding: 10px 16px;
85                                         padding-bottom: 20px;
86                                         cursor: pointer;
87                                 }
88
89                                 .speaker-controls-time .reset-button {
90                                         opacity: 0;
91                                         float: right;
92                                         color: #666;
93                                         text-decoration: none;
94                                 }
95                                 .speaker-controls-time:hover .reset-button {
96                                         opacity: 1;
97                                 }
98
99                                 .speaker-controls-time .timer,
100                                 .speaker-controls-time .clock {
101                                         width: 50%;
102                                         font-size: 1.9em;
103                                 }
104
105                                 .speaker-controls-time .timer {
106                                         float: left;
107                                 }
108
109                                 .speaker-controls-time .clock {
110                                         float: right;
111                                         text-align: right;
112                                 }
113
114                                 .speaker-controls-time span.mute {
115                                         color: #bbb;
116                                 }
117
118                                 .speaker-controls-notes {
119                                         padding: 10px 16px;
120                                 }
121
122                                 .speaker-controls-notes .value {
123                                         margin-top: 5px;
124                                         line-height: 1.4;
125                                         font-size: 1.2em;
126                                 }
127
128                         .clear {
129                                 clear: both;
130                         }
131
132                         @media screen and (max-width: 1080px) {
133                                 #speaker-controls {
134                                         font-size: 16px;
135                                 }
136                         }
137
138                         @media screen and (max-width: 900px) {
139                                 #speaker-controls {
140                                         font-size: 14px;
141                                 }
142                         }
143
144                         @media screen and (max-width: 800px) {
145                                 #speaker-controls {
146                                         font-size: 12px;
147                                 }
148                         }
149
150                 </style>
151         </head>
152
153         <body>
154
155                 <div id="current-slide"></div>
156                 <div id="upcoming-slide"><span class="label">UPCOMING:</span></div>
157                 <div id="speaker-controls">
158                         <div class="speaker-controls-time">
159                                 <h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
160                                 <div class="clock">
161                                         <span class="clock-value">0:00 AM</span>
162                                 </div>
163                                 <div class="timer">
164                                         <span class="hours-value">00</span><span class="minutes-value">:00</span><span class="seconds-value">:00</span>
165                                 </div>
166                                 <div class="clear"></div>
167                         </div>
168
169                         <div class="speaker-controls-notes hidden">
170                                 <h4 class="label">Notes</h4>
171                                 <div class="value"></div>
172                         </div>
173                 </div>
174
175                 <script src="../../plugin/markdown/marked.js"></script>
176                 <script>
177
178                         (function() {
179
180                                 var notes,
181                                         notesValue,
182                                         currentState,
183                                         currentSlide,
184                                         upcomingSlide,
185                                         connected = false;
186
187                                 window.addEventListener( 'message', function( event ) {
188
189                                         var data = JSON.parse( event.data );
190
191                                         // Messages sent by the notes plugin inside of the main window
192                                         if( data && data.namespace === 'reveal-notes' ) {
193                                                 if( data.type === 'connect' ) {
194                                                         handleConnectMessage( data );
195                                                 }
196                                                 else if( data.type === 'state' ) {
197                                                         handleStateMessage( data );
198                                                 }
199                                         }
200                                         // Messages sent by the reveal.js inside of the current slide preview
201                                         else if( data && data.namespace === 'reveal' ) {
202                                                 if( /ready/.test( data.eventName ) ) {
203                                                         // Send a message back to notify that the handshake is complete
204                                                         window.opener.postMessage( JSON.stringify({ namespace: 'reveal-notes', type: 'connected'} ), '*' );
205                                                 }
206                                                 else if( /slidechanged|fragmentshown|fragmenthidden|overviewshown|overviewhidden|paused|resumed/.test( data.eventName ) && currentState !== JSON.stringify( data.state ) ) {
207                                                         window.opener.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ]} ), '*' );
208                                                 }
209                                         }
210
211                                 } );
212
213                                 /**
214                                  * Called when the main window is trying to establish a
215                                  * connection.
216                                  */
217                                 function handleConnectMessage( data ) {
218
219                                         if( connected === false ) {
220                                                 connected = true;
221
222                                                 setupIframes( data );
223                                                 setupKeyboard();
224                                                 setupNotes();
225                                                 setupTimer();
226                                         }
227
228                                 }
229
230                                 /**
231                                  * Called when the main window sends an updated state.
232                                  */
233                                 function handleStateMessage( data ) {
234
235                                         // Store the most recently set state to avoid circular loops
236                                         // applying the same state
237                                         currentState = JSON.stringify( data.state );
238
239                                         // No need for updating the notes in case of fragment changes
240                                         if ( data.notes ) {
241                                                 notes.classList.remove( 'hidden' );
242                                                 notesValue.style.whiteSpace = data.whitespace;
243                                                 if( data.markdown ) {
244                                                         notesValue.innerHTML = marked( data.notes );
245                                                 }
246                                                 else {
247                                                         notesValue.innerHTML = data.notes;
248                                                 }
249                                         }
250                                         else {
251                                                 notes.classList.add( 'hidden' );
252                                         }
253
254                                         // Update the note slides
255                                         currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
256                                         upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
257                                         upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'next' }), '*' );
258
259                                 }
260
261                                 // Limit to max one state update per X ms
262                                 handleStateMessage = debounce( handleStateMessage, 200 );
263
264                                 /**
265                                  * Forward keyboard events to the current slide window.
266                                  * This enables keyboard events to work even if focus
267                                  * isn't set on the current slide iframe.
268                                  */
269                                 function setupKeyboard() {
270
271                                         document.addEventListener( 'keydown', function( event ) {
272                                                 currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'triggerKey', args: [ event.keyCode ] }), '*' );
273                                         } );
274
275                                 }
276
277                                 /**
278                                  * Creates the preview iframes.
279                                  */
280                                 function setupIframes( data ) {
281
282                                         var params = [
283                                                 'receiver',
284                                                 'progress=false',
285                                                 'history=false',
286                                                 'transition=none',
287                                                 'autoSlide=0',
288                                                 'backgroundTransition=none'
289                                         ].join( '&' );
290
291                                         var hash = '#/' + data.state.indexh + '/' + data.state.indexv;
292                                         var currentURL = data.url + '?' + params + '&postMessageEvents=true' + hash;
293                                         var upcomingURL = data.url + '?' + params + '&controls=false' + hash;
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
405                 </script>
406         </body>
407 </html>