hyla 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/Rakefile +6 -2
- data/bin/hyla +3 -2
- data/lib/hyla/commands/generate.rb +43 -41
- data/lib/hyla/configuration.rb +1 -1
- data/lib/hyla/project.rb +1 -1
- data/lib/resources/assets/revealjs-redhat/image/collapsed.png +0 -0
- data/lib/resources/assets/revealjs-redhat/image/expanded.png +0 -0
- data/lib/resources/assets/revealjs-redhat/lib/css/conference.css +663 -0
- data/lib/resources/assets/revealjs-redhat/lib/css/font-awesome-4.3.0.css +2886 -1098
- data/lib/resources/assets/revealjs-redhat/lib/css/gpe.css +746 -180
- data/lib/resources/assets/revealjs-redhat/lib/css/print/pdf.css +32 -65
- data/lib/resources/assets/revealjs-redhat/lib/css/theme-output.css +1509 -395
- data/lib/resources/assets/revealjs-redhat/lib/css/theme-v2-liberation.css +4332 -1366
- data/lib/resources/assets/revealjs-redhat/lib/css/theme-v2-overpass.css +4320 -1364
- data/lib/resources/assets/revealjs-redhat/lib/js/debug/gpe.js +8 -8
- data/lib/resources/assets/revealjs-redhat/lib/js/debug/reveal.js +129 -91
- data/lib/resources/assets/revealjs-redhat/lib/js/gpe.min.js +3 -3
- data/lib/resources/assets/revealjs-redhat/lib/js/reveal.min.js +18 -13
- data/lib/resources/assets/revealjs/css/theme/conference-redhat.css +14 -6
- data/lib/resources/assets/revealjs/css/theme/old-gpe.css +670 -181
- data/lib/resources/assets/revealjs/js/{reveal.js → debug/reveal.js} +1619 -492
- data/lib/resources/assets/revealjs/js/reveal.min.js +342 -9
- data/lib/resources/assets/revealjs/lib/css/font-awesome-4.3.0.css +2886 -1098
- data/lib/resources/assets/sass/conference.scss +589 -0
- data/lib/resources/assets/sass/new-gpe.scss +79 -0
- data/lib/resources/backends/slim/revealjs-redhat/block_paragraph.html.slim +18 -6
- data/lib/resources/backends/slim/revealjs-redhat/block_ulist.html.slim +25 -9
- data/lib/resources/backends/slim/revealjs/document.html.slim +1 -1
- data/lib/templates/course/audio.txt +2 -2
- data/lib/templates/course/cover.txt +19 -7
- data/lib/templates/course/footer.txt +1 -3
- data/lib/templates/course/index.txt +2 -2
- data/lib/templates/course/labinstructions.txt +1 -3
- data/lib/templates/course/objectives.txt +1 -12
- data/lib/templates/course/summary.txt +1 -8
- metadata +7 -3
@@ -2,19 +2,36 @@
|
|
2
2
|
* reveal.js
|
3
3
|
* http://lab.hakim.se/reveal-js
|
4
4
|
* MIT licensed
|
5
|
+
* Version 3.1.0
|
5
6
|
*
|
6
|
-
* Copyright (C)
|
7
|
+
* Copyright (C) 2015 Hakim El Hattab, http://hakim.se
|
7
8
|
*/
|
8
|
-
|
9
|
+
(function( root, factory ) {
|
10
|
+
if( typeof define === 'function' && define.amd ) {
|
11
|
+
// AMD. Register as an anonymous module.
|
12
|
+
define( function() {
|
13
|
+
root.Reveal = factory();
|
14
|
+
return root.Reveal;
|
15
|
+
} );
|
16
|
+
} else if( typeof exports === 'object' ) {
|
17
|
+
// Node. Does not work with strict CommonJS.
|
18
|
+
module.exports = factory();
|
19
|
+
} else {
|
20
|
+
// Browser globals.
|
21
|
+
root.Reveal = factory();
|
22
|
+
}
|
23
|
+
}( this, function() {
|
9
24
|
|
10
25
|
'use strict';
|
11
26
|
|
12
|
-
var
|
13
|
-
HORIZONTAL_SLIDES_SELECTOR = '.reveal .slides>section',
|
14
|
-
VERTICAL_SLIDES_SELECTOR = '.reveal .slides>section.present>section',
|
15
|
-
HOME_SLIDE_SELECTOR = '.reveal .slides>section:first-of-type',
|
27
|
+
var Reveal;
|
16
28
|
|
17
|
-
|
29
|
+
var SLIDES_SELECTOR = '.slides section',
|
30
|
+
HORIZONTAL_SLIDES_SELECTOR = '.slides>section',
|
31
|
+
VERTICAL_SLIDES_SELECTOR = '.slides>section.present>section',
|
32
|
+
HOME_SLIDE_SELECTOR = '.slides>section:first-of-type',
|
33
|
+
|
34
|
+
// Configuration defaults, can be overridden at initialization time
|
18
35
|
config = {
|
19
36
|
|
20
37
|
// The "normal" size of the presentation, aspect ratio will be preserved
|
@@ -27,7 +44,7 @@ var Reveal = (function(){
|
|
27
44
|
|
28
45
|
// Bounds for smallest/largest possible scale to apply to content
|
29
46
|
minScale: 0.2,
|
30
|
-
maxScale: 1.
|
47
|
+
maxScale: 1.5,
|
31
48
|
|
32
49
|
// Display controls in the bottom right corner
|
33
50
|
controls: true,
|
@@ -44,6 +61,9 @@ var Reveal = (function(){
|
|
44
61
|
// Enable keyboard shortcuts for navigation
|
45
62
|
keyboard: true,
|
46
63
|
|
64
|
+
// Optional function that blocks keyboard events when retuning false
|
65
|
+
keyboardCondition: null,
|
66
|
+
|
47
67
|
// Enable the slide overview mode
|
48
68
|
overview: true,
|
49
69
|
|
@@ -66,6 +86,13 @@ var Reveal = (function(){
|
|
66
86
|
// i.e. contained within a limited portion of the screen
|
67
87
|
embedded: false,
|
68
88
|
|
89
|
+
// Flags if we should show a help overlay when the questionmark
|
90
|
+
// key is pressed
|
91
|
+
help: true,
|
92
|
+
|
93
|
+
// Flags if it should be possible to pause the presentation (blackout)
|
94
|
+
pause: true,
|
95
|
+
|
69
96
|
// Number of milliseconds between automatically proceeding to the
|
70
97
|
// next slide, disabled when set to 0, this value can be overwritten
|
71
98
|
// by using a data-autoslide attribute on your slides
|
@@ -86,20 +113,23 @@ var Reveal = (function(){
|
|
86
113
|
// Opens links in an iframe preview overlay
|
87
114
|
previewLinks: false,
|
88
115
|
|
89
|
-
//
|
90
|
-
|
116
|
+
// Exposes the reveal.js API through window.postMessage
|
117
|
+
postMessage: true,
|
91
118
|
|
92
|
-
//
|
93
|
-
|
119
|
+
// Dispatches all reveal.js events to the parent window through postMessage
|
120
|
+
postMessageEvents: false,
|
121
|
+
|
122
|
+
// Focuses body when page changes visiblity to ensure keyboard shortcuts work
|
123
|
+
focusBodyOnPageVisibilityChange: true,
|
94
124
|
|
95
125
|
// Transition style
|
96
|
-
transition: '
|
126
|
+
transition: 'slide', // none/fade/slide/convex/concave/zoom
|
97
127
|
|
98
128
|
// Transition speed
|
99
129
|
transitionSpeed: 'default', // default/fast/slow
|
100
130
|
|
101
131
|
// Transition style for full page slide backgrounds
|
102
|
-
backgroundTransition: '
|
132
|
+
backgroundTransition: 'fade', // none/fade/slide/convex/concave/zoom
|
103
133
|
|
104
134
|
// Parallax background image
|
105
135
|
parallaxBackgroundImage: '', // CSS syntax, e.g. "a.jpg"
|
@@ -107,6 +137,10 @@ var Reveal = (function(){
|
|
107
137
|
// Parallax background size
|
108
138
|
parallaxBackgroundSize: '', // CSS syntax, e.g. "3000px 2000px"
|
109
139
|
|
140
|
+
// Amount of pixels to move the parallax background per slide step
|
141
|
+
parallaxBackgroundHorizontal: null,
|
142
|
+
parallaxBackgroundVertical: null,
|
143
|
+
|
110
144
|
// Number of slides away from the current that are visible
|
111
145
|
viewDistance: 3,
|
112
146
|
|
@@ -115,61 +149,62 @@ var Reveal = (function(){
|
|
115
149
|
|
116
150
|
},
|
117
151
|
|
118
|
-
|
152
|
+
// Flags if reveal.js is loaded (has dispatched the 'ready' event)
|
119
153
|
loaded = false,
|
120
154
|
|
121
|
-
|
155
|
+
// Flags if the overview mode is currently active
|
156
|
+
overview = false,
|
157
|
+
|
158
|
+
// The horizontal and vertical index of the currently active slide
|
122
159
|
indexh,
|
123
160
|
indexv,
|
124
161
|
|
125
|
-
|
162
|
+
// The previous and current slide HTML elements
|
126
163
|
previousSlide,
|
127
164
|
currentSlide,
|
128
165
|
|
129
166
|
previousBackground,
|
130
167
|
|
131
|
-
|
132
|
-
|
133
|
-
|
168
|
+
// Slides may hold a data-state attribute which we pick up and apply
|
169
|
+
// as a class to the body. This list contains the combined state of
|
170
|
+
// all current slides.
|
134
171
|
state = [],
|
135
172
|
|
136
|
-
|
173
|
+
// The current scale of the presentation (see width/height config)
|
137
174
|
scale = 1,
|
138
175
|
|
139
|
-
|
176
|
+
// CSS transform that is currently applied to the slides container,
|
177
|
+
// split into two groups
|
178
|
+
slidesTransform = { layout: '', overview: '' },
|
179
|
+
|
180
|
+
// Cached references to DOM elements
|
140
181
|
dom = {},
|
141
182
|
|
142
|
-
|
183
|
+
// Features supported by the browser, see #checkCapabilities()
|
143
184
|
features = {},
|
144
185
|
|
145
|
-
|
186
|
+
// Client is a mobile device, see #checkCapabilities()
|
146
187
|
isMobileDevice,
|
147
188
|
|
148
|
-
|
189
|
+
// Throttles mouse wheel navigation
|
149
190
|
lastMouseWheelStep = 0,
|
150
191
|
|
151
|
-
|
192
|
+
// Delays updates to the URL due to a Chrome thumbnailer bug
|
152
193
|
writeURLTimeout = 0,
|
153
194
|
|
154
|
-
|
155
|
-
activateOverviewTimeout = 0,
|
156
|
-
|
157
|
-
// A delay used to deactivate the overview mode
|
158
|
-
deactivateOverviewTimeout = 0,
|
159
|
-
|
160
|
-
// Flags if the interaction event listeners are bound
|
195
|
+
// Flags if the interaction event listeners are bound
|
161
196
|
eventsAreBound = false,
|
162
197
|
|
163
|
-
|
198
|
+
// The current auto-slide duration
|
164
199
|
autoSlide = 0,
|
165
200
|
|
166
|
-
|
201
|
+
// Auto slide properties
|
167
202
|
autoSlidePlayer,
|
168
203
|
autoSlideTimeout = 0,
|
169
204
|
autoSlideStartTime = -1,
|
170
205
|
autoSlidePaused = false,
|
171
206
|
|
172
|
-
|
207
|
+
// Holds information about the currently ongoing touch input
|
173
208
|
touch = {
|
174
209
|
startX: 0,
|
175
210
|
startY: 0,
|
@@ -177,6 +212,21 @@ var Reveal = (function(){
|
|
177
212
|
startCount: 0,
|
178
213
|
captured: false,
|
179
214
|
threshold: 40
|
215
|
+
},
|
216
|
+
|
217
|
+
// Holds information about the keyboard shortcuts
|
218
|
+
keyboardShortcuts = {
|
219
|
+
'N , SPACE': 'Next slide',
|
220
|
+
'P': 'Previous slide',
|
221
|
+
'← , H': 'Navigate left',
|
222
|
+
'→ , L': 'Navigate right',
|
223
|
+
'↑ , K': 'Navigate up',
|
224
|
+
'↓ , J': 'Navigate down',
|
225
|
+
'Home': 'First slide',
|
226
|
+
'End': 'Last slide',
|
227
|
+
'B , .': 'Pause',
|
228
|
+
'F': 'Fullscreen',
|
229
|
+
'ESC, O': 'Slide overview'
|
180
230
|
};
|
181
231
|
|
182
232
|
/**
|
@@ -189,11 +239,30 @@ var Reveal = (function(){
|
|
189
239
|
if( !features.transforms2d && !features.transforms3d ) {
|
190
240
|
document.body.setAttribute( 'class', 'no-transforms' );
|
191
241
|
|
242
|
+
// Since JS won't be running any further, we load all lazy
|
243
|
+
// loading elements upfront
|
244
|
+
var images = toArray( document.getElementsByTagName( 'img' ) ),
|
245
|
+
iframes = toArray( document.getElementsByTagName( 'iframe' ) );
|
246
|
+
|
247
|
+
var lazyLoadable = images.concat( iframes );
|
248
|
+
|
249
|
+
for( var i = 0, len = lazyLoadable.length; i < len; i++ ) {
|
250
|
+
var element = lazyLoadable[i];
|
251
|
+
if( element.getAttribute( 'data-src' ) ) {
|
252
|
+
element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
|
253
|
+
element.removeAttribute( 'data-src' );
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
192
257
|
// If the browser doesn't support core features we won't be
|
193
258
|
// using JavaScript to control the presentation
|
194
259
|
return;
|
195
260
|
}
|
196
261
|
|
262
|
+
// Cache references to key DOM elements
|
263
|
+
dom.wrapper = document.querySelector( '.reveal' );
|
264
|
+
dom.slides = document.querySelector( '.reveal .slides' );
|
265
|
+
|
197
266
|
// Force a layout when the whole page, incl fonts, has loaded
|
198
267
|
window.addEventListener( 'load', layout, false );
|
199
268
|
|
@@ -222,34 +291,39 @@ var Reveal = (function(){
|
|
222
291
|
function checkCapabilities() {
|
223
292
|
|
224
293
|
features.transforms3d = 'WebkitPerspective' in document.body.style ||
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
294
|
+
'MozPerspective' in document.body.style ||
|
295
|
+
'msPerspective' in document.body.style ||
|
296
|
+
'OPerspective' in document.body.style ||
|
297
|
+
'perspective' in document.body.style;
|
229
298
|
|
230
299
|
features.transforms2d = 'WebkitTransform' in document.body.style ||
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
300
|
+
'MozTransform' in document.body.style ||
|
301
|
+
'msTransform' in document.body.style ||
|
302
|
+
'OTransform' in document.body.style ||
|
303
|
+
'transform' in document.body.style;
|
235
304
|
|
236
305
|
features.requestAnimationFrameMethod = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
|
237
306
|
features.requestAnimationFrame = typeof features.requestAnimationFrameMethod === 'function';
|
238
307
|
|
239
308
|
features.canvas = !!document.createElement( 'canvas' ).getContext;
|
240
309
|
|
241
|
-
|
310
|
+
features.touch = !!( 'ontouchstart' in window );
|
242
311
|
|
243
|
-
|
312
|
+
// Transitions in the overview are disabled in desktop and
|
313
|
+
// mobile Safari due to lag
|
314
|
+
features.overviewTransitions = !/Version\/[\d\.]+.*Safari/.test( navigator.userAgent );
|
244
315
|
|
316
|
+
isMobileDevice = /(iphone|ipod|ipad|android)/gi.test( navigator.userAgent );
|
245
317
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
318
|
+
}
|
319
|
+
|
320
|
+
/**
|
321
|
+
* Loads the dependencies of reveal.js. Dependencies are
|
322
|
+
* defined via the configuration option 'dependencies'
|
323
|
+
* and will be loaded prior to starting/binding reveal.js.
|
324
|
+
* Some dependencies may have an 'async' flag, if so they
|
325
|
+
* will load after reveal.js has been started up.
|
326
|
+
*/
|
253
327
|
function load() {
|
254
328
|
|
255
329
|
var scripts = [],
|
@@ -316,6 +390,12 @@ var Reveal = (function(){
|
|
316
390
|
// Make sure we've got all the DOM elements we need
|
317
391
|
setupDOM();
|
318
392
|
|
393
|
+
// Listen to messages posted to this window
|
394
|
+
setupPostMessage();
|
395
|
+
|
396
|
+
// Prevent iframes from scrolling the slides out of view
|
397
|
+
setupIframeScrollPrevention();
|
398
|
+
|
319
399
|
// Resets all vertical slides so that only the first is visible
|
320
400
|
resetVerticalSlides();
|
321
401
|
|
@@ -343,6 +423,20 @@ var Reveal = (function(){
|
|
343
423
|
} );
|
344
424
|
}, 1 );
|
345
425
|
|
426
|
+
// Special setup and config is required when printing to PDF
|
427
|
+
if( isPrintingPDF() ) {
|
428
|
+
removeEventListeners();
|
429
|
+
|
430
|
+
// The document needs to have loaded for the PDF layout
|
431
|
+
// measurements to be accurate
|
432
|
+
if( document.readyState === 'complete' ) {
|
433
|
+
setupPDF();
|
434
|
+
}
|
435
|
+
else {
|
436
|
+
window.addEventListener( 'load', setupPDF );
|
437
|
+
}
|
438
|
+
}
|
439
|
+
|
346
440
|
}
|
347
441
|
|
348
442
|
/**
|
@@ -352,11 +446,6 @@ var Reveal = (function(){
|
|
352
446
|
*/
|
353
447
|
function setupDOM() {
|
354
448
|
|
355
|
-
// Cache references to key DOM elements
|
356
|
-
dom.theme = document.querySelector( '#theme' );
|
357
|
-
dom.wrapper = document.querySelector( '.reveal' );
|
358
|
-
dom.slides = document.querySelector( '.reveal .slides' );
|
359
|
-
|
360
449
|
// Prevent transitions while we're loading
|
361
450
|
dom.slides.classList.add( 'no-transition' );
|
362
451
|
|
@@ -377,14 +466,14 @@ var Reveal = (function(){
|
|
377
466
|
// Slide number
|
378
467
|
dom.slideNumber = createSingletonNode( dom.wrapper, 'div', 'slide-number', '' );
|
379
468
|
|
380
|
-
// State background element [DEPRECATED]
|
381
|
-
createSingletonNode( dom.wrapper, 'div', 'state-background', null );
|
382
|
-
|
383
469
|
// Overlay graphic which is displayed during the paused mode
|
384
470
|
createSingletonNode( dom.wrapper, 'div', 'pause-overlay', null );
|
385
471
|
|
386
472
|
// Cache references to elements
|
387
473
|
dom.controls = document.querySelector( '.reveal .controls' );
|
474
|
+
dom.theme = document.querySelector( '#theme' );
|
475
|
+
|
476
|
+
dom.wrapper.setAttribute( 'role', 'application' );
|
388
477
|
|
389
478
|
// There can be multiple instances of controls throughout the page
|
390
479
|
dom.controlsLeft = toArray( document.querySelectorAll( '.navigate-left' ) );
|
@@ -394,6 +483,120 @@ var Reveal = (function(){
|
|
394
483
|
dom.controlsPrev = toArray( document.querySelectorAll( '.navigate-prev' ) );
|
395
484
|
dom.controlsNext = toArray( document.querySelectorAll( '.navigate-next' ) );
|
396
485
|
|
486
|
+
dom.statusDiv = createStatusDiv();
|
487
|
+
}
|
488
|
+
|
489
|
+
/**
|
490
|
+
* Creates a hidden div with role aria-live to announce the
|
491
|
+
* current slide content. Hide the div off-screen to make it
|
492
|
+
* available only to Assistive Technologies.
|
493
|
+
*/
|
494
|
+
function createStatusDiv() {
|
495
|
+
|
496
|
+
var statusDiv = document.getElementById( 'aria-status-div' );
|
497
|
+
if( !statusDiv ) {
|
498
|
+
statusDiv = document.createElement( 'div' );
|
499
|
+
statusDiv.style.position = 'absolute';
|
500
|
+
statusDiv.style.height = '1px';
|
501
|
+
statusDiv.style.width = '1px';
|
502
|
+
statusDiv.style.overflow ='hidden';
|
503
|
+
statusDiv.style.clip = 'rect( 1px, 1px, 1px, 1px )';
|
504
|
+
statusDiv.setAttribute( 'id', 'aria-status-div' );
|
505
|
+
statusDiv.setAttribute( 'aria-live', 'polite' );
|
506
|
+
statusDiv.setAttribute( 'aria-atomic','true' );
|
507
|
+
dom.wrapper.appendChild( statusDiv );
|
508
|
+
}
|
509
|
+
return statusDiv;
|
510
|
+
|
511
|
+
}
|
512
|
+
|
513
|
+
/**
|
514
|
+
* Configures the presentation for printing to a static
|
515
|
+
* PDF.
|
516
|
+
*/
|
517
|
+
function setupPDF() {
|
518
|
+
|
519
|
+
var slideSize = getComputedSlideSize( window.innerWidth, window.innerHeight );
|
520
|
+
|
521
|
+
// Dimensions of the PDF pages
|
522
|
+
var pageWidth = Math.floor( slideSize.width * ( 1 + config.margin ) ),
|
523
|
+
pageHeight = Math.floor( slideSize.height * ( 1 + config.margin ) );
|
524
|
+
|
525
|
+
// Dimensions of slides within the pages
|
526
|
+
var slideWidth = slideSize.width,
|
527
|
+
slideHeight = slideSize.height;
|
528
|
+
|
529
|
+
// Let the browser know what page size we want to print
|
530
|
+
injectStyleSheet( '@page{size:'+ pageWidth +'px '+ pageHeight +'px; margin: 0;}' );
|
531
|
+
|
532
|
+
// Limit the size of certain elements to the dimensions of the slide
|
533
|
+
injectStyleSheet( '.reveal section>img, .reveal section>video, .reveal section>iframe{max-width: '+ slideWidth +'px; max-height:'+ slideHeight +'px}' );
|
534
|
+
|
535
|
+
document.body.classList.add( 'print-pdf' );
|
536
|
+
document.body.style.width = pageWidth + 'px';
|
537
|
+
document.body.style.height = pageHeight + 'px';
|
538
|
+
|
539
|
+
// Slide and slide background layout
|
540
|
+
toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) {
|
541
|
+
|
542
|
+
// Vertical stacks are not centred since their section
|
543
|
+
// children will be
|
544
|
+
if( slide.classList.contains( 'stack' ) === false ) {
|
545
|
+
// Center the slide inside of the page, giving the slide some margin
|
546
|
+
var left = ( pageWidth - slideWidth ) / 2,
|
547
|
+
top = ( pageHeight - slideHeight ) / 2;
|
548
|
+
|
549
|
+
var contentHeight = getAbsoluteHeight( slide );
|
550
|
+
var numberOfPages = Math.max( Math.ceil( contentHeight / pageHeight ), 1 );
|
551
|
+
|
552
|
+
// Center slides vertically
|
553
|
+
if( numberOfPages === 1 && config.center || slide.classList.contains( 'center' ) ) {
|
554
|
+
top = Math.max( ( pageHeight - contentHeight ) / 2, 0 );
|
555
|
+
}
|
556
|
+
|
557
|
+
// Position the slide inside of the page
|
558
|
+
slide.style.left = left + 'px';
|
559
|
+
slide.style.top = top + 'px';
|
560
|
+
slide.style.width = slideWidth + 'px';
|
561
|
+
|
562
|
+
// TODO Backgrounds need to be multiplied when the slide
|
563
|
+
// stretches over multiple pages
|
564
|
+
var background = slide.querySelector( '.slide-background' );
|
565
|
+
if( background ) {
|
566
|
+
background.style.width = pageWidth + 'px';
|
567
|
+
background.style.height = ( pageHeight * numberOfPages ) + 'px';
|
568
|
+
background.style.top = -top + 'px';
|
569
|
+
background.style.left = -left + 'px';
|
570
|
+
}
|
571
|
+
}
|
572
|
+
|
573
|
+
} );
|
574
|
+
|
575
|
+
// Show all fragments
|
576
|
+
toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ' .fragment' ) ).forEach( function( fragment ) {
|
577
|
+
fragment.classList.add( 'visible' );
|
578
|
+
} );
|
579
|
+
|
580
|
+
}
|
581
|
+
|
582
|
+
/**
|
583
|
+
* This is an unfortunate necessity. Iframes can trigger the
|
584
|
+
* parent window to scroll, for example by focusing an input.
|
585
|
+
* This scrolling can not be prevented by hiding overflow in
|
586
|
+
* CSS so we have to resort to repeatedly checking if the
|
587
|
+
* browser has decided to offset our slides :(
|
588
|
+
*/
|
589
|
+
function setupIframeScrollPrevention() {
|
590
|
+
|
591
|
+
if( dom.slides.querySelector( 'iframe' ) ) {
|
592
|
+
setInterval( function() {
|
593
|
+
if( dom.wrapper.scrollTop !== 0 || dom.wrapper.scrollLeft !== 0 ) {
|
594
|
+
dom.wrapper.scrollTop = 0;
|
595
|
+
dom.wrapper.scrollLeft = 0;
|
596
|
+
}
|
597
|
+
}, 500 );
|
598
|
+
}
|
599
|
+
|
397
600
|
}
|
398
601
|
|
399
602
|
/**
|
@@ -403,15 +606,26 @@ var Reveal = (function(){
|
|
403
606
|
*/
|
404
607
|
function createSingletonNode( container, tagname, classname, innerHTML ) {
|
405
608
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
609
|
+
// Find all nodes matching the description
|
610
|
+
var nodes = container.querySelectorAll( '.' + classname );
|
611
|
+
|
612
|
+
// Check all matches to find one which is a direct child of
|
613
|
+
// the specified container
|
614
|
+
for( var i = 0; i < nodes.length; i++ ) {
|
615
|
+
var testNode = nodes[i];
|
616
|
+
if( testNode.parentNode === container ) {
|
617
|
+
return testNode;
|
412
618
|
}
|
413
|
-
container.appendChild( node );
|
414
619
|
}
|
620
|
+
|
621
|
+
// If no node was found, create it now
|
622
|
+
var node = document.createElement( tagname );
|
623
|
+
node.classList.add( classname );
|
624
|
+
if( typeof innerHTML === 'string' ) {
|
625
|
+
node.innerHTML = innerHTML;
|
626
|
+
}
|
627
|
+
container.appendChild( node );
|
628
|
+
|
415
629
|
return node;
|
416
630
|
|
417
631
|
}
|
@@ -423,81 +637,36 @@ var Reveal = (function(){
|
|
423
637
|
*/
|
424
638
|
function createBackgrounds() {
|
425
639
|
|
426
|
-
|
427
|
-
document.body.classList.add( 'print-pdf' );
|
428
|
-
}
|
640
|
+
var printMode = isPrintingPDF();
|
429
641
|
|
430
642
|
// Clear prior backgrounds
|
431
643
|
dom.background.innerHTML = '';
|
432
644
|
dom.background.classList.add( 'no-transition' );
|
433
645
|
|
434
|
-
// Helper method for creating a background element for the
|
435
|
-
// given slide
|
436
|
-
function _createBackground( slide, container ) {
|
437
|
-
|
438
|
-
var data = {
|
439
|
-
background: slide.getAttribute( 'data-background' ),
|
440
|
-
backgroundSize: slide.getAttribute( 'data-background-size' ),
|
441
|
-
backgroundImage: slide.getAttribute( 'data-background-image' ),
|
442
|
-
backgroundColor: slide.getAttribute( 'data-background-color' ),
|
443
|
-
backgroundRepeat: slide.getAttribute( 'data-background-repeat' ),
|
444
|
-
backgroundPosition: slide.getAttribute( 'data-background-position' ),
|
445
|
-
backgroundTransition: slide.getAttribute( 'data-background-transition' )
|
446
|
-
};
|
447
|
-
|
448
|
-
var element = document.createElement( 'div' );
|
449
|
-
element.className = 'slide-background';
|
450
|
-
|
451
|
-
if( data.background ) {
|
452
|
-
// Auto-wrap image urls in url(...)
|
453
|
-
if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)$/gi.test( data.background ) ) {
|
454
|
-
element.style.backgroundImage = 'url('+ data.background +')';
|
455
|
-
}
|
456
|
-
else {
|
457
|
-
element.style.background = data.background;
|
458
|
-
}
|
459
|
-
}
|
460
|
-
|
461
|
-
if( data.background || data.backgroundColor || data.backgroundImage ) {
|
462
|
-
element.setAttribute( 'data-background-hash', data.background + data.backgroundSize + data.backgroundImage + data.backgroundColor + data.backgroundRepeat + data.backgroundPosition + data.backgroundTransition );
|
463
|
-
}
|
464
|
-
|
465
|
-
// Additional and optional background properties
|
466
|
-
if( data.backgroundSize ) element.style.backgroundSize = data.backgroundSize;
|
467
|
-
if( data.backgroundImage ) element.style.backgroundImage = 'url("' + data.backgroundImage + '")';
|
468
|
-
if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor;
|
469
|
-
if( data.backgroundRepeat ) element.style.backgroundRepeat = data.backgroundRepeat;
|
470
|
-
if( data.backgroundPosition ) element.style.backgroundPosition = data.backgroundPosition;
|
471
|
-
if( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition );
|
472
|
-
|
473
|
-
container.appendChild( element );
|
474
|
-
|
475
|
-
return element;
|
476
|
-
|
477
|
-
}
|
478
|
-
|
479
646
|
// Iterate over all horizontal slides
|
480
|
-
toArray(
|
647
|
+
toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).forEach( function( slideh ) {
|
481
648
|
|
482
649
|
var backgroundStack;
|
483
650
|
|
484
|
-
if(
|
485
|
-
backgroundStack =
|
651
|
+
if( printMode ) {
|
652
|
+
backgroundStack = createBackground( slideh, slideh );
|
486
653
|
}
|
487
654
|
else {
|
488
|
-
backgroundStack =
|
655
|
+
backgroundStack = createBackground( slideh, dom.background );
|
489
656
|
}
|
490
657
|
|
491
658
|
// Iterate over all vertical slides
|
492
659
|
toArray( slideh.querySelectorAll( 'section' ) ).forEach( function( slidev ) {
|
493
660
|
|
494
|
-
if(
|
495
|
-
|
661
|
+
if( printMode ) {
|
662
|
+
createBackground( slidev, slidev );
|
496
663
|
}
|
497
664
|
else {
|
498
|
-
|
665
|
+
createBackground( slidev, backgroundStack );
|
499
666
|
}
|
500
667
|
|
668
|
+
backgroundStack.classList.add( 'stack' );
|
669
|
+
|
501
670
|
} );
|
502
671
|
|
503
672
|
} );
|
@@ -526,13 +695,131 @@ var Reveal = (function(){
|
|
526
695
|
|
527
696
|
}
|
528
697
|
|
698
|
+
/**
|
699
|
+
* Creates a background for the given slide.
|
700
|
+
*
|
701
|
+
* @param {HTMLElement} slide
|
702
|
+
* @param {HTMLElement} container The element that the background
|
703
|
+
* should be appended to
|
704
|
+
*/
|
705
|
+
function createBackground( slide, container ) {
|
706
|
+
|
707
|
+
var data = {
|
708
|
+
background: slide.getAttribute( 'data-background' ),
|
709
|
+
backgroundSize: slide.getAttribute( 'data-background-size' ),
|
710
|
+
backgroundImage: slide.getAttribute( 'data-background-image' ),
|
711
|
+
backgroundVideo: slide.getAttribute( 'data-background-video' ),
|
712
|
+
backgroundIframe: slide.getAttribute( 'data-background-iframe' ),
|
713
|
+
backgroundColor: slide.getAttribute( 'data-background-color' ),
|
714
|
+
backgroundRepeat: slide.getAttribute( 'data-background-repeat' ),
|
715
|
+
backgroundPosition: slide.getAttribute( 'data-background-position' ),
|
716
|
+
backgroundTransition: slide.getAttribute( 'data-background-transition' )
|
717
|
+
};
|
718
|
+
|
719
|
+
var element = document.createElement( 'div' );
|
720
|
+
|
721
|
+
// Carry over custom classes from the slide to the background
|
722
|
+
element.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' );
|
723
|
+
|
724
|
+
if( data.background ) {
|
725
|
+
// Auto-wrap image urls in url(...)
|
726
|
+
if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)$/gi.test( data.background ) ) {
|
727
|
+
slide.setAttribute( 'data-background-image', data.background );
|
728
|
+
}
|
729
|
+
else {
|
730
|
+
element.style.background = data.background;
|
731
|
+
}
|
732
|
+
}
|
733
|
+
|
734
|
+
// Create a hash for this combination of background settings.
|
735
|
+
// This is used to determine when two slide backgrounds are
|
736
|
+
// the same.
|
737
|
+
if( data.background || data.backgroundColor || data.backgroundImage || data.backgroundVideo || data.backgroundIframe ) {
|
738
|
+
element.setAttribute( 'data-background-hash', data.background +
|
739
|
+
data.backgroundSize +
|
740
|
+
data.backgroundImage +
|
741
|
+
data.backgroundVideo +
|
742
|
+
data.backgroundIframe +
|
743
|
+
data.backgroundColor +
|
744
|
+
data.backgroundRepeat +
|
745
|
+
data.backgroundPosition +
|
746
|
+
data.backgroundTransition );
|
747
|
+
}
|
748
|
+
|
749
|
+
// Additional and optional background properties
|
750
|
+
if( data.backgroundSize ) element.style.backgroundSize = data.backgroundSize;
|
751
|
+
if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor;
|
752
|
+
if( data.backgroundRepeat ) element.style.backgroundRepeat = data.backgroundRepeat;
|
753
|
+
if( data.backgroundPosition ) element.style.backgroundPosition = data.backgroundPosition;
|
754
|
+
if( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition );
|
755
|
+
|
756
|
+
container.appendChild( element );
|
757
|
+
|
758
|
+
// If backgrounds are being recreated, clear old classes
|
759
|
+
slide.classList.remove( 'has-dark-background' );
|
760
|
+
slide.classList.remove( 'has-light-background' );
|
761
|
+
|
762
|
+
// If this slide has a background color, add a class that
|
763
|
+
// signals if it is light or dark. If the slide has no background
|
764
|
+
// color, no class will be set
|
765
|
+
var computedBackgroundColor = window.getComputedStyle( element ).backgroundColor;
|
766
|
+
if( computedBackgroundColor ) {
|
767
|
+
var rgb = colorToRgb( computedBackgroundColor );
|
768
|
+
|
769
|
+
// Ignore fully transparent backgrounds. Some browsers return
|
770
|
+
// rgba(0,0,0,0) when reading the computed background color of
|
771
|
+
// an element with no background
|
772
|
+
if( rgb && rgb.a !== 0 ) {
|
773
|
+
if( colorBrightness( computedBackgroundColor ) < 128 ) {
|
774
|
+
slide.classList.add( 'has-dark-background' );
|
775
|
+
}
|
776
|
+
else {
|
777
|
+
slide.classList.add( 'has-light-background' );
|
778
|
+
}
|
779
|
+
}
|
780
|
+
}
|
781
|
+
|
782
|
+
return element;
|
783
|
+
|
784
|
+
}
|
785
|
+
|
786
|
+
/**
|
787
|
+
* Registers a listener to postMessage events, this makes it
|
788
|
+
* possible to call all reveal.js API methods from another
|
789
|
+
* window. For example:
|
790
|
+
*
|
791
|
+
* revealWindow.postMessage( JSON.stringify({
|
792
|
+
* method: 'slide',
|
793
|
+
* args: [ 2 ]
|
794
|
+
* }), '*' );
|
795
|
+
*/
|
796
|
+
function setupPostMessage() {
|
797
|
+
|
798
|
+
if( config.postMessage ) {
|
799
|
+
window.addEventListener( 'message', function ( event ) {
|
800
|
+
var data = event.data;
|
801
|
+
|
802
|
+
// Make sure we're dealing with JSON
|
803
|
+
if( typeof data === 'string' && data.charAt( 0 ) === '{' && data.charAt( data.length - 1 ) === '}' ) {
|
804
|
+
data = JSON.parse( data );
|
805
|
+
|
806
|
+
// Check if the requested method can be found
|
807
|
+
if( data.method && typeof Reveal[data.method] === 'function' ) {
|
808
|
+
Reveal[data.method].apply( Reveal, data.args );
|
809
|
+
}
|
810
|
+
}
|
811
|
+
}, false );
|
812
|
+
}
|
813
|
+
|
814
|
+
}
|
815
|
+
|
529
816
|
/**
|
530
817
|
* Applies the configuration settings from the config
|
531
818
|
* object. May be called multiple times.
|
532
819
|
*/
|
533
820
|
function configure( options ) {
|
534
821
|
|
535
|
-
var numberOfSlides =
|
822
|
+
var numberOfSlides = dom.wrapper.querySelectorAll( SLIDES_SELECTOR ).length;
|
536
823
|
|
537
824
|
dom.wrapper.classList.remove( config.transition );
|
538
825
|
|
@@ -565,6 +852,11 @@ var Reveal = (function(){
|
|
565
852
|
dom.wrapper.classList.remove( 'center' );
|
566
853
|
}
|
567
854
|
|
855
|
+
// Exit the paused mode if it was configured off
|
856
|
+
if( config.pause === false ) {
|
857
|
+
resume();
|
858
|
+
}
|
859
|
+
|
568
860
|
if( config.mouseWheel ) {
|
569
861
|
document.addEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF
|
570
862
|
document.addEventListener( 'mousewheel', onDocumentMouseScroll, false );
|
@@ -591,7 +883,13 @@ var Reveal = (function(){
|
|
591
883
|
enablePreviewLinks( '[data-preview-link]' );
|
592
884
|
}
|
593
885
|
|
594
|
-
//
|
886
|
+
// Remove existing auto-slide controls
|
887
|
+
if( autoSlidePlayer ) {
|
888
|
+
autoSlidePlayer.destroy();
|
889
|
+
autoSlidePlayer = null;
|
890
|
+
}
|
891
|
+
|
892
|
+
// Generate auto-slide controls if needed
|
595
893
|
if( numberOfSlides > 1 && config.autoSlide && config.autoSlideStoppable && features.canvas && features.requestAnimationFrame ) {
|
596
894
|
autoSlidePlayer = new Playback( dom.wrapper, function() {
|
597
895
|
return Math.min( Math.max( ( Date.now() - autoSlideStartTime ) / autoSlide, 0 ), 1 );
|
@@ -600,21 +898,13 @@ var Reveal = (function(){
|
|
600
898
|
autoSlidePlayer.on( 'click', onAutoSlidePlayerClick );
|
601
899
|
autoSlidePaused = false;
|
602
900
|
}
|
603
|
-
else if( autoSlidePlayer ) {
|
604
|
-
autoSlidePlayer.destroy();
|
605
|
-
autoSlidePlayer = null;
|
606
|
-
}
|
607
901
|
|
608
|
-
//
|
609
|
-
if( config.
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
if( config.theme !== themeName ) {
|
615
|
-
themeURL = themeURL.replace(themeFinder, config.theme);
|
616
|
-
dom.theme.setAttribute( 'href', themeURL );
|
617
|
-
}
|
902
|
+
// When fragments are turned off they should be visible
|
903
|
+
if( config.fragments === false ) {
|
904
|
+
toArray( dom.slides.querySelectorAll( '.fragment' ) ).forEach( function( element ) {
|
905
|
+
element.classList.add( 'visible' );
|
906
|
+
element.classList.remove( 'current-fragment' );
|
907
|
+
} );
|
618
908
|
}
|
619
909
|
|
620
910
|
sync();
|
@@ -637,7 +927,14 @@ var Reveal = (function(){
|
|
637
927
|
dom.wrapper.addEventListener( 'touchend', onTouchEnd, false );
|
638
928
|
|
639
929
|
// Support pointer-style touch interaction as well
|
640
|
-
if( window.navigator.
|
930
|
+
if( window.navigator.pointerEnabled ) {
|
931
|
+
// IE 11 uses un-prefixed version of pointer events
|
932
|
+
dom.wrapper.addEventListener( 'pointerdown', onPointerDown, false );
|
933
|
+
dom.wrapper.addEventListener( 'pointermove', onPointerMove, false );
|
934
|
+
dom.wrapper.addEventListener( 'pointerup', onPointerUp, false );
|
935
|
+
}
|
936
|
+
else if( window.navigator.msPointerEnabled ) {
|
937
|
+
// IE 10 uses prefixed version of pointer events
|
641
938
|
dom.wrapper.addEventListener( 'MSPointerDown', onPointerDown, false );
|
642
939
|
dom.wrapper.addEventListener( 'MSPointerMove', onPointerMove, false );
|
643
940
|
dom.wrapper.addEventListener( 'MSPointerUp', onPointerUp, false );
|
@@ -646,13 +943,14 @@ var Reveal = (function(){
|
|
646
943
|
|
647
944
|
if( config.keyboard ) {
|
648
945
|
document.addEventListener( 'keydown', onDocumentKeyDown, false );
|
946
|
+
document.addEventListener( 'keypress', onDocumentKeyPress, false );
|
649
947
|
}
|
650
948
|
|
651
949
|
if( config.progress && dom.progress ) {
|
652
950
|
dom.progress.addEventListener( 'click', onProgressClicked, false );
|
653
951
|
}
|
654
952
|
|
655
|
-
if( config.
|
953
|
+
if( config.focusBodyOnPageVisibilityChange ) {
|
656
954
|
var visibilityChange;
|
657
955
|
|
658
956
|
if( 'hidden' in document ) {
|
@@ -670,7 +968,17 @@ var Reveal = (function(){
|
|
670
968
|
}
|
671
969
|
}
|
672
970
|
|
673
|
-
|
971
|
+
// Listen to both touch and click events, in case the device
|
972
|
+
// supports both
|
973
|
+
var pointerEvents = [ 'touchstart', 'click' ];
|
974
|
+
|
975
|
+
// Only support touch for Android, fixes double navigations in
|
976
|
+
// stock browser
|
977
|
+
if( navigator.userAgent.match( /android/gi ) ) {
|
978
|
+
pointerEvents = [ 'touchstart' ];
|
979
|
+
}
|
980
|
+
|
981
|
+
pointerEvents.forEach( function( eventName ) {
|
674
982
|
dom.controlsLeft.forEach( function( el ) { el.addEventListener( eventName, onNavigateLeftClicked, false ); } );
|
675
983
|
dom.controlsRight.forEach( function( el ) { el.addEventListener( eventName, onNavigateRightClicked, false ); } );
|
676
984
|
dom.controlsUp.forEach( function( el ) { el.addEventListener( eventName, onNavigateUpClicked, false ); } );
|
@@ -689,6 +997,7 @@ var Reveal = (function(){
|
|
689
997
|
eventsAreBound = false;
|
690
998
|
|
691
999
|
document.removeEventListener( 'keydown', onDocumentKeyDown, false );
|
1000
|
+
document.removeEventListener( 'keypress', onDocumentKeyPress, false );
|
692
1001
|
window.removeEventListener( 'hashchange', onWindowHashChange, false );
|
693
1002
|
window.removeEventListener( 'resize', onWindowResize, false );
|
694
1003
|
|
@@ -696,7 +1005,14 @@ var Reveal = (function(){
|
|
696
1005
|
dom.wrapper.removeEventListener( 'touchmove', onTouchMove, false );
|
697
1006
|
dom.wrapper.removeEventListener( 'touchend', onTouchEnd, false );
|
698
1007
|
|
699
|
-
|
1008
|
+
// IE11
|
1009
|
+
if( window.navigator.pointerEnabled ) {
|
1010
|
+
dom.wrapper.removeEventListener( 'pointerdown', onPointerDown, false );
|
1011
|
+
dom.wrapper.removeEventListener( 'pointermove', onPointerMove, false );
|
1012
|
+
dom.wrapper.removeEventListener( 'pointerup', onPointerUp, false );
|
1013
|
+
}
|
1014
|
+
// IE10
|
1015
|
+
else if( window.navigator.msPointerEnabled ) {
|
700
1016
|
dom.wrapper.removeEventListener( 'MSPointerDown', onPointerDown, false );
|
701
1017
|
dom.wrapper.removeEventListener( 'MSPointerMove', onPointerMove, false );
|
702
1018
|
dom.wrapper.removeEventListener( 'MSPointerUp', onPointerUp, false );
|
@@ -738,6 +1054,22 @@ var Reveal = (function(){
|
|
738
1054
|
|
739
1055
|
}
|
740
1056
|
|
1057
|
+
/**
|
1058
|
+
* Utility for deserializing a value.
|
1059
|
+
*/
|
1060
|
+
function deserialize( value ) {
|
1061
|
+
|
1062
|
+
if( typeof value === 'string' ) {
|
1063
|
+
if( value === 'null' ) return null;
|
1064
|
+
else if( value === 'true' ) return true;
|
1065
|
+
else if( value === 'false' ) return false;
|
1066
|
+
else if( value.match( /^\d+$/ ) ) return parseFloat( value );
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
return value;
|
1070
|
+
|
1071
|
+
}
|
1072
|
+
|
741
1073
|
/**
|
742
1074
|
* Measures the distance in pixels between point a
|
743
1075
|
* and point b.
|
@@ -762,11 +1094,119 @@ var Reveal = (function(){
|
|
762
1094
|
element.style.WebkitTransform = transform;
|
763
1095
|
element.style.MozTransform = transform;
|
764
1096
|
element.style.msTransform = transform;
|
765
|
-
element.style.OTransform = transform;
|
766
1097
|
element.style.transform = transform;
|
767
1098
|
|
768
1099
|
}
|
769
1100
|
|
1101
|
+
/**
|
1102
|
+
* Applies CSS transforms to the slides container. The container
|
1103
|
+
* is transformed from two separate sources: layout and the overview
|
1104
|
+
* mode.
|
1105
|
+
*/
|
1106
|
+
function transformSlides( transforms ) {
|
1107
|
+
|
1108
|
+
// Pick up new transforms from arguments
|
1109
|
+
if( typeof transforms.layout === 'string' ) slidesTransform.layout = transforms.layout;
|
1110
|
+
if( typeof transforms.overview === 'string' ) slidesTransform.overview = transforms.overview;
|
1111
|
+
|
1112
|
+
// Apply the transforms to the slides container
|
1113
|
+
if( slidesTransform.layout ) {
|
1114
|
+
transformElement( dom.slides, slidesTransform.layout + ' ' + slidesTransform.overview );
|
1115
|
+
}
|
1116
|
+
else {
|
1117
|
+
transformElement( dom.slides, slidesTransform.overview );
|
1118
|
+
}
|
1119
|
+
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
/**
|
1123
|
+
* Injects the given CSS styles into the DOM.
|
1124
|
+
*/
|
1125
|
+
function injectStyleSheet( value ) {
|
1126
|
+
|
1127
|
+
var tag = document.createElement( 'style' );
|
1128
|
+
tag.type = 'text/css';
|
1129
|
+
if( tag.styleSheet ) {
|
1130
|
+
tag.styleSheet.cssText = value;
|
1131
|
+
}
|
1132
|
+
else {
|
1133
|
+
tag.appendChild( document.createTextNode( value ) );
|
1134
|
+
}
|
1135
|
+
document.getElementsByTagName( 'head' )[0].appendChild( tag );
|
1136
|
+
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
/**
|
1140
|
+
* Converts various color input formats to an {r:0,g:0,b:0} object.
|
1141
|
+
*
|
1142
|
+
* @param {String} color The string representation of a color,
|
1143
|
+
* the following formats are supported:
|
1144
|
+
* - #000
|
1145
|
+
* - #000000
|
1146
|
+
* - rgb(0,0,0)
|
1147
|
+
*/
|
1148
|
+
function colorToRgb( color ) {
|
1149
|
+
|
1150
|
+
var hex3 = color.match( /^#([0-9a-f]{3})$/i );
|
1151
|
+
if( hex3 && hex3[1] ) {
|
1152
|
+
hex3 = hex3[1];
|
1153
|
+
return {
|
1154
|
+
r: parseInt( hex3.charAt( 0 ), 16 ) * 0x11,
|
1155
|
+
g: parseInt( hex3.charAt( 1 ), 16 ) * 0x11,
|
1156
|
+
b: parseInt( hex3.charAt( 2 ), 16 ) * 0x11
|
1157
|
+
};
|
1158
|
+
}
|
1159
|
+
|
1160
|
+
var hex6 = color.match( /^#([0-9a-f]{6})$/i );
|
1161
|
+
if( hex6 && hex6[1] ) {
|
1162
|
+
hex6 = hex6[1];
|
1163
|
+
return {
|
1164
|
+
r: parseInt( hex6.substr( 0, 2 ), 16 ),
|
1165
|
+
g: parseInt( hex6.substr( 2, 2 ), 16 ),
|
1166
|
+
b: parseInt( hex6.substr( 4, 2 ), 16 )
|
1167
|
+
};
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
var rgb = color.match( /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i );
|
1171
|
+
if( rgb ) {
|
1172
|
+
return {
|
1173
|
+
r: parseInt( rgb[1], 10 ),
|
1174
|
+
g: parseInt( rgb[2], 10 ),
|
1175
|
+
b: parseInt( rgb[3], 10 )
|
1176
|
+
};
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
var rgba = color.match( /^rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\,\s*([\d]+|[\d]*.[\d]+)\s*\)$/i );
|
1180
|
+
if( rgba ) {
|
1181
|
+
return {
|
1182
|
+
r: parseInt( rgba[1], 10 ),
|
1183
|
+
g: parseInt( rgba[2], 10 ),
|
1184
|
+
b: parseInt( rgba[3], 10 ),
|
1185
|
+
a: parseFloat( rgba[4] )
|
1186
|
+
};
|
1187
|
+
}
|
1188
|
+
|
1189
|
+
return null;
|
1190
|
+
|
1191
|
+
}
|
1192
|
+
|
1193
|
+
/**
|
1194
|
+
* Calculates brightness on a scale of 0-255.
|
1195
|
+
*
|
1196
|
+
* @param color See colorStringToRgb for supported formats.
|
1197
|
+
*/
|
1198
|
+
function colorBrightness( color ) {
|
1199
|
+
|
1200
|
+
if( typeof color === 'string' ) color = colorToRgb( color );
|
1201
|
+
|
1202
|
+
if( color ) {
|
1203
|
+
return ( color.r * 299 + color.g * 587 + color.b * 114 ) / 1000;
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
return null;
|
1207
|
+
|
1208
|
+
}
|
1209
|
+
|
770
1210
|
/**
|
771
1211
|
* Retrieves the height of the given element by looking
|
772
1212
|
* at the position and height of its immediate children.
|
@@ -782,7 +1222,7 @@ var Reveal = (function(){
|
|
782
1222
|
|
783
1223
|
if( typeof child.offsetTop === 'number' && child.style ) {
|
784
1224
|
// Count # of abs children
|
785
|
-
if( child.
|
1225
|
+
if( window.getComputedStyle( child ).position === 'absolute' ) {
|
786
1226
|
absoluteChildren += 1;
|
787
1227
|
}
|
788
1228
|
|
@@ -804,40 +1244,26 @@ var Reveal = (function(){
|
|
804
1244
|
|
805
1245
|
/**
|
806
1246
|
* Returns the remaining height within the parent of the
|
807
|
-
* target element
|
808
|
-
* siblings.
|
1247
|
+
* target element.
|
809
1248
|
*
|
810
|
-
* remaining height = [parent height] - [
|
1249
|
+
* remaining height = [ configured parent height ] - [ current parent height ]
|
811
1250
|
*/
|
812
1251
|
function getRemainingHeight( element, height ) {
|
813
1252
|
|
814
1253
|
height = height || 0;
|
815
1254
|
|
816
1255
|
if( element ) {
|
817
|
-
var
|
818
|
-
var siblings = parent.childNodes;
|
819
|
-
|
820
|
-
// Subtract the height of each sibling
|
821
|
-
toArray( siblings ).forEach( function( sibling ) {
|
822
|
-
|
823
|
-
if( typeof sibling.offsetHeight === 'number' && sibling !== element ) {
|
1256
|
+
var newHeight, oldHeight = element.style.height;
|
824
1257
|
|
825
|
-
|
826
|
-
|
827
|
-
|
1258
|
+
// Change the .stretch element height to 0 in order find the height of all
|
1259
|
+
// the other elements
|
1260
|
+
element.style.height = '0px';
|
1261
|
+
newHeight = height - element.parentNode.offsetHeight;
|
828
1262
|
|
829
|
-
|
830
|
-
|
831
|
-
}
|
832
|
-
|
833
|
-
} );
|
834
|
-
|
835
|
-
var elementStyles = window.getComputedStyle( element );
|
836
|
-
|
837
|
-
// Subtract the margins of the target element
|
838
|
-
height -= parseInt( elementStyles.marginTop, 10 ) +
|
839
|
-
parseInt( elementStyles.marginBottom, 10 );
|
1263
|
+
// Restore the old height, just in case
|
1264
|
+
element.style.height = oldHeight + 'px';
|
840
1265
|
|
1266
|
+
return newHeight;
|
841
1267
|
}
|
842
1268
|
|
843
1269
|
return height;
|
@@ -882,13 +1308,19 @@ var Reveal = (function(){
|
|
882
1308
|
* Dispatches an event of the specified type from the
|
883
1309
|
* reveal DOM element.
|
884
1310
|
*/
|
885
|
-
function dispatchEvent( type,
|
1311
|
+
function dispatchEvent( type, args ) {
|
886
1312
|
|
887
|
-
var event = document.createEvent(
|
1313
|
+
var event = document.createEvent( 'HTMLEvents', 1, 2 );
|
888
1314
|
event.initEvent( type, true, true );
|
889
|
-
extend( event,
|
1315
|
+
extend( event, args );
|
890
1316
|
dom.wrapper.dispatchEvent( event );
|
891
1317
|
|
1318
|
+
// If we're in an iframe, post each reveal.js event to the
|
1319
|
+
// parent window. Used by the notes plugin
|
1320
|
+
if( config.postMessageEvents && window.parent !== window.self ) {
|
1321
|
+
window.parent.postMessage( JSON.stringify({ namespace: 'reveal', eventName: type, state: getState() }), '*' );
|
1322
|
+
}
|
1323
|
+
|
892
1324
|
}
|
893
1325
|
|
894
1326
|
/**
|
@@ -897,7 +1329,7 @@ var Reveal = (function(){
|
|
897
1329
|
function enableRollingLinks() {
|
898
1330
|
|
899
1331
|
if( features.transforms3d && !( 'msPerspective' in document.body.style ) ) {
|
900
|
-
var anchors =
|
1332
|
+
var anchors = dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ' a' );
|
901
1333
|
|
902
1334
|
for( var i = 0, len = anchors.length; i < len; i++ ) {
|
903
1335
|
var anchor = anchors[i];
|
@@ -921,7 +1353,7 @@ var Reveal = (function(){
|
|
921
1353
|
*/
|
922
1354
|
function disableRollingLinks() {
|
923
1355
|
|
924
|
-
var anchors =
|
1356
|
+
var anchors = dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ' a.roll' );
|
925
1357
|
|
926
1358
|
for( var i = 0, len = anchors.length; i < len; i++ ) {
|
927
1359
|
var anchor = anchors[i];
|
@@ -968,53 +1400,98 @@ var Reveal = (function(){
|
|
968
1400
|
/**
|
969
1401
|
* Opens a preview window for the target URL.
|
970
1402
|
*/
|
971
|
-
function
|
1403
|
+
function showPreview( url ) {
|
972
1404
|
|
973
|
-
|
1405
|
+
closeOverlay();
|
974
1406
|
|
975
|
-
dom.
|
976
|
-
dom.
|
977
|
-
dom.
|
1407
|
+
dom.overlay = document.createElement( 'div' );
|
1408
|
+
dom.overlay.classList.add( 'overlay' );
|
1409
|
+
dom.overlay.classList.add( 'overlay-preview' );
|
1410
|
+
dom.wrapper.appendChild( dom.overlay );
|
978
1411
|
|
979
|
-
dom.
|
1412
|
+
dom.overlay.innerHTML = [
|
980
1413
|
'<header>',
|
981
|
-
|
982
|
-
|
1414
|
+
'<a class="close" href="#"><span class="icon"></span></a>',
|
1415
|
+
'<a class="external" href="'+ url +'" target="_blank"><span class="icon"></span></a>',
|
983
1416
|
'</header>',
|
984
1417
|
'<div class="spinner"></div>',
|
985
1418
|
'<div class="viewport">',
|
986
|
-
|
1419
|
+
'<iframe src="'+ url +'"></iframe>',
|
987
1420
|
'</div>'
|
988
1421
|
].join('');
|
989
1422
|
|
990
|
-
dom.
|
991
|
-
dom.
|
1423
|
+
dom.overlay.querySelector( 'iframe' ).addEventListener( 'load', function( event ) {
|
1424
|
+
dom.overlay.classList.add( 'loaded' );
|
992
1425
|
}, false );
|
993
1426
|
|
994
|
-
dom.
|
995
|
-
|
1427
|
+
dom.overlay.querySelector( '.close' ).addEventListener( 'click', function( event ) {
|
1428
|
+
closeOverlay();
|
996
1429
|
event.preventDefault();
|
997
1430
|
}, false );
|
998
1431
|
|
999
|
-
dom.
|
1000
|
-
|
1432
|
+
dom.overlay.querySelector( '.external' ).addEventListener( 'click', function( event ) {
|
1433
|
+
closeOverlay();
|
1001
1434
|
}, false );
|
1002
1435
|
|
1003
1436
|
setTimeout( function() {
|
1004
|
-
dom.
|
1437
|
+
dom.overlay.classList.add( 'visible' );
|
1005
1438
|
}, 1 );
|
1006
1439
|
|
1007
1440
|
}
|
1008
1441
|
|
1009
1442
|
/**
|
1010
|
-
*
|
1443
|
+
* Opens a overlay window with help material.
|
1011
1444
|
*/
|
1012
|
-
function
|
1445
|
+
function showHelp() {
|
1446
|
+
|
1447
|
+
if( config.help ) {
|
1448
|
+
|
1449
|
+
closeOverlay();
|
1450
|
+
|
1451
|
+
dom.overlay = document.createElement( 'div' );
|
1452
|
+
dom.overlay.classList.add( 'overlay' );
|
1453
|
+
dom.overlay.classList.add( 'overlay-help' );
|
1454
|
+
dom.wrapper.appendChild( dom.overlay );
|
1455
|
+
|
1456
|
+
var html = '<p class="title">Keyboard Shortcuts</p><br/>';
|
1457
|
+
|
1458
|
+
html += '<table><th>KEY</th><th>ACTION</th>';
|
1459
|
+
for( var key in keyboardShortcuts ) {
|
1460
|
+
html += '<tr><td>' + key + '</td><td>' + keyboardShortcuts[ key ] + '</td></tr>';
|
1461
|
+
}
|
1462
|
+
|
1463
|
+
html += '</table>';
|
1464
|
+
|
1465
|
+
dom.overlay.innerHTML = [
|
1466
|
+
'<header>',
|
1467
|
+
'<a class="close" href="#"><span class="icon"></span></a>',
|
1468
|
+
'</header>',
|
1469
|
+
'<div class="viewport">',
|
1470
|
+
'<div class="viewport-inner">'+ html +'</div>',
|
1471
|
+
'</div>'
|
1472
|
+
].join('');
|
1473
|
+
|
1474
|
+
dom.overlay.querySelector( '.close' ).addEventListener( 'click', function( event ) {
|
1475
|
+
closeOverlay();
|
1476
|
+
event.preventDefault();
|
1477
|
+
}, false );
|
1478
|
+
|
1479
|
+
setTimeout( function() {
|
1480
|
+
dom.overlay.classList.add( 'visible' );
|
1481
|
+
}, 1 );
|
1013
1482
|
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
/**
|
1488
|
+
* Closes any currently open overlay.
|
1489
|
+
*/
|
1490
|
+
function closeOverlay() {
|
1491
|
+
|
1492
|
+
if( dom.overlay ) {
|
1493
|
+
dom.overlay.parentNode.removeChild( dom.overlay );
|
1494
|
+
dom.overlay = null;
|
1018
1495
|
}
|
1019
1496
|
|
1020
1497
|
}
|
@@ -1027,54 +1504,50 @@ var Reveal = (function(){
|
|
1027
1504
|
|
1028
1505
|
if( dom.wrapper && !isPrintingPDF() ) {
|
1029
1506
|
|
1030
|
-
|
1031
|
-
var availableWidth = dom.wrapper.offsetWidth,
|
1032
|
-
availableHeight = dom.wrapper.offsetHeight;
|
1507
|
+
var size = getComputedSlideSize();
|
1033
1508
|
|
1034
|
-
//
|
1035
|
-
availableWidth -= ( availableHeight * config.margin );
|
1036
|
-
availableHeight -= ( availableHeight * config.margin );
|
1037
|
-
|
1038
|
-
// Dimensions of the content
|
1039
|
-
var slideWidth = config.width,
|
1040
|
-
slideHeight = config.height,
|
1041
|
-
slidePadding = 20; // TODO Dig this out of DOM
|
1509
|
+
var slidePadding = 20; // TODO Dig this out of DOM
|
1042
1510
|
|
1043
1511
|
// Layout the contents of the slides
|
1044
1512
|
layoutSlideContents( config.width, config.height, slidePadding );
|
1045
1513
|
|
1046
|
-
|
1047
|
-
|
1048
|
-
slideWidth = parseInt( slideWidth, 10 ) / 100 * availableWidth;
|
1049
|
-
}
|
1050
|
-
|
1051
|
-
// Slide height may be a percentage of available height
|
1052
|
-
if( typeof slideHeight === 'string' && /%$/.test( slideHeight ) ) {
|
1053
|
-
slideHeight = parseInt( slideHeight, 10 ) / 100 * availableHeight;
|
1054
|
-
}
|
1055
|
-
|
1056
|
-
dom.slides.style.width = slideWidth + 'px';
|
1057
|
-
dom.slides.style.height = slideHeight + 'px';
|
1514
|
+
dom.slides.style.width = size.width + 'px';
|
1515
|
+
dom.slides.style.height = size.height + 'px';
|
1058
1516
|
|
1059
1517
|
// Determine scale of content to fit within available space
|
1060
|
-
scale = Math.min(
|
1518
|
+
scale = Math.min( size.presentationWidth / size.width, size.presentationHeight / size.height );
|
1061
1519
|
|
1062
1520
|
// Respect max/min scale settings
|
1063
1521
|
scale = Math.max( scale, config.minScale );
|
1064
1522
|
scale = Math.min( scale, config.maxScale );
|
1065
1523
|
|
1066
|
-
//
|
1067
|
-
|
1068
|
-
|
1069
|
-
dom.slides.style.
|
1524
|
+
// Don't apply any scaling styles if scale is 1
|
1525
|
+
if( scale === 1 ) {
|
1526
|
+
dom.slides.style.zoom = '';
|
1527
|
+
dom.slides.style.left = '';
|
1528
|
+
dom.slides.style.top = '';
|
1529
|
+
dom.slides.style.bottom = '';
|
1530
|
+
dom.slides.style.right = '';
|
1531
|
+
transformSlides( { layout: '' } );
|
1070
1532
|
}
|
1071
|
-
// Apply scale transform as a fallback
|
1072
1533
|
else {
|
1073
|
-
|
1534
|
+
// Prefer zooming in desktop Chrome so that content remains crisp
|
1535
|
+
if( !isMobileDevice && /chrome/i.test( navigator.userAgent ) && typeof dom.slides.style.zoom !== 'undefined' ) {
|
1536
|
+
dom.slides.style.zoom = scale;
|
1537
|
+
transformSlides( { layout: '' } );
|
1538
|
+
}
|
1539
|
+
// Apply scale transform as a fallback
|
1540
|
+
else {
|
1541
|
+
dom.slides.style.left = '50%';
|
1542
|
+
dom.slides.style.top = '50%';
|
1543
|
+
dom.slides.style.bottom = 'auto';
|
1544
|
+
dom.slides.style.right = 'auto';
|
1545
|
+
transformSlides( { layout: 'translate(-50%, -50%) scale('+ scale +')' } );
|
1546
|
+
}
|
1074
1547
|
}
|
1075
1548
|
|
1076
1549
|
// Select all slides, vertical and horizontal
|
1077
|
-
var slides = toArray(
|
1550
|
+
var slides = toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) );
|
1078
1551
|
|
1079
1552
|
for( var i = 0, len = slides.length; i < len; i++ ) {
|
1080
1553
|
var slide = slides[ i ];
|
@@ -1091,7 +1564,7 @@ var Reveal = (function(){
|
|
1091
1564
|
slide.style.top = 0;
|
1092
1565
|
}
|
1093
1566
|
else {
|
1094
|
-
slide.style.top = Math.max(
|
1567
|
+
slide.style.top = Math.max( ( ( size.height - getAbsoluteHeight( slide ) ) / 2 ) - slidePadding, 0 ) + 'px';
|
1095
1568
|
}
|
1096
1569
|
}
|
1097
1570
|
else {
|
@@ -1117,7 +1590,7 @@ var Reveal = (function(){
|
|
1117
1590
|
toArray( dom.slides.querySelectorAll( 'section > .stretch' ) ).forEach( function( element ) {
|
1118
1591
|
|
1119
1592
|
// Determine how much vertical space we can use
|
1120
|
-
var remainingHeight = getRemainingHeight( element,
|
1593
|
+
var remainingHeight = getRemainingHeight( element, height );
|
1121
1594
|
|
1122
1595
|
// Consider the aspect ratio of media elements
|
1123
1596
|
if( /(img|video)/gi.test( element.nodeName ) ) {
|
@@ -1139,6 +1612,41 @@ var Reveal = (function(){
|
|
1139
1612
|
|
1140
1613
|
}
|
1141
1614
|
|
1615
|
+
/**
|
1616
|
+
* Calculates the computed pixel size of our slides. These
|
1617
|
+
* values are based on the width and height configuration
|
1618
|
+
* options.
|
1619
|
+
*/
|
1620
|
+
function getComputedSlideSize( presentationWidth, presentationHeight ) {
|
1621
|
+
|
1622
|
+
var size = {
|
1623
|
+
// Slide size
|
1624
|
+
width: config.width,
|
1625
|
+
height: config.height,
|
1626
|
+
|
1627
|
+
// Presentation size
|
1628
|
+
presentationWidth: presentationWidth || dom.wrapper.offsetWidth,
|
1629
|
+
presentationHeight: presentationHeight || dom.wrapper.offsetHeight
|
1630
|
+
};
|
1631
|
+
|
1632
|
+
// Reduce available space by margin
|
1633
|
+
size.presentationWidth -= ( size.presentationWidth * config.margin );
|
1634
|
+
size.presentationHeight -= ( size.presentationHeight * config.margin );
|
1635
|
+
|
1636
|
+
// Slide width may be a percentage of available width
|
1637
|
+
if( typeof size.width === 'string' && /%$/.test( size.width ) ) {
|
1638
|
+
size.width = parseInt( size.width, 10 ) / 100 * size.presentationWidth;
|
1639
|
+
}
|
1640
|
+
|
1641
|
+
// Slide height may be a percentage of available height
|
1642
|
+
if( typeof size.height === 'string' && /%$/.test( size.height ) ) {
|
1643
|
+
size.height = parseInt( size.height, 10 ) / 100 * size.presentationHeight;
|
1644
|
+
}
|
1645
|
+
|
1646
|
+
return size;
|
1647
|
+
|
1648
|
+
}
|
1649
|
+
|
1142
1650
|
/**
|
1143
1651
|
* Stores the vertical index of a stack so that the same
|
1144
1652
|
* vertical slide can be selected when navigating to and
|
@@ -1176,92 +1684,122 @@ var Reveal = (function(){
|
|
1176
1684
|
}
|
1177
1685
|
|
1178
1686
|
/**
|
1179
|
-
* Displays the overview of slides (quick nav) by
|
1180
|
-
*
|
1181
|
-
*
|
1182
|
-
* Experimental feature, might be dropped if perf
|
1183
|
-
* can't be improved.
|
1687
|
+
* Displays the overview of slides (quick nav) by scaling
|
1688
|
+
* down and arranging all slide elements.
|
1184
1689
|
*/
|
1185
1690
|
function activateOverview() {
|
1186
1691
|
|
1187
1692
|
// Only proceed if enabled in config
|
1188
|
-
if( config.overview ) {
|
1693
|
+
if( config.overview && !isOverview() ) {
|
1189
1694
|
|
1190
|
-
|
1191
|
-
cancelAutoSlide();
|
1192
|
-
|
1193
|
-
var wasActive = dom.wrapper.classList.contains( 'overview' );
|
1194
|
-
|
1195
|
-
// Vary the depth of the overview based on screen size
|
1196
|
-
var depth = window.innerWidth < 400 ? 1000 : 2500;
|
1695
|
+
overview = true;
|
1197
1696
|
|
1198
1697
|
dom.wrapper.classList.add( 'overview' );
|
1199
1698
|
dom.wrapper.classList.remove( 'overview-deactivating' );
|
1200
1699
|
|
1201
|
-
|
1202
|
-
|
1700
|
+
if( features.overviewTransitions ) {
|
1701
|
+
setTimeout( function() {
|
1702
|
+
dom.wrapper.classList.add( 'overview-animated' );
|
1703
|
+
}, 1 );
|
1704
|
+
}
|
1203
1705
|
|
1204
|
-
//
|
1205
|
-
|
1206
|
-
// before we can position them
|
1207
|
-
activateOverviewTimeout = setTimeout( function() {
|
1706
|
+
// Don't auto-slide while in overview mode
|
1707
|
+
cancelAutoSlide();
|
1208
1708
|
|
1209
|
-
|
1709
|
+
// Move the backgrounds element into the slide container to
|
1710
|
+
// that the same scaling is applied
|
1711
|
+
dom.slides.appendChild( dom.background );
|
1210
1712
|
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1713
|
+
// Clicking on an overview slide navigates to it
|
1714
|
+
toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) {
|
1715
|
+
if( !slide.classList.contains( 'stack' ) ) {
|
1716
|
+
slide.addEventListener( 'click', onOverviewSlideClicked, true );
|
1717
|
+
}
|
1718
|
+
} );
|
1214
1719
|
|
1215
|
-
|
1720
|
+
updateSlidesVisibility();
|
1721
|
+
layoutOverview();
|
1722
|
+
updateOverview();
|
1216
1723
|
|
1217
|
-
|
1218
|
-
transformElement( hslide, 'translateZ(-'+ depth +'px) translate(' + ( ( i - indexh ) * hoffset ) + '%, 0%)' );
|
1724
|
+
layout();
|
1219
1725
|
|
1220
|
-
|
1726
|
+
// Notify observers of the overview showing
|
1727
|
+
dispatchEvent( 'overviewshown', {
|
1728
|
+
'indexh': indexh,
|
1729
|
+
'indexv': indexv,
|
1730
|
+
'currentSlide': currentSlide
|
1731
|
+
} );
|
1221
1732
|
|
1222
|
-
|
1733
|
+
}
|
1223
1734
|
|
1224
|
-
|
1225
|
-
var verticalIndex = i === indexh ? indexv : getPreviousVerticalIndex( hslide );
|
1735
|
+
}
|
1226
1736
|
|
1227
|
-
|
1737
|
+
/**
|
1738
|
+
* Uses CSS transforms to position all slides in a grid for
|
1739
|
+
* display inside of the overview mode.
|
1740
|
+
*/
|
1741
|
+
function layoutOverview() {
|
1228
1742
|
|
1229
|
-
|
1230
|
-
|
1743
|
+
var margin = 70;
|
1744
|
+
var slideWidth = config.width + margin,
|
1745
|
+
slideHeight = config.height + margin;
|
1231
1746
|
|
1232
|
-
|
1233
|
-
|
1747
|
+
// Reverse in RTL mode
|
1748
|
+
if( config.rtl ) {
|
1749
|
+
slideWidth = -slideWidth;
|
1750
|
+
}
|
1234
1751
|
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1752
|
+
// Layout slides
|
1753
|
+
toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).forEach( function( hslide, h ) {
|
1754
|
+
hslide.setAttribute( 'data-index-h', h );
|
1755
|
+
transformElement( hslide, 'translate3d(' + ( h * slideWidth ) + 'px, 0, 0)' );
|
1238
1756
|
|
1239
|
-
|
1240
|
-
else {
|
1757
|
+
if( hslide.classList.contains( 'stack' ) ) {
|
1241
1758
|
|
1242
|
-
|
1243
|
-
|
1759
|
+
toArray( hslide.querySelectorAll( 'section' ) ).forEach( function( vslide, v ) {
|
1760
|
+
vslide.setAttribute( 'data-index-h', h );
|
1761
|
+
vslide.setAttribute( 'data-index-v', v );
|
1244
1762
|
|
1245
|
-
|
1246
|
-
}
|
1763
|
+
transformElement( vslide, 'translate3d(0, ' + ( v * slideHeight ) + 'px, 0)' );
|
1764
|
+
} );
|
1247
1765
|
|
1248
|
-
|
1766
|
+
}
|
1767
|
+
} );
|
1249
1768
|
|
1250
|
-
|
1769
|
+
// Layout slide backgrounds
|
1770
|
+
toArray( dom.background.childNodes ).forEach( function( hbackground, h ) {
|
1771
|
+
transformElement( hbackground, 'translate3d(' + ( h * slideWidth ) + 'px, 0, 0)' );
|
1251
1772
|
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
'indexv': indexv,
|
1257
|
-
'currentSlide': currentSlide
|
1258
|
-
} );
|
1259
|
-
}
|
1773
|
+
toArray( hbackground.querySelectorAll( '.slide-background' ) ).forEach( function( vbackground, v ) {
|
1774
|
+
transformElement( vbackground, 'translate3d(0, ' + ( v * slideHeight ) + 'px, 0)' );
|
1775
|
+
} );
|
1776
|
+
} );
|
1260
1777
|
|
1261
|
-
|
1778
|
+
}
|
1262
1779
|
|
1780
|
+
/**
|
1781
|
+
* Moves the overview viewport to the current slides.
|
1782
|
+
* Called each time the current slide changes.
|
1783
|
+
*/
|
1784
|
+
function updateOverview() {
|
1785
|
+
|
1786
|
+
var margin = 70;
|
1787
|
+
var slideWidth = config.width + margin,
|
1788
|
+
slideHeight = config.height + margin;
|
1789
|
+
|
1790
|
+
// Reverse in RTL mode
|
1791
|
+
if( config.rtl ) {
|
1792
|
+
slideWidth = -slideWidth;
|
1263
1793
|
}
|
1264
1794
|
|
1795
|
+
transformSlides( {
|
1796
|
+
overview: [
|
1797
|
+
'translateX('+ ( -indexh * slideWidth ) +'px)',
|
1798
|
+
'translateY('+ ( -indexv * slideHeight ) +'px)',
|
1799
|
+
'translateZ('+ ( window.innerWidth < 400 ? -1000 : -2500 ) +'px)'
|
1800
|
+
].join( ' ' )
|
1801
|
+
} );
|
1802
|
+
|
1265
1803
|
}
|
1266
1804
|
|
1267
1805
|
/**
|
@@ -1273,30 +1811,41 @@ var Reveal = (function(){
|
|
1273
1811
|
// Only proceed if enabled in config
|
1274
1812
|
if( config.overview ) {
|
1275
1813
|
|
1276
|
-
|
1277
|
-
clearTimeout( deactivateOverviewTimeout );
|
1814
|
+
overview = false;
|
1278
1815
|
|
1279
1816
|
dom.wrapper.classList.remove( 'overview' );
|
1817
|
+
dom.wrapper.classList.remove( 'overview-animated' );
|
1280
1818
|
|
1281
1819
|
// Temporarily add a class so that transitions can do different things
|
1282
1820
|
// depending on whether they are exiting/entering overview, or just
|
1283
1821
|
// moving from slide to slide
|
1284
1822
|
dom.wrapper.classList.add( 'overview-deactivating' );
|
1285
1823
|
|
1286
|
-
|
1824
|
+
setTimeout( function () {
|
1287
1825
|
dom.wrapper.classList.remove( 'overview-deactivating' );
|
1288
1826
|
}, 1 );
|
1289
1827
|
|
1290
|
-
//
|
1291
|
-
|
1292
|
-
|
1828
|
+
// Move the background element back out
|
1829
|
+
dom.wrapper.appendChild( dom.background );
|
1830
|
+
|
1831
|
+
// Clean up changes made to slides
|
1832
|
+
toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) {
|
1293
1833
|
transformElement( slide, '' );
|
1294
1834
|
|
1295
1835
|
slide.removeEventListener( 'click', onOverviewSlideClicked, true );
|
1296
1836
|
} );
|
1297
1837
|
|
1838
|
+
// Clean up changes made to backgrounds
|
1839
|
+
toArray( dom.background.querySelectorAll( '.slide-background' ) ).forEach( function( background ) {
|
1840
|
+
transformElement( background, '' );
|
1841
|
+
} );
|
1842
|
+
|
1843
|
+
transformSlides( { overview: '' } );
|
1844
|
+
|
1298
1845
|
slide( indexh, indexv );
|
1299
1846
|
|
1847
|
+
layout();
|
1848
|
+
|
1300
1849
|
cueAutoSlide();
|
1301
1850
|
|
1302
1851
|
// Notify observers of the overview hiding
|
@@ -1335,7 +1884,7 @@ var Reveal = (function(){
|
|
1335
1884
|
*/
|
1336
1885
|
function isOverview() {
|
1337
1886
|
|
1338
|
-
return
|
1887
|
+
return overview;
|
1339
1888
|
|
1340
1889
|
}
|
1341
1890
|
|
@@ -1367,10 +1916,10 @@ var Reveal = (function(){
|
|
1367
1916
|
|
1368
1917
|
// Check which implementation is available
|
1369
1918
|
var requestMethod = element.requestFullScreen ||
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1919
|
+
element.webkitRequestFullscreen ||
|
1920
|
+
element.webkitRequestFullScreen ||
|
1921
|
+
element.mozRequestFullScreen ||
|
1922
|
+
element.msRequestFullscreen;
|
1374
1923
|
|
1375
1924
|
if( requestMethod ) {
|
1376
1925
|
requestMethod.apply( element );
|
@@ -1384,13 +1933,15 @@ var Reveal = (function(){
|
|
1384
1933
|
*/
|
1385
1934
|
function pause() {
|
1386
1935
|
|
1387
|
-
|
1936
|
+
if( config.pause ) {
|
1937
|
+
var wasPaused = dom.wrapper.classList.contains( 'paused' );
|
1388
1938
|
|
1389
|
-
|
1390
|
-
|
1939
|
+
cancelAutoSlide();
|
1940
|
+
dom.wrapper.classList.add( 'paused' );
|
1391
1941
|
|
1392
|
-
|
1393
|
-
|
1942
|
+
if( wasPaused === false ) {
|
1943
|
+
dispatchEvent( 'paused' );
|
1944
|
+
}
|
1394
1945
|
}
|
1395
1946
|
|
1396
1947
|
}
|
@@ -1414,13 +1965,13 @@ var Reveal = (function(){
|
|
1414
1965
|
/**
|
1415
1966
|
* Toggles the paused mode on and off.
|
1416
1967
|
*/
|
1417
|
-
function togglePause() {
|
1968
|
+
function togglePause( override ) {
|
1418
1969
|
|
1419
|
-
if(
|
1420
|
-
resume();
|
1970
|
+
if( typeof override === 'boolean' ) {
|
1971
|
+
override ? pause() : resume();
|
1421
1972
|
}
|
1422
1973
|
else {
|
1423
|
-
pause();
|
1974
|
+
isPaused() ? resume() : pause();
|
1424
1975
|
}
|
1425
1976
|
|
1426
1977
|
}
|
@@ -1434,6 +1985,34 @@ var Reveal = (function(){
|
|
1434
1985
|
|
1435
1986
|
}
|
1436
1987
|
|
1988
|
+
/**
|
1989
|
+
* Toggles the auto slide mode on and off.
|
1990
|
+
*
|
1991
|
+
* @param {Boolean} override Optional flag which sets the desired state.
|
1992
|
+
* True means autoplay starts, false means it stops.
|
1993
|
+
*/
|
1994
|
+
|
1995
|
+
function toggleAutoSlide( override ) {
|
1996
|
+
|
1997
|
+
if( typeof override === 'boolean' ) {
|
1998
|
+
override ? resumeAutoSlide() : pauseAutoSlide();
|
1999
|
+
}
|
2000
|
+
|
2001
|
+
else {
|
2002
|
+
autoSlidePaused ? resumeAutoSlide() : pauseAutoSlide();
|
2003
|
+
}
|
2004
|
+
|
2005
|
+
}
|
2006
|
+
|
2007
|
+
/**
|
2008
|
+
* Checks if the auto slide mode is currently on.
|
2009
|
+
*/
|
2010
|
+
function isAutoSliding() {
|
2011
|
+
|
2012
|
+
return !!( autoSlide && !autoSlidePaused );
|
2013
|
+
|
2014
|
+
}
|
2015
|
+
|
1437
2016
|
/**
|
1438
2017
|
* Steps from the current point in the presentation to the
|
1439
2018
|
* slide which matches the specified horizontal and vertical
|
@@ -1451,11 +2030,11 @@ var Reveal = (function(){
|
|
1451
2030
|
previousSlide = currentSlide;
|
1452
2031
|
|
1453
2032
|
// Query all horizontal slides in the deck
|
1454
|
-
var horizontalSlides =
|
2033
|
+
var horizontalSlides = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
|
1455
2034
|
|
1456
2035
|
// If no vertical index is specified and the upcoming slide is a
|
1457
2036
|
// stack, resume at its previous vertical index
|
1458
|
-
if( v === undefined ) {
|
2037
|
+
if( v === undefined && !isOverview() ) {
|
1459
2038
|
v = getPreviousVerticalIndex( horizontalSlides[ h ] );
|
1460
2039
|
}
|
1461
2040
|
|
@@ -1505,9 +2084,9 @@ var Reveal = (function(){
|
|
1505
2084
|
document.documentElement.classList.remove( stateBefore.pop() );
|
1506
2085
|
}
|
1507
2086
|
|
1508
|
-
//
|
2087
|
+
// Update the overview if it's currently active
|
1509
2088
|
if( isOverview() ) {
|
1510
|
-
|
2089
|
+
updateOverview();
|
1511
2090
|
}
|
1512
2091
|
|
1513
2092
|
// Find the current horizontal slide and any possible vertical slides
|
@@ -1544,13 +2123,14 @@ var Reveal = (function(){
|
|
1544
2123
|
// stacks
|
1545
2124
|
if( previousSlide ) {
|
1546
2125
|
previousSlide.classList.remove( 'present' );
|
2126
|
+
previousSlide.setAttribute( 'aria-hidden', 'true' );
|
1547
2127
|
|
1548
2128
|
// Reset all slides upon navigate to home
|
1549
2129
|
// Issue: #285
|
1550
|
-
if (
|
2130
|
+
if ( dom.wrapper.querySelector( HOME_SLIDE_SELECTOR ).classList.contains( 'present' ) ) {
|
1551
2131
|
// Launch async task
|
1552
2132
|
setTimeout( function () {
|
1553
|
-
var slides = toArray(
|
2133
|
+
var slides = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.stack') ), i;
|
1554
2134
|
for( i in slides ) {
|
1555
2135
|
if( slides[i] ) {
|
1556
2136
|
// Reset stack
|
@@ -1562,11 +2142,14 @@ var Reveal = (function(){
|
|
1562
2142
|
}
|
1563
2143
|
|
1564
2144
|
// Handle embedded content
|
1565
|
-
if( slideChanged ) {
|
2145
|
+
if( slideChanged || !previousSlide ) {
|
1566
2146
|
stopEmbeddedContent( previousSlide );
|
1567
2147
|
startEmbeddedContent( currentSlide );
|
1568
2148
|
}
|
1569
2149
|
|
2150
|
+
// Announce the current slide contents, for screen readers
|
2151
|
+
dom.statusDiv.textContent = currentSlide.textContent;
|
2152
|
+
|
1570
2153
|
updateControls();
|
1571
2154
|
updateProgress();
|
1572
2155
|
updateBackground();
|
@@ -1603,12 +2186,23 @@ var Reveal = (function(){
|
|
1603
2186
|
// Re-create the slide backgrounds
|
1604
2187
|
createBackgrounds();
|
1605
2188
|
|
2189
|
+
// Write the current hash to the URL
|
2190
|
+
writeURL();
|
2191
|
+
|
1606
2192
|
sortAllFragments();
|
1607
2193
|
|
1608
2194
|
updateControls();
|
1609
2195
|
updateProgress();
|
1610
2196
|
updateBackground( true );
|
1611
2197
|
updateSlideNumber();
|
2198
|
+
updateSlidesVisibility();
|
2199
|
+
|
2200
|
+
formatEmbeddedContent();
|
2201
|
+
startEmbeddedContent( currentSlide );
|
2202
|
+
|
2203
|
+
if( isOverview() ) {
|
2204
|
+
layoutOverview();
|
2205
|
+
}
|
1612
2206
|
|
1613
2207
|
}
|
1614
2208
|
|
@@ -1618,7 +2212,7 @@ var Reveal = (function(){
|
|
1618
2212
|
*/
|
1619
2213
|
function resetVerticalSlides() {
|
1620
2214
|
|
1621
|
-
var horizontalSlides = toArray(
|
2215
|
+
var horizontalSlides = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
|
1622
2216
|
horizontalSlides.forEach( function( horizontalSlide ) {
|
1623
2217
|
|
1624
2218
|
var verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) );
|
@@ -1628,6 +2222,7 @@ var Reveal = (function(){
|
|
1628
2222
|
verticalSlide.classList.remove( 'present' );
|
1629
2223
|
verticalSlide.classList.remove( 'past' );
|
1630
2224
|
verticalSlide.classList.add( 'future' );
|
2225
|
+
verticalSlide.setAttribute( 'aria-hidden', 'true' );
|
1631
2226
|
}
|
1632
2227
|
|
1633
2228
|
} );
|
@@ -1642,7 +2237,7 @@ var Reveal = (function(){
|
|
1642
2237
|
*/
|
1643
2238
|
function sortAllFragments() {
|
1644
2239
|
|
1645
|
-
var horizontalSlides = toArray(
|
2240
|
+
var horizontalSlides = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
|
1646
2241
|
horizontalSlides.forEach( function( horizontalSlide ) {
|
1647
2242
|
|
1648
2243
|
var verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) );
|
@@ -1675,9 +2270,11 @@ var Reveal = (function(){
|
|
1675
2270
|
|
1676
2271
|
// Select all slides and convert the NodeList result to
|
1677
2272
|
// an array
|
1678
|
-
var slides = toArray(
|
2273
|
+
var slides = toArray( dom.wrapper.querySelectorAll( selector ) ),
|
1679
2274
|
slidesLength = slides.length;
|
1680
2275
|
|
2276
|
+
var printMode = isPrintingPDF();
|
2277
|
+
|
1681
2278
|
if( slidesLength ) {
|
1682
2279
|
|
1683
2280
|
// Should the index loop?
|
@@ -1703,43 +2300,55 @@ var Reveal = (function(){
|
|
1703
2300
|
|
1704
2301
|
// http://www.w3.org/html/wg/drafts/html/master/editing.html#the-hidden-attribute
|
1705
2302
|
element.setAttribute( 'hidden', '' );
|
2303
|
+
element.setAttribute( 'aria-hidden', 'true' );
|
2304
|
+
|
2305
|
+
// If this element contains vertical slides
|
2306
|
+
if( element.querySelector( 'section' ) ) {
|
2307
|
+
element.classList.add( 'stack' );
|
2308
|
+
}
|
2309
|
+
|
2310
|
+
// If we're printing static slides, all slides are "present"
|
2311
|
+
if( printMode ) {
|
2312
|
+
element.classList.add( 'present' );
|
2313
|
+
continue;
|
2314
|
+
}
|
1706
2315
|
|
1707
2316
|
if( i < index ) {
|
1708
2317
|
// Any element previous to index is given the 'past' class
|
1709
2318
|
element.classList.add( reverse ? 'future' : 'past' );
|
1710
2319
|
|
1711
|
-
|
2320
|
+
if( config.fragments ) {
|
2321
|
+
var pastFragments = toArray( element.querySelectorAll( '.fragment' ) );
|
1712
2322
|
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
2323
|
+
// Show all fragments on prior slides
|
2324
|
+
while( pastFragments.length ) {
|
2325
|
+
var pastFragment = pastFragments.pop();
|
2326
|
+
pastFragment.classList.add( 'visible' );
|
2327
|
+
pastFragment.classList.remove( 'current-fragment' );
|
2328
|
+
}
|
1718
2329
|
}
|
1719
2330
|
}
|
1720
2331
|
else if( i > index ) {
|
1721
2332
|
// Any element subsequent to index is given the 'future' class
|
1722
2333
|
element.classList.add( reverse ? 'past' : 'future' );
|
1723
2334
|
|
1724
|
-
|
2335
|
+
if( config.fragments ) {
|
2336
|
+
var futureFragments = toArray( element.querySelectorAll( '.fragment.visible' ) );
|
1725
2337
|
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
1730
|
-
|
2338
|
+
// No fragments in future slides should be visible ahead of time
|
2339
|
+
while( futureFragments.length ) {
|
2340
|
+
var futureFragment = futureFragments.pop();
|
2341
|
+
futureFragment.classList.remove( 'visible' );
|
2342
|
+
futureFragment.classList.remove( 'current-fragment' );
|
2343
|
+
}
|
1731
2344
|
}
|
1732
2345
|
}
|
1733
|
-
|
1734
|
-
// If this element contains vertical slides
|
1735
|
-
if( element.querySelector( 'section' ) ) {
|
1736
|
-
element.classList.add( 'stack' );
|
1737
|
-
}
|
1738
2346
|
}
|
1739
2347
|
|
1740
2348
|
// Mark the current slide as present
|
1741
2349
|
slides[index].classList.add( 'present' );
|
1742
2350
|
slides[index].removeAttribute( 'hidden' );
|
2351
|
+
slides[index].removeAttribute( 'aria-hidden' );
|
1743
2352
|
|
1744
2353
|
// If this slide has a state associated with it, add it
|
1745
2354
|
// onto the current state of the deck
|
@@ -1767,12 +2376,12 @@ var Reveal = (function(){
|
|
1767
2376
|
|
1768
2377
|
// Select all slides and convert the NodeList result to
|
1769
2378
|
// an array
|
1770
|
-
var horizontalSlides = toArray(
|
2379
|
+
var horizontalSlides = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ),
|
1771
2380
|
horizontalSlidesLength = horizontalSlides.length,
|
1772
2381
|
distanceX,
|
1773
2382
|
distanceY;
|
1774
2383
|
|
1775
|
-
if( horizontalSlidesLength ) {
|
2384
|
+
if( horizontalSlidesLength && typeof indexh !== 'undefined' ) {
|
1776
2385
|
|
1777
2386
|
// The number of steps away from the present slide that will
|
1778
2387
|
// be visible
|
@@ -1780,7 +2389,12 @@ var Reveal = (function(){
|
|
1780
2389
|
|
1781
2390
|
// Limit view distance on weaker devices
|
1782
2391
|
if( isMobileDevice ) {
|
1783
|
-
viewDistance = isOverview() ? 6 :
|
2392
|
+
viewDistance = isOverview() ? 6 : 2;
|
2393
|
+
}
|
2394
|
+
|
2395
|
+
// All slides need to be visible when exporting to PDF
|
2396
|
+
if( isPrintingPDF() ) {
|
2397
|
+
viewDistance = Number.MAX_VALUE;
|
1784
2398
|
}
|
1785
2399
|
|
1786
2400
|
for( var x = 0; x < horizontalSlidesLength; x++ ) {
|
@@ -1789,11 +2403,22 @@ var Reveal = (function(){
|
|
1789
2403
|
var verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) ),
|
1790
2404
|
verticalSlidesLength = verticalSlides.length;
|
1791
2405
|
|
1792
|
-
//
|
1793
|
-
distanceX = Math.abs( ( indexh
|
2406
|
+
// Determine how far away this slide is from the present
|
2407
|
+
distanceX = Math.abs( ( indexh || 0 ) - x ) || 0;
|
2408
|
+
|
2409
|
+
// If the presentation is looped, distance should measure
|
2410
|
+
// 1 between the first and last slides
|
2411
|
+
if( config.loop ) {
|
2412
|
+
distanceX = Math.abs( ( ( indexh || 0 ) - x ) % ( horizontalSlidesLength - viewDistance ) ) || 0;
|
2413
|
+
}
|
1794
2414
|
|
1795
2415
|
// Show the horizontal slide if it's within the view distance
|
1796
|
-
|
2416
|
+
if( distanceX < viewDistance ) {
|
2417
|
+
showSlide( horizontalSlide );
|
2418
|
+
}
|
2419
|
+
else {
|
2420
|
+
hideSlide( horizontalSlide );
|
2421
|
+
}
|
1797
2422
|
|
1798
2423
|
if( verticalSlidesLength ) {
|
1799
2424
|
|
@@ -1802,9 +2427,14 @@ var Reveal = (function(){
|
|
1802
2427
|
for( var y = 0; y < verticalSlidesLength; y++ ) {
|
1803
2428
|
var verticalSlide = verticalSlides[y];
|
1804
2429
|
|
1805
|
-
distanceY = x === indexh ? Math.abs( indexv - y ) : Math.abs( y - oy );
|
2430
|
+
distanceY = x === ( indexh || 0 ) ? Math.abs( ( indexv || 0 ) - y ) : Math.abs( y - oy );
|
1806
2431
|
|
1807
|
-
|
2432
|
+
if( distanceX + distanceY < viewDistance ) {
|
2433
|
+
showSlide( verticalSlide );
|
2434
|
+
}
|
2435
|
+
else {
|
2436
|
+
hideSlide( verticalSlide );
|
2437
|
+
}
|
1808
2438
|
}
|
1809
2439
|
|
1810
2440
|
}
|
@@ -1820,44 +2450,9 @@ var Reveal = (function(){
|
|
1820
2450
|
function updateProgress() {
|
1821
2451
|
|
1822
2452
|
// Update progress if enabled
|
1823
|
-
if( config.progress && dom.
|
1824
|
-
|
1825
|
-
var horizontalSlides = toArray( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
|
1826
|
-
|
1827
|
-
// The number of past and total slides
|
1828
|
-
var totalCount = document.querySelectorAll( SLIDES_SELECTOR + ':not(.stack)' ).length;
|
1829
|
-
var pastCount = 0;
|
1830
|
-
|
1831
|
-
// Step through all slides and count the past ones
|
1832
|
-
mainLoop: for( var i = 0; i < horizontalSlides.length; i++ ) {
|
1833
|
-
|
1834
|
-
var horizontalSlide = horizontalSlides[i];
|
1835
|
-
var verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) );
|
1836
|
-
|
1837
|
-
for( var j = 0; j < verticalSlides.length; j++ ) {
|
1838
|
-
|
1839
|
-
// Stop as soon as we arrive at the present
|
1840
|
-
if( verticalSlides[j].classList.contains( 'present' ) ) {
|
1841
|
-
break mainLoop;
|
1842
|
-
}
|
2453
|
+
if( config.progress && dom.progressbar ) {
|
1843
2454
|
|
1844
|
-
|
1845
|
-
|
1846
|
-
}
|
1847
|
-
|
1848
|
-
// Stop as soon as we arrive at the present
|
1849
|
-
if( horizontalSlide.classList.contains( 'present' ) ) {
|
1850
|
-
break;
|
1851
|
-
}
|
1852
|
-
|
1853
|
-
// Don't count the wrapping section for vertical slides
|
1854
|
-
if( horizontalSlide.classList.contains( 'stack' ) === false ) {
|
1855
|
-
pastCount++;
|
1856
|
-
}
|
1857
|
-
|
1858
|
-
}
|
1859
|
-
|
1860
|
-
dom.progressbar.style.width = ( pastCount / ( totalCount - 1 ) ) * window.innerWidth + 'px';
|
2455
|
+
dom.progressbar.style.width = getProgress() * dom.wrapper.offsetWidth + 'px';
|
1861
2456
|
|
1862
2457
|
}
|
1863
2458
|
|
@@ -1865,19 +2460,31 @@ var Reveal = (function(){
|
|
1865
2460
|
|
1866
2461
|
/**
|
1867
2462
|
* Updates the slide number div to reflect the current slide.
|
2463
|
+
*
|
2464
|
+
* Slide number format can be defined as a string using the
|
2465
|
+
* following variables:
|
2466
|
+
* h: current slide's horizontal index
|
2467
|
+
* v: current slide's vertical index
|
2468
|
+
* c: current slide index (flattened)
|
2469
|
+
* t: total number of slides (flattened)
|
1868
2470
|
*/
|
1869
2471
|
function updateSlideNumber() {
|
1870
2472
|
|
1871
2473
|
// Update slide number if enabled
|
1872
2474
|
if( config.slideNumber && dom.slideNumber) {
|
1873
2475
|
|
1874
|
-
//
|
1875
|
-
var
|
1876
|
-
|
1877
|
-
|
2476
|
+
// Default to only showing the current slide number
|
2477
|
+
var format = 'c';
|
2478
|
+
|
2479
|
+
// Check if a custom slide number format is available
|
2480
|
+
if( typeof config.slideNumber === 'string' ) {
|
2481
|
+
format = config.slideNumber;
|
1878
2482
|
}
|
1879
2483
|
|
1880
|
-
dom.slideNumber.innerHTML =
|
2484
|
+
dom.slideNumber.innerHTML = format.replace( /h/g, indexh )
|
2485
|
+
.replace( /v/g, indexv )
|
2486
|
+
.replace( /c/g, getSlidePastCount() + 1 )
|
2487
|
+
.replace( /t/g, getTotalSlides() );
|
1881
2488
|
}
|
1882
2489
|
|
1883
2490
|
}
|
@@ -1892,13 +2499,13 @@ var Reveal = (function(){
|
|
1892
2499
|
|
1893
2500
|
// Remove the 'enabled' class from all directions
|
1894
2501
|
dom.controlsLeft.concat( dom.controlsRight )
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
1899
|
-
|
1900
|
-
|
1901
|
-
|
2502
|
+
.concat( dom.controlsUp )
|
2503
|
+
.concat( dom.controlsDown )
|
2504
|
+
.concat( dom.controlsPrev )
|
2505
|
+
.concat( dom.controlsNext ).forEach( function( node ) {
|
2506
|
+
node.classList.remove( 'enabled' );
|
2507
|
+
node.classList.remove( 'fragmented' );
|
2508
|
+
} );
|
1902
2509
|
|
1903
2510
|
// Add the 'enabled' class to the available routes
|
1904
2511
|
if( routes.left ) dom.controlsLeft.forEach( function( el ) { el.classList.add( 'enabled' ); } );
|
@@ -1951,43 +2558,76 @@ var Reveal = (function(){
|
|
1951
2558
|
// states of their slides (past/present/future)
|
1952
2559
|
toArray( dom.background.childNodes ).forEach( function( backgroundh, h ) {
|
1953
2560
|
|
2561
|
+
backgroundh.classList.remove( 'past' );
|
2562
|
+
backgroundh.classList.remove( 'present' );
|
2563
|
+
backgroundh.classList.remove( 'future' );
|
2564
|
+
|
1954
2565
|
if( h < indexh ) {
|
1955
|
-
backgroundh.
|
2566
|
+
backgroundh.classList.add( horizontalPast );
|
1956
2567
|
}
|
1957
2568
|
else if ( h > indexh ) {
|
1958
|
-
backgroundh.
|
2569
|
+
backgroundh.classList.add( horizontalFuture );
|
1959
2570
|
}
|
1960
2571
|
else {
|
1961
|
-
backgroundh.
|
2572
|
+
backgroundh.classList.add( 'present' );
|
1962
2573
|
|
1963
2574
|
// Store a reference to the current background element
|
1964
2575
|
currentBackground = backgroundh;
|
1965
2576
|
}
|
1966
2577
|
|
1967
2578
|
if( includeAll || h === indexh ) {
|
1968
|
-
toArray( backgroundh.
|
2579
|
+
toArray( backgroundh.querySelectorAll( '.slide-background' ) ).forEach( function( backgroundv, v ) {
|
2580
|
+
|
2581
|
+
backgroundv.classList.remove( 'past' );
|
2582
|
+
backgroundv.classList.remove( 'present' );
|
2583
|
+
backgroundv.classList.remove( 'future' );
|
1969
2584
|
|
1970
2585
|
if( v < indexv ) {
|
1971
|
-
backgroundv.
|
2586
|
+
backgroundv.classList.add( 'past' );
|
1972
2587
|
}
|
1973
2588
|
else if ( v > indexv ) {
|
1974
|
-
backgroundv.
|
2589
|
+
backgroundv.classList.add( 'future' );
|
1975
2590
|
}
|
1976
2591
|
else {
|
1977
|
-
backgroundv.
|
2592
|
+
backgroundv.classList.add( 'present' );
|
1978
2593
|
|
1979
2594
|
// Only if this is the present horizontal and vertical slide
|
1980
2595
|
if( h === indexh ) currentBackground = backgroundv;
|
1981
2596
|
}
|
1982
2597
|
|
1983
|
-
} );
|
2598
|
+
} );
|
2599
|
+
}
|
2600
|
+
|
2601
|
+
} );
|
2602
|
+
|
2603
|
+
// Stop any currently playing video background
|
2604
|
+
if( previousBackground ) {
|
2605
|
+
|
2606
|
+
var previousVideo = previousBackground.querySelector( 'video' );
|
2607
|
+
if( previousVideo ) previousVideo.pause();
|
2608
|
+
|
2609
|
+
}
|
2610
|
+
|
2611
|
+
if( currentBackground ) {
|
2612
|
+
|
2613
|
+
// Start video playback
|
2614
|
+
var currentVideo = currentBackground.querySelector( 'video' );
|
2615
|
+
if( currentVideo ) {
|
2616
|
+
currentVideo.currentTime = 0;
|
2617
|
+
currentVideo.play();
|
1984
2618
|
}
|
1985
2619
|
|
1986
|
-
|
2620
|
+
var backgroundImageURL = currentBackground.style.backgroundImage || '';
|
1987
2621
|
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
2622
|
+
// Restart GIFs (doesn't work in Firefox)
|
2623
|
+
if( /\.gif/i.test( backgroundImageURL ) ) {
|
2624
|
+
currentBackground.style.backgroundImage = '';
|
2625
|
+
window.getComputedStyle( currentBackground ).opacity;
|
2626
|
+
currentBackground.style.backgroundImage = backgroundImageURL;
|
2627
|
+
}
|
2628
|
+
|
2629
|
+
// Don't transition between identical backgrounds. This
|
2630
|
+
// prevents unwanted flicker.
|
1991
2631
|
var previousBackgroundHash = previousBackground ? previousBackground.getAttribute( 'data-background-hash' ) : null;
|
1992
2632
|
var currentBackgroundHash = currentBackground.getAttribute( 'data-background-hash' );
|
1993
2633
|
if( currentBackgroundHash && currentBackgroundHash === previousBackgroundHash && currentBackground !== previousBackground ) {
|
@@ -1995,6 +2635,20 @@ var Reveal = (function(){
|
|
1995
2635
|
}
|
1996
2636
|
|
1997
2637
|
previousBackground = currentBackground;
|
2638
|
+
|
2639
|
+
}
|
2640
|
+
|
2641
|
+
// If there's a background brightness flag for this slide,
|
2642
|
+
// bubble it to the .reveal container
|
2643
|
+
if( currentSlide ) {
|
2644
|
+
[ 'has-light-background', 'has-dark-background' ].forEach( function( classToBubble ) {
|
2645
|
+
if( currentSlide.classList.contains( classToBubble ) ) {
|
2646
|
+
dom.wrapper.classList.add( classToBubble );
|
2647
|
+
}
|
2648
|
+
else {
|
2649
|
+
dom.wrapper.classList.remove( classToBubble );
|
2650
|
+
}
|
2651
|
+
} );
|
1998
2652
|
}
|
1999
2653
|
|
2000
2654
|
// Allow the first background to apply without transition
|
@@ -2012,8 +2666,8 @@ var Reveal = (function(){
|
|
2012
2666
|
|
2013
2667
|
if( config.parallaxBackgroundImage ) {
|
2014
2668
|
|
2015
|
-
var horizontalSlides =
|
2016
|
-
verticalSlides =
|
2669
|
+
var horizontalSlides = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ),
|
2670
|
+
verticalSlides = dom.wrapper.querySelectorAll( VERTICAL_SLIDES_SELECTOR );
|
2017
2671
|
|
2018
2672
|
var backgroundSize = dom.background.style.backgroundSize.split( ' ' ),
|
2019
2673
|
backgroundWidth, backgroundHeight;
|
@@ -2026,16 +2680,138 @@ var Reveal = (function(){
|
|
2026
2680
|
backgroundHeight = parseInt( backgroundSize[1], 10 );
|
2027
2681
|
}
|
2028
2682
|
|
2029
|
-
var slideWidth = dom.background.offsetWidth
|
2030
|
-
|
2031
|
-
|
2683
|
+
var slideWidth = dom.background.offsetWidth,
|
2684
|
+
horizontalSlideCount = horizontalSlides.length,
|
2685
|
+
horizontalOffsetMultiplier,
|
2686
|
+
horizontalOffset;
|
2687
|
+
|
2688
|
+
if( typeof config.parallaxBackgroundHorizontal === 'number' ) {
|
2689
|
+
horizontalOffsetMultiplier = config.parallaxBackgroundHorizontal;
|
2690
|
+
}
|
2691
|
+
else {
|
2692
|
+
horizontalOffsetMultiplier = ( backgroundWidth - slideWidth ) / ( horizontalSlideCount-1 );
|
2693
|
+
}
|
2694
|
+
|
2695
|
+
horizontalOffset = horizontalOffsetMultiplier * indexh * -1;
|
2696
|
+
|
2697
|
+
var slideHeight = dom.background.offsetHeight,
|
2698
|
+
verticalSlideCount = verticalSlides.length,
|
2699
|
+
verticalOffsetMultiplier,
|
2700
|
+
verticalOffset;
|
2701
|
+
|
2702
|
+
if( typeof config.parallaxBackgroundVertical === 'number' ) {
|
2703
|
+
verticalOffsetMultiplier = config.parallaxBackgroundVertical;
|
2704
|
+
}
|
2705
|
+
else {
|
2706
|
+
verticalOffsetMultiplier = ( backgroundHeight - slideHeight ) / ( verticalSlideCount-1 );
|
2707
|
+
}
|
2708
|
+
|
2709
|
+
verticalOffset = verticalSlideCount > 0 ? verticalOffsetMultiplier * indexv * 1 : 0;
|
2710
|
+
|
2711
|
+
dom.background.style.backgroundPosition = horizontalOffset + 'px ' + -verticalOffset + 'px';
|
2712
|
+
|
2713
|
+
}
|
2714
|
+
|
2715
|
+
}
|
2716
|
+
|
2717
|
+
/**
|
2718
|
+
* Called when the given slide is within the configured view
|
2719
|
+
* distance. Shows the slide element and loads any content
|
2720
|
+
* that is set to load lazily (data-src).
|
2721
|
+
*/
|
2722
|
+
function showSlide( slide ) {
|
2723
|
+
|
2724
|
+
// Show the slide element
|
2725
|
+
slide.style.display = 'block';
|
2726
|
+
|
2727
|
+
// Media elements with data-src attributes
|
2728
|
+
toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src]' ) ).forEach( function( element ) {
|
2729
|
+
element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
|
2730
|
+
element.removeAttribute( 'data-src' );
|
2731
|
+
} );
|
2732
|
+
|
2733
|
+
// Media elements with <source> children
|
2734
|
+
toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( function( media ) {
|
2735
|
+
var sources = 0;
|
2736
|
+
|
2737
|
+
toArray( media.querySelectorAll( 'source[data-src]' ) ).forEach( function( source ) {
|
2738
|
+
source.setAttribute( 'src', source.getAttribute( 'data-src' ) );
|
2739
|
+
source.removeAttribute( 'data-src' );
|
2740
|
+
sources += 1;
|
2741
|
+
} );
|
2742
|
+
|
2743
|
+
// If we rewrote sources for this video/audio element, we need
|
2744
|
+
// to manually tell it to load from its new origin
|
2745
|
+
if( sources > 0 ) {
|
2746
|
+
media.load();
|
2747
|
+
}
|
2748
|
+
} );
|
2749
|
+
|
2750
|
+
|
2751
|
+
// Show the corresponding background element
|
2752
|
+
var indices = getIndices( slide );
|
2753
|
+
var background = getSlideBackground( indices.h, indices.v );
|
2754
|
+
if( background ) {
|
2755
|
+
background.style.display = 'block';
|
2756
|
+
|
2757
|
+
// If the background contains media, load it
|
2758
|
+
if( background.hasAttribute( 'data-loaded' ) === false ) {
|
2759
|
+
background.setAttribute( 'data-loaded', 'true' );
|
2760
|
+
|
2761
|
+
var backgroundImage = slide.getAttribute( 'data-background-image' ),
|
2762
|
+
backgroundVideo = slide.getAttribute( 'data-background-video' ),
|
2763
|
+
backgroundVideoLoop = slide.hasAttribute( 'data-background-video-loop' ),
|
2764
|
+
backgroundIframe = slide.getAttribute( 'data-background-iframe' );
|
2765
|
+
|
2766
|
+
// Images
|
2767
|
+
if( backgroundImage ) {
|
2768
|
+
background.style.backgroundImage = 'url('+ backgroundImage +')';
|
2769
|
+
}
|
2770
|
+
// Videos
|
2771
|
+
else if ( backgroundVideo && !isSpeakerNotes() ) {
|
2772
|
+
var video = document.createElement( 'video' );
|
2773
|
+
|
2774
|
+
if( backgroundVideoLoop ) {
|
2775
|
+
video.setAttribute( 'loop', '' );
|
2776
|
+
}
|
2777
|
+
|
2778
|
+
// Support comma separated lists of video sources
|
2779
|
+
backgroundVideo.split( ',' ).forEach( function( source ) {
|
2780
|
+
video.innerHTML += '<source src="'+ source +'">';
|
2781
|
+
} );
|
2782
|
+
|
2783
|
+
background.appendChild( video );
|
2784
|
+
}
|
2785
|
+
// Iframes
|
2786
|
+
else if( backgroundIframe ) {
|
2787
|
+
var iframe = document.createElement( 'iframe' );
|
2788
|
+
iframe.setAttribute( 'src', backgroundIframe );
|
2789
|
+
iframe.style.width = '100%';
|
2790
|
+
iframe.style.height = '100%';
|
2791
|
+
iframe.style.maxHeight = '100%';
|
2792
|
+
iframe.style.maxWidth = '100%';
|
2793
|
+
|
2794
|
+
background.appendChild( iframe );
|
2795
|
+
}
|
2796
|
+
}
|
2797
|
+
}
|
2798
|
+
|
2799
|
+
}
|
2032
2800
|
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2801
|
+
/**
|
2802
|
+
* Called when the given slide is moved outside of the
|
2803
|
+
* configured view distance.
|
2804
|
+
*/
|
2805
|
+
function hideSlide( slide ) {
|
2036
2806
|
|
2037
|
-
|
2807
|
+
// Hide the slide element
|
2808
|
+
slide.style.display = 'none';
|
2038
2809
|
|
2810
|
+
// Hide the corresponding background element
|
2811
|
+
var indices = getIndices( slide );
|
2812
|
+
var background = getSlideBackground( indices.h, indices.v );
|
2813
|
+
if( background ) {
|
2814
|
+
background.style.display = 'none';
|
2039
2815
|
}
|
2040
2816
|
|
2041
2817
|
}
|
@@ -2047,8 +2823,8 @@ var Reveal = (function(){
|
|
2047
2823
|
*/
|
2048
2824
|
function availableRoutes() {
|
2049
2825
|
|
2050
|
-
var horizontalSlides =
|
2051
|
-
verticalSlides =
|
2826
|
+
var horizontalSlides = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ),
|
2827
|
+
verticalSlides = dom.wrapper.querySelectorAll( VERTICAL_SLIDES_SELECTOR );
|
2052
2828
|
|
2053
2829
|
var routes = {
|
2054
2830
|
left: indexh > 0 || config.loop,
|
@@ -2091,6 +2867,30 @@ var Reveal = (function(){
|
|
2091
2867
|
|
2092
2868
|
}
|
2093
2869
|
|
2870
|
+
/**
|
2871
|
+
* Enforces origin-specific format rules for embedded media.
|
2872
|
+
*/
|
2873
|
+
function formatEmbeddedContent() {
|
2874
|
+
|
2875
|
+
var _appendParamToIframeSource = function( sourceAttribute, sourceURL, param ) {
|
2876
|
+
toArray( dom.slides.querySelectorAll( 'iframe['+ sourceAttribute +'*="'+ sourceURL +'"]' ) ).forEach( function( el ) {
|
2877
|
+
var src = el.getAttribute( sourceAttribute );
|
2878
|
+
if( src && src.indexOf( param ) === -1 ) {
|
2879
|
+
el.setAttribute( sourceAttribute, src + ( !/\?/.test( src ) ? '?' : '&' ) + param );
|
2880
|
+
}
|
2881
|
+
});
|
2882
|
+
};
|
2883
|
+
|
2884
|
+
// YouTube frames must include "?enablejsapi=1"
|
2885
|
+
_appendParamToIframeSource( 'src', 'youtube.com/embed/', 'enablejsapi=1' );
|
2886
|
+
_appendParamToIframeSource( 'data-src', 'youtube.com/embed/', 'enablejsapi=1' );
|
2887
|
+
|
2888
|
+
// Vimeo frames must include "?api=1"
|
2889
|
+
_appendParamToIframeSource( 'src', 'player.vimeo.com/', 'api=1' );
|
2890
|
+
_appendParamToIframeSource( 'data-src', 'player.vimeo.com/', 'api=1' );
|
2891
|
+
|
2892
|
+
}
|
2893
|
+
|
2094
2894
|
/**
|
2095
2895
|
* Start playback of any embedded content inside of
|
2096
2896
|
* the targeted slide.
|
@@ -2098,24 +2898,56 @@ var Reveal = (function(){
|
|
2098
2898
|
function startEmbeddedContent( slide ) {
|
2099
2899
|
|
2100
2900
|
if( slide && !isSpeakerNotes() ) {
|
2901
|
+
// Restart GIFs
|
2902
|
+
toArray( slide.querySelectorAll( 'img[src$=".gif"]' ) ).forEach( function( el ) {
|
2903
|
+
// Setting the same unchanged source like this was confirmed
|
2904
|
+
// to work in Chrome, FF & Safari
|
2905
|
+
el.setAttribute( 'src', el.getAttribute( 'src' ) );
|
2906
|
+
} );
|
2907
|
+
|
2101
2908
|
// HTML5 media elements
|
2102
2909
|
toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
|
2103
|
-
if( el.hasAttribute( 'data-autoplay' ) ) {
|
2910
|
+
if( el.hasAttribute( 'data-autoplay' ) && typeof el.play === 'function' ) {
|
2104
2911
|
el.play();
|
2105
2912
|
}
|
2106
2913
|
} );
|
2107
2914
|
|
2108
|
-
//
|
2109
|
-
toArray( slide.querySelectorAll( 'iframe' ) ).forEach( function( el ) {
|
2110
|
-
|
2111
|
-
});
|
2915
|
+
// Normal iframes
|
2916
|
+
toArray( slide.querySelectorAll( 'iframe[src]' ) ).forEach( function( el ) {
|
2917
|
+
startEmbeddedIframe( { target: el } );
|
2918
|
+
} );
|
2112
2919
|
|
2113
|
-
//
|
2114
|
-
toArray( slide.querySelectorAll( 'iframe[src
|
2115
|
-
if( el.
|
2116
|
-
el.
|
2920
|
+
// Lazy loading iframes
|
2921
|
+
toArray( slide.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) {
|
2922
|
+
if( el.getAttribute( 'src' ) !== el.getAttribute( 'data-src' ) ) {
|
2923
|
+
el.removeEventListener( 'load', startEmbeddedIframe ); // remove first to avoid dupes
|
2924
|
+
el.addEventListener( 'load', startEmbeddedIframe );
|
2925
|
+
el.setAttribute( 'src', el.getAttribute( 'data-src' ) );
|
2117
2926
|
}
|
2118
|
-
});
|
2927
|
+
} );
|
2928
|
+
}
|
2929
|
+
|
2930
|
+
}
|
2931
|
+
|
2932
|
+
/**
|
2933
|
+
* "Starts" the content of an embedded iframe using the
|
2934
|
+
* postmessage API.
|
2935
|
+
*/
|
2936
|
+
function startEmbeddedIframe( event ) {
|
2937
|
+
|
2938
|
+
var iframe = event.target;
|
2939
|
+
|
2940
|
+
// YouTube postMessage API
|
2941
|
+
if( /youtube\.com\/embed\//.test( iframe.getAttribute( 'src' ) ) && iframe.hasAttribute( 'data-autoplay' ) ) {
|
2942
|
+
iframe.contentWindow.postMessage( '{"event":"command","func":"playVideo","args":""}', '*' );
|
2943
|
+
}
|
2944
|
+
// Vimeo postMessage API
|
2945
|
+
else if( /player\.vimeo\.com\//.test( iframe.getAttribute( 'src' ) ) && iframe.hasAttribute( 'data-autoplay' ) ) {
|
2946
|
+
iframe.contentWindow.postMessage( '{"method":"play"}', '*' );
|
2947
|
+
}
|
2948
|
+
// Generic postMessage API
|
2949
|
+
else {
|
2950
|
+
iframe.contentWindow.postMessage( 'slide:start', '*' );
|
2119
2951
|
}
|
2120
2952
|
|
2121
2953
|
}
|
@@ -2126,27 +2958,120 @@ var Reveal = (function(){
|
|
2126
2958
|
*/
|
2127
2959
|
function stopEmbeddedContent( slide ) {
|
2128
2960
|
|
2129
|
-
if( slide ) {
|
2961
|
+
if( slide && slide.parentNode ) {
|
2130
2962
|
// HTML5 media elements
|
2131
2963
|
toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
|
2132
|
-
if( !el.hasAttribute( 'data-ignore' ) ) {
|
2964
|
+
if( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) {
|
2133
2965
|
el.pause();
|
2134
2966
|
}
|
2135
2967
|
} );
|
2136
2968
|
|
2137
|
-
//
|
2969
|
+
// Generic postMessage API for non-lazy loaded iframes
|
2138
2970
|
toArray( slide.querySelectorAll( 'iframe' ) ).forEach( function( el ) {
|
2139
2971
|
el.contentWindow.postMessage( 'slide:stop', '*' );
|
2972
|
+
el.removeEventListener( 'load', startEmbeddedIframe );
|
2140
2973
|
});
|
2141
2974
|
|
2142
|
-
// YouTube
|
2975
|
+
// YouTube postMessage API
|
2143
2976
|
toArray( slide.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) {
|
2144
2977
|
if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) {
|
2145
2978
|
el.contentWindow.postMessage( '{"event":"command","func":"pauseVideo","args":""}', '*' );
|
2146
2979
|
}
|
2147
2980
|
});
|
2981
|
+
|
2982
|
+
// Vimeo postMessage API
|
2983
|
+
toArray( slide.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) {
|
2984
|
+
if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) {
|
2985
|
+
el.contentWindow.postMessage( '{"method":"pause"}', '*' );
|
2986
|
+
}
|
2987
|
+
});
|
2988
|
+
|
2989
|
+
// Lazy loading iframes
|
2990
|
+
toArray( slide.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) {
|
2991
|
+
// Only removing the src doesn't actually unload the frame
|
2992
|
+
// in all browsers (Firefox) so we set it to blank first
|
2993
|
+
el.setAttribute( 'src', 'about:blank' );
|
2994
|
+
el.removeAttribute( 'src' );
|
2995
|
+
} );
|
2996
|
+
}
|
2997
|
+
|
2998
|
+
}
|
2999
|
+
|
3000
|
+
/**
|
3001
|
+
* Returns the number of past slides. This can be used as a global
|
3002
|
+
* flattened index for slides.
|
3003
|
+
*/
|
3004
|
+
function getSlidePastCount() {
|
3005
|
+
|
3006
|
+
var horizontalSlides = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
|
3007
|
+
|
3008
|
+
// The number of past slides
|
3009
|
+
var pastCount = 0;
|
3010
|
+
|
3011
|
+
// Step through all slides and count the past ones
|
3012
|
+
mainLoop: for( var i = 0; i < horizontalSlides.length; i++ ) {
|
3013
|
+
|
3014
|
+
var horizontalSlide = horizontalSlides[i];
|
3015
|
+
var verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) );
|
3016
|
+
|
3017
|
+
for( var j = 0; j < verticalSlides.length; j++ ) {
|
3018
|
+
|
3019
|
+
// Stop as soon as we arrive at the present
|
3020
|
+
if( verticalSlides[j].classList.contains( 'present' ) ) {
|
3021
|
+
break mainLoop;
|
3022
|
+
}
|
3023
|
+
|
3024
|
+
pastCount++;
|
3025
|
+
|
3026
|
+
}
|
3027
|
+
|
3028
|
+
// Stop as soon as we arrive at the present
|
3029
|
+
if( horizontalSlide.classList.contains( 'present' ) ) {
|
3030
|
+
break;
|
3031
|
+
}
|
3032
|
+
|
3033
|
+
// Don't count the wrapping section for vertical slides
|
3034
|
+
if( horizontalSlide.classList.contains( 'stack' ) === false ) {
|
3035
|
+
pastCount++;
|
3036
|
+
}
|
3037
|
+
|
3038
|
+
}
|
3039
|
+
|
3040
|
+
return pastCount;
|
3041
|
+
|
3042
|
+
}
|
3043
|
+
|
3044
|
+
/**
|
3045
|
+
* Returns a value ranging from 0-1 that represents
|
3046
|
+
* how far into the presentation we have navigated.
|
3047
|
+
*/
|
3048
|
+
function getProgress() {
|
3049
|
+
|
3050
|
+
// The number of past and total slides
|
3051
|
+
var totalCount = getTotalSlides();
|
3052
|
+
var pastCount = getSlidePastCount();
|
3053
|
+
|
3054
|
+
if( currentSlide ) {
|
3055
|
+
|
3056
|
+
var allFragments = currentSlide.querySelectorAll( '.fragment' );
|
3057
|
+
|
3058
|
+
// If there are fragments in the current slide those should be
|
3059
|
+
// accounted for in the progress.
|
3060
|
+
if( allFragments.length > 0 ) {
|
3061
|
+
var visibleFragments = currentSlide.querySelectorAll( '.fragment.visible' );
|
3062
|
+
|
3063
|
+
// This value represents how big a portion of the slide progress
|
3064
|
+
// that is made up by its fragments (0-1)
|
3065
|
+
var fragmentWeight = 0.9;
|
3066
|
+
|
3067
|
+
// Add fragment progress to the past slide count
|
3068
|
+
pastCount += ( visibleFragments.length / allFragments.length ) * fragmentWeight;
|
3069
|
+
}
|
3070
|
+
|
2148
3071
|
}
|
2149
3072
|
|
3073
|
+
return pastCount / ( totalCount - 1 );
|
3074
|
+
|
2150
3075
|
}
|
2151
3076
|
|
2152
3077
|
/**
|
@@ -2173,8 +3098,13 @@ var Reveal = (function(){
|
|
2173
3098
|
// If the first bit is invalid and there is a name we can
|
2174
3099
|
// assume that this is a named link
|
2175
3100
|
if( isNaN( parseInt( bits[0], 10 ) ) && name.length ) {
|
2176
|
-
|
2177
|
-
|
3101
|
+
var element;
|
3102
|
+
|
3103
|
+
// Ensure the named link is a valid HTML ID attribute
|
3104
|
+
if( /^[a-zA-Z][\w:.-]*$/.test( name ) ) {
|
3105
|
+
// Find the slide with the specified ID
|
3106
|
+
element = document.getElementById( name );
|
3107
|
+
}
|
2178
3108
|
|
2179
3109
|
if( element ) {
|
2180
3110
|
// Find the position of the named slide and navigate to it
|
@@ -2216,12 +3146,19 @@ var Reveal = (function(){
|
|
2216
3146
|
if( typeof delay === 'number' ) {
|
2217
3147
|
writeURLTimeout = setTimeout( writeURL, delay );
|
2218
3148
|
}
|
2219
|
-
else {
|
3149
|
+
else if( currentSlide ) {
|
2220
3150
|
var url = '/';
|
2221
3151
|
|
3152
|
+
// Attempt to create a named link based on the slide's ID
|
3153
|
+
var id = currentSlide.getAttribute( 'id' );
|
3154
|
+
if( id ) {
|
3155
|
+
id = id.toLowerCase();
|
3156
|
+
id = id.replace( /[^a-zA-Z0-9\-\_\:\.]/g, '' );
|
3157
|
+
}
|
3158
|
+
|
2222
3159
|
// If the current slide has an ID, use that as a named link
|
2223
|
-
if(
|
2224
|
-
url = '/' +
|
3160
|
+
if( typeof id === 'string' && id.length ) {
|
3161
|
+
url = '/' + id;
|
2225
3162
|
}
|
2226
3163
|
// Otherwise use the /h/v index
|
2227
3164
|
else {
|
@@ -2258,11 +3195,14 @@ var Reveal = (function(){
|
|
2258
3195
|
var slideh = isVertical ? slide.parentNode : slide;
|
2259
3196
|
|
2260
3197
|
// Select all horizontal slides
|
2261
|
-
var horizontalSlides = toArray(
|
3198
|
+
var horizontalSlides = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
|
2262
3199
|
|
2263
3200
|
// Now that we know which the horizontal slide is, get its index
|
2264
3201
|
h = Math.max( horizontalSlides.indexOf( slideh ), 0 );
|
2265
3202
|
|
3203
|
+
// Assume we're not vertical
|
3204
|
+
v = undefined;
|
3205
|
+
|
2266
3206
|
// If this is a vertical slide, grab the vertical index
|
2267
3207
|
if( isVertical ) {
|
2268
3208
|
v = Math.max( toArray( slide.parentNode.querySelectorAll( 'section' ) ).indexOf( slide ), 0 );
|
@@ -2272,8 +3212,13 @@ var Reveal = (function(){
|
|
2272
3212
|
if( !slide && currentSlide ) {
|
2273
3213
|
var hasFragments = currentSlide.querySelectorAll( '.fragment' ).length > 0;
|
2274
3214
|
if( hasFragments ) {
|
2275
|
-
var
|
2276
|
-
|
3215
|
+
var currentFragment = currentSlide.querySelector( '.current-fragment' );
|
3216
|
+
if( currentFragment && currentFragment.hasAttribute( 'data-fragment-index' ) ) {
|
3217
|
+
f = parseInt( currentFragment.getAttribute( 'data-fragment-index' ), 10 );
|
3218
|
+
}
|
3219
|
+
else {
|
3220
|
+
f = currentSlide.querySelectorAll( '.fragment.visible' ).length - 1;
|
3221
|
+
}
|
2277
3222
|
}
|
2278
3223
|
}
|
2279
3224
|
|
@@ -2281,6 +3226,107 @@ var Reveal = (function(){
|
|
2281
3226
|
|
2282
3227
|
}
|
2283
3228
|
|
3229
|
+
/**
|
3230
|
+
* Retrieves the total number of slides in this presentation.
|
3231
|
+
*/
|
3232
|
+
function getTotalSlides() {
|
3233
|
+
|
3234
|
+
return dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ':not(.stack)' ).length;
|
3235
|
+
|
3236
|
+
}
|
3237
|
+
|
3238
|
+
/**
|
3239
|
+
* Returns the slide element matching the specified index.
|
3240
|
+
*/
|
3241
|
+
function getSlide( x, y ) {
|
3242
|
+
|
3243
|
+
var horizontalSlide = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR )[ x ];
|
3244
|
+
var verticalSlides = horizontalSlide && horizontalSlide.querySelectorAll( 'section' );
|
3245
|
+
|
3246
|
+
if( verticalSlides && verticalSlides.length && typeof y === 'number' ) {
|
3247
|
+
return verticalSlides ? verticalSlides[ y ] : undefined;
|
3248
|
+
}
|
3249
|
+
|
3250
|
+
return horizontalSlide;
|
3251
|
+
|
3252
|
+
}
|
3253
|
+
|
3254
|
+
/**
|
3255
|
+
* Returns the background element for the given slide.
|
3256
|
+
* All slides, even the ones with no background properties
|
3257
|
+
* defined, have a background element so as long as the
|
3258
|
+
* index is valid an element will be returned.
|
3259
|
+
*/
|
3260
|
+
function getSlideBackground( x, y ) {
|
3261
|
+
|
3262
|
+
// When printing to PDF the slide backgrounds are nested
|
3263
|
+
// inside of the slides
|
3264
|
+
if( isPrintingPDF() ) {
|
3265
|
+
var slide = getSlide( x, y );
|
3266
|
+
if( slide ) {
|
3267
|
+
var background = slide.querySelector( '.slide-background' );
|
3268
|
+
if( background && background.parentNode === slide ) {
|
3269
|
+
return background;
|
3270
|
+
}
|
3271
|
+
}
|
3272
|
+
|
3273
|
+
return undefined;
|
3274
|
+
}
|
3275
|
+
|
3276
|
+
var horizontalBackground = dom.wrapper.querySelectorAll( '.backgrounds>.slide-background' )[ x ];
|
3277
|
+
var verticalBackgrounds = horizontalBackground && horizontalBackground.querySelectorAll( '.slide-background' );
|
3278
|
+
|
3279
|
+
if( verticalBackgrounds && verticalBackgrounds.length && typeof y === 'number' ) {
|
3280
|
+
return verticalBackgrounds ? verticalBackgrounds[ y ] : undefined;
|
3281
|
+
}
|
3282
|
+
|
3283
|
+
return horizontalBackground;
|
3284
|
+
|
3285
|
+
}
|
3286
|
+
|
3287
|
+
/**
|
3288
|
+
* Retrieves the current state of the presentation as
|
3289
|
+
* an object. This state can then be restored at any
|
3290
|
+
* time.
|
3291
|
+
*/
|
3292
|
+
function getState() {
|
3293
|
+
|
3294
|
+
var indices = getIndices();
|
3295
|
+
|
3296
|
+
return {
|
3297
|
+
indexh: indices.h,
|
3298
|
+
indexv: indices.v,
|
3299
|
+
indexf: indices.f,
|
3300
|
+
paused: isPaused(),
|
3301
|
+
overview: isOverview()
|
3302
|
+
};
|
3303
|
+
|
3304
|
+
}
|
3305
|
+
|
3306
|
+
/**
|
3307
|
+
* Restores the presentation to the given state.
|
3308
|
+
*
|
3309
|
+
* @param {Object} state As generated by getState()
|
3310
|
+
*/
|
3311
|
+
function setState( state ) {
|
3312
|
+
|
3313
|
+
if( typeof state === 'object' ) {
|
3314
|
+
slide( deserialize( state.indexh ), deserialize( state.indexv ), deserialize( state.indexf ) );
|
3315
|
+
|
3316
|
+
var pausedFlag = deserialize( state.paused ),
|
3317
|
+
overviewFlag = deserialize( state.overview );
|
3318
|
+
|
3319
|
+
if( typeof pausedFlag === 'boolean' && pausedFlag !== isPaused() ) {
|
3320
|
+
togglePause( pausedFlag );
|
3321
|
+
}
|
3322
|
+
|
3323
|
+
if( typeof overviewFlag === 'boolean' && overviewFlag !== isOverview() ) {
|
3324
|
+
toggleOverview( overviewFlag );
|
3325
|
+
}
|
3326
|
+
}
|
3327
|
+
|
3328
|
+
}
|
3329
|
+
|
2284
3330
|
/**
|
2285
3331
|
* Return a sorted fragments list, ordered by an increasing
|
2286
3332
|
* "data-fragment-index" attribute.
|
@@ -2392,6 +3438,9 @@ var Reveal = (function(){
|
|
2392
3438
|
element.classList.add( 'visible' );
|
2393
3439
|
element.classList.remove( 'current-fragment' );
|
2394
3440
|
|
3441
|
+
// Announce the fragments one by one to the Screen Reader
|
3442
|
+
dom.statusDiv.textContent = element.textContent;
|
3443
|
+
|
2395
3444
|
if( i === index ) {
|
2396
3445
|
element.classList.add( 'current-fragment' );
|
2397
3446
|
}
|
@@ -2415,6 +3464,7 @@ var Reveal = (function(){
|
|
2415
3464
|
}
|
2416
3465
|
|
2417
3466
|
updateControls();
|
3467
|
+
updateProgress();
|
2418
3468
|
|
2419
3469
|
return !!( fragmentsShown.length || fragmentsHidden.length );
|
2420
3470
|
|
@@ -2459,14 +3509,21 @@ var Reveal = (function(){
|
|
2459
3509
|
|
2460
3510
|
if( currentSlide ) {
|
2461
3511
|
|
3512
|
+
var currentFragment = currentSlide.querySelector( '.current-fragment' );
|
3513
|
+
|
3514
|
+
var fragmentAutoSlide = currentFragment ? currentFragment.getAttribute( 'data-autoslide' ) : null;
|
2462
3515
|
var parentAutoSlide = currentSlide.parentNode ? currentSlide.parentNode.getAttribute( 'data-autoslide' ) : null;
|
2463
3516
|
var slideAutoSlide = currentSlide.getAttribute( 'data-autoslide' );
|
2464
3517
|
|
2465
3518
|
// Pick value in the following priority order:
|
2466
|
-
// 1. Current
|
2467
|
-
// 2.
|
2468
|
-
// 3.
|
2469
|
-
|
3519
|
+
// 1. Current fragment's data-autoslide
|
3520
|
+
// 2. Current slide's data-autoslide
|
3521
|
+
// 3. Parent slide's data-autoslide
|
3522
|
+
// 4. Global autoSlide setting
|
3523
|
+
if( fragmentAutoSlide ) {
|
3524
|
+
autoSlide = parseInt( fragmentAutoSlide, 10 );
|
3525
|
+
}
|
3526
|
+
else if( slideAutoSlide ) {
|
2470
3527
|
autoSlide = parseInt( slideAutoSlide, 10 );
|
2471
3528
|
}
|
2472
3529
|
else if( parentAutoSlide ) {
|
@@ -2478,14 +3535,17 @@ var Reveal = (function(){
|
|
2478
3535
|
|
2479
3536
|
// If there are media elements with data-autoplay,
|
2480
3537
|
// automatically set the autoSlide duration to the
|
2481
|
-
// length of that media
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2485
|
-
|
3538
|
+
// length of that media. Not applicable if the slide
|
3539
|
+
// is divided up into fragments.
|
3540
|
+
if( currentSlide.querySelectorAll( '.fragment' ).length === 0 ) {
|
3541
|
+
toArray( currentSlide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
|
3542
|
+
if( el.hasAttribute( 'data-autoplay' ) ) {
|
3543
|
+
if( autoSlide && el.duration * 1000 > autoSlide ) {
|
3544
|
+
autoSlide = ( el.duration * 1000 ) + 1000;
|
3545
|
+
}
|
2486
3546
|
}
|
2487
|
-
}
|
2488
|
-
}
|
3547
|
+
} );
|
3548
|
+
}
|
2489
3549
|
|
2490
3550
|
// Cue the next auto-slide if:
|
2491
3551
|
// - There is an autoSlide value
|
@@ -2493,7 +3553,7 @@ var Reveal = (function(){
|
|
2493
3553
|
// - The presentation isn't paused
|
2494
3554
|
// - The overview isn't active
|
2495
3555
|
// - The presentation isn't over
|
2496
|
-
if( autoSlide && !autoSlidePaused && !isPaused() && !isOverview() && ( !Reveal.isLastSlide() || config.loop === true ) ) {
|
3556
|
+
if( autoSlide && !autoSlidePaused && !isPaused() && !isOverview() && ( !Reveal.isLastSlide() || availableFragments().next || config.loop === true ) ) {
|
2497
3557
|
autoSlideTimeout = setTimeout( navigateNext, autoSlide );
|
2498
3558
|
autoSlideStartTime = Date.now();
|
2499
3559
|
}
|
@@ -2518,19 +3578,25 @@ var Reveal = (function(){
|
|
2518
3578
|
|
2519
3579
|
function pauseAutoSlide() {
|
2520
3580
|
|
2521
|
-
autoSlidePaused
|
2522
|
-
|
3581
|
+
if( autoSlide && !autoSlidePaused ) {
|
3582
|
+
autoSlidePaused = true;
|
3583
|
+
dispatchEvent( 'autoslidepaused' );
|
3584
|
+
clearTimeout( autoSlideTimeout );
|
2523
3585
|
|
2524
|
-
|
2525
|
-
|
3586
|
+
if( autoSlidePlayer ) {
|
3587
|
+
autoSlidePlayer.setPlaying( false );
|
3588
|
+
}
|
2526
3589
|
}
|
2527
3590
|
|
2528
3591
|
}
|
2529
3592
|
|
2530
3593
|
function resumeAutoSlide() {
|
2531
3594
|
|
2532
|
-
autoSlidePaused
|
2533
|
-
|
3595
|
+
if( autoSlide && autoSlidePaused ) {
|
3596
|
+
autoSlidePaused = false;
|
3597
|
+
dispatchEvent( 'autoslideresumed' );
|
3598
|
+
cueAutoSlide();
|
3599
|
+
}
|
2534
3600
|
|
2535
3601
|
}
|
2536
3602
|
|
@@ -2597,7 +3663,14 @@ var Reveal = (function(){
|
|
2597
3663
|
}
|
2598
3664
|
else {
|
2599
3665
|
// Fetch the previous horizontal slide, if there is one
|
2600
|
-
var previousSlide
|
3666
|
+
var previousSlide;
|
3667
|
+
|
3668
|
+
if( config.rtl ) {
|
3669
|
+
previousSlide = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.future' ) ).pop();
|
3670
|
+
}
|
3671
|
+
else {
|
3672
|
+
previousSlide = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.past' ) ).pop();
|
3673
|
+
}
|
2601
3674
|
|
2602
3675
|
if( previousSlide ) {
|
2603
3676
|
var v = ( previousSlide.querySelectorAll( 'section' ).length - 1 ) || undefined;
|
@@ -2610,13 +3683,21 @@ var Reveal = (function(){
|
|
2610
3683
|
}
|
2611
3684
|
|
2612
3685
|
/**
|
2613
|
-
*
|
3686
|
+
* The reverse of #navigatePrev().
|
2614
3687
|
*/
|
2615
3688
|
function navigateNext() {
|
2616
3689
|
|
2617
3690
|
// Prioritize revealing fragments
|
2618
3691
|
if( nextFragment() === false ) {
|
2619
|
-
availableRoutes().down
|
3692
|
+
if( availableRoutes().down ) {
|
3693
|
+
navigateDown();
|
3694
|
+
}
|
3695
|
+
else if( config.rtl ) {
|
3696
|
+
navigateLeft();
|
3697
|
+
}
|
3698
|
+
else {
|
3699
|
+
navigateRight();
|
3700
|
+
}
|
2620
3701
|
}
|
2621
3702
|
|
2622
3703
|
// If auto-sliding is enabled we need to cue up
|
@@ -2642,21 +3723,47 @@ var Reveal = (function(){
|
|
2642
3723
|
|
2643
3724
|
}
|
2644
3725
|
|
3726
|
+
/**
|
3727
|
+
* Handler for the document level 'keypress' event.
|
3728
|
+
*/
|
3729
|
+
function onDocumentKeyPress( event ) {
|
3730
|
+
|
3731
|
+
// Check if the pressed key is question mark
|
3732
|
+
if( event.shiftKey && event.charCode === 63 ) {
|
3733
|
+
if( dom.overlay ) {
|
3734
|
+
closeOverlay();
|
3735
|
+
}
|
3736
|
+
else {
|
3737
|
+
showHelp( true );
|
3738
|
+
}
|
3739
|
+
}
|
3740
|
+
|
3741
|
+
}
|
3742
|
+
|
2645
3743
|
/**
|
2646
3744
|
* Handler for the document level 'keydown' event.
|
2647
3745
|
*/
|
2648
3746
|
function onDocumentKeyDown( event ) {
|
2649
3747
|
|
3748
|
+
// If there's a condition specified and it returns false,
|
3749
|
+
// ignore this event
|
3750
|
+
if( typeof config.keyboardCondition === 'function' && config.keyboardCondition() === false ) {
|
3751
|
+
return true;
|
3752
|
+
}
|
3753
|
+
|
3754
|
+
// Remember if auto-sliding was paused so we can toggle it
|
3755
|
+
var autoSlideWasPaused = autoSlidePaused;
|
3756
|
+
|
2650
3757
|
onUserInput( event );
|
2651
3758
|
|
2652
3759
|
// Check if there's a focused element that could be using
|
2653
3760
|
// the keyboard
|
2654
|
-
var
|
2655
|
-
var
|
3761
|
+
var activeElementIsCE = document.activeElement && document.activeElement.contentEditable !== 'inherit';
|
3762
|
+
var activeElementIsInput = document.activeElement && document.activeElement.tagName && /input|textarea/i.test( document.activeElement.tagName );
|
2656
3763
|
|
2657
3764
|
// Disregard the event if there's a focused element or a
|
2658
3765
|
// keyboard modifier key is present
|
2659
|
-
if(
|
3766
|
+
if( activeElementIsCE || activeElementIsInput || (event.shiftKey && event.keyCode !== 32) || event.altKey || event.ctrlKey || event.metaKey ) return;
|
2660
3767
|
|
2661
3768
|
// While paused only allow "unpausing" keyboard events (b and .)
|
2662
3769
|
if( isPaused() && [66,190,191].indexOf( event.keyCode ) === -1 ) {
|
@@ -2719,10 +3826,12 @@ var Reveal = (function(){
|
|
2719
3826
|
case 32: isOverview() ? deactivateOverview() : event.shiftKey ? navigatePrev() : navigateNext(); break;
|
2720
3827
|
// return
|
2721
3828
|
case 13: isOverview() ? deactivateOverview() : triggered = false; break;
|
2722
|
-
// b, period, Logitech presenter tools "black screen" button
|
2723
|
-
case 66: case 190: case 191: togglePause(); break;
|
3829
|
+
// two-spot, semicolon, b, period, Logitech presenter tools "black screen" button
|
3830
|
+
case 58: case 59: case 66: case 190: case 191: togglePause(); break;
|
2724
3831
|
// f
|
2725
3832
|
case 70: enterFullscreen(); break;
|
3833
|
+
// a
|
3834
|
+
case 65: if ( config.autoSlideStoppable ) toggleAutoSlide( autoSlideWasPaused ); break;
|
2726
3835
|
default:
|
2727
3836
|
triggered = false;
|
2728
3837
|
}
|
@@ -2732,18 +3841,18 @@ var Reveal = (function(){
|
|
2732
3841
|
// If the input resulted in a triggered action we should prevent
|
2733
3842
|
// the browsers default behavior
|
2734
3843
|
if( triggered ) {
|
2735
|
-
event.preventDefault();
|
3844
|
+
event.preventDefault && event.preventDefault();
|
2736
3845
|
}
|
2737
3846
|
// ESC or O key
|
2738
3847
|
else if ( ( event.keyCode === 27 || event.keyCode === 79 ) && features.transforms3d ) {
|
2739
|
-
if( dom.
|
2740
|
-
|
3848
|
+
if( dom.overlay ) {
|
3849
|
+
closeOverlay();
|
2741
3850
|
}
|
2742
3851
|
else {
|
2743
3852
|
toggleOverview();
|
2744
3853
|
}
|
2745
3854
|
|
2746
|
-
event.preventDefault();
|
3855
|
+
event.preventDefault && event.preventDefault();
|
2747
3856
|
}
|
2748
3857
|
|
2749
3858
|
// If auto-sliding is enabled we need to cue up
|
@@ -2877,7 +3986,7 @@ var Reveal = (function(){
|
|
2877
3986
|
*/
|
2878
3987
|
function onPointerDown( event ) {
|
2879
3988
|
|
2880
|
-
if( event.pointerType === event.MSPOINTER_TYPE_TOUCH ) {
|
3989
|
+
if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" ) {
|
2881
3990
|
event.touches = [{ clientX: event.clientX, clientY: event.clientY }];
|
2882
3991
|
onTouchStart( event );
|
2883
3992
|
}
|
@@ -2889,7 +3998,7 @@ var Reveal = (function(){
|
|
2889
3998
|
*/
|
2890
3999
|
function onPointerMove( event ) {
|
2891
4000
|
|
2892
|
-
if( event.pointerType === event.MSPOINTER_TYPE_TOUCH )
|
4001
|
+
if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" ) {
|
2893
4002
|
event.touches = [{ clientX: event.clientX, clientY: event.clientY }];
|
2894
4003
|
onTouchMove( event );
|
2895
4004
|
}
|
@@ -2901,7 +4010,7 @@ var Reveal = (function(){
|
|
2901
4010
|
*/
|
2902
4011
|
function onPointerUp( event ) {
|
2903
4012
|
|
2904
|
-
if( event.pointerType === event.MSPOINTER_TYPE_TOUCH )
|
4013
|
+
if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" ) {
|
2905
4014
|
event.touches = [{ clientX: event.clientX, clientY: event.clientY }];
|
2906
4015
|
onTouchEnd( event );
|
2907
4016
|
}
|
@@ -2942,9 +4051,13 @@ var Reveal = (function(){
|
|
2942
4051
|
|
2943
4052
|
event.preventDefault();
|
2944
4053
|
|
2945
|
-
var slidesTotal = toArray(
|
4054
|
+
var slidesTotal = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).length;
|
2946
4055
|
var slideIndex = Math.floor( ( event.clientX / dom.wrapper.offsetWidth ) * slidesTotal );
|
2947
4056
|
|
4057
|
+
if( config.rtl ) {
|
4058
|
+
slideIndex = slidesTotal - slideIndex;
|
4059
|
+
}
|
4060
|
+
|
2948
4061
|
slide( slideIndex );
|
2949
4062
|
|
2950
4063
|
}
|
@@ -2983,13 +4096,16 @@ var Reveal = (function(){
|
|
2983
4096
|
function onPageVisibilityChange( event ) {
|
2984
4097
|
|
2985
4098
|
var isHidden = document.webkitHidden ||
|
2986
|
-
|
2987
|
-
|
4099
|
+
document.msHidden ||
|
4100
|
+
document.hidden;
|
2988
4101
|
|
2989
4102
|
// If, after clicking a link or similar and we're coming back,
|
2990
4103
|
// focus the document.body to ensure we can use keyboard shortcuts
|
2991
4104
|
if( isHidden === false && document.activeElement !== document.body ) {
|
2992
|
-
|
4105
|
+
// Not all elements support .blur() - SVGs among them.
|
4106
|
+
if( typeof document.activeElement.blur === 'function' ) {
|
4107
|
+
document.activeElement.blur();
|
4108
|
+
}
|
2993
4109
|
document.body.focus();
|
2994
4110
|
}
|
2995
4111
|
|
@@ -3033,10 +4149,12 @@ var Reveal = (function(){
|
|
3033
4149
|
*/
|
3034
4150
|
function onPreviewLinkClicked( event ) {
|
3035
4151
|
|
3036
|
-
|
3037
|
-
|
3038
|
-
|
3039
|
-
|
4152
|
+
if( event.currentTarget && event.currentTarget.hasAttribute( 'href' ) ) {
|
4153
|
+
var url = event.currentTarget.getAttribute( 'href' );
|
4154
|
+
if( url ) {
|
4155
|
+
showPreview( url );
|
4156
|
+
event.preventDefault();
|
4157
|
+
}
|
3040
4158
|
}
|
3041
4159
|
|
3042
4160
|
}
|
@@ -3232,7 +4350,7 @@ var Reveal = (function(){
|
|
3232
4350
|
// --------------------------------------------------------------------//
|
3233
4351
|
|
3234
4352
|
|
3235
|
-
|
4353
|
+
Reveal = {
|
3236
4354
|
initialize: initialize,
|
3237
4355
|
configure: configure,
|
3238
4356
|
sync: sync,
|
@@ -3275,28 +4393,35 @@ var Reveal = (function(){
|
|
3275
4393
|
// Toggles the "black screen" mode on/off
|
3276
4394
|
togglePause: togglePause,
|
3277
4395
|
|
4396
|
+
// Toggles the auto slide mode on/off
|
4397
|
+
toggleAutoSlide: toggleAutoSlide,
|
4398
|
+
|
3278
4399
|
// State checks
|
3279
4400
|
isOverview: isOverview,
|
3280
4401
|
isPaused: isPaused,
|
4402
|
+
isAutoSliding: isAutoSliding,
|
3281
4403
|
|
3282
4404
|
// Adds or removes all internal event listeners (such as keyboard)
|
3283
4405
|
addEventListeners: addEventListeners,
|
3284
4406
|
removeEventListeners: removeEventListeners,
|
3285
4407
|
|
4408
|
+
// Facility for persisting and restoring the presentation state
|
4409
|
+
getState: getState,
|
4410
|
+
setState: setState,
|
4411
|
+
|
4412
|
+
// Presentation progress on range of 0-1
|
4413
|
+
getProgress: getProgress,
|
4414
|
+
|
3286
4415
|
// Returns the indices of the current, or specified, slide
|
3287
4416
|
getIndices: getIndices,
|
3288
4417
|
|
3289
|
-
|
3290
|
-
getSlide: function( x, y ) {
|
3291
|
-
var horizontalSlide = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR )[ x ];
|
3292
|
-
var verticalSlides = horizontalSlide && horizontalSlide.querySelectorAll( 'section' );
|
4418
|
+
getTotalSlides: getTotalSlides,
|
3293
4419
|
|
3294
|
-
|
3295
|
-
|
3296
|
-
}
|
4420
|
+
// Returns the slide element at the specified index
|
4421
|
+
getSlide: getSlide,
|
3297
4422
|
|
3298
|
-
|
3299
|
-
|
4423
|
+
// Returns the slide background element at the specified index
|
4424
|
+
getSlideBackground: getSlideBackground,
|
3300
4425
|
|
3301
4426
|
// Returns the previous slide element, may be null
|
3302
4427
|
getPreviousSlide: function() {
|
@@ -3330,12 +4455,7 @@ var Reveal = (function(){
|
|
3330
4455
|
for( var i in query ) {
|
3331
4456
|
var value = query[ i ];
|
3332
4457
|
|
3333
|
-
query[ i ] = unescape( value );
|
3334
|
-
|
3335
|
-
if( value === 'null' ) query[ i ] = null;
|
3336
|
-
else if( value === 'true' ) query[ i ] = true;
|
3337
|
-
else if( value === 'false' ) query[ i ] = false;
|
3338
|
-
else if( value.match( /^\d+$/ ) ) query[ i ] = parseFloat( value );
|
4458
|
+
query[ i ] = deserialize( unescape( value ) );
|
3339
4459
|
}
|
3340
4460
|
|
3341
4461
|
return query;
|
@@ -3343,7 +4463,7 @@ var Reveal = (function(){
|
|
3343
4463
|
|
3344
4464
|
// Returns true if we're currently on the first slide
|
3345
4465
|
isFirstSlide: function() {
|
3346
|
-
return
|
4466
|
+
return ( indexh === 0 && indexv === 0 );
|
3347
4467
|
},
|
3348
4468
|
|
3349
4469
|
// Returns true if we're currently on the last slide
|
@@ -3376,7 +4496,14 @@ var Reveal = (function(){
|
|
3376
4496
|
if( 'addEventListener' in window ) {
|
3377
4497
|
( dom.wrapper || document.querySelector( '.reveal' ) ).removeEventListener( type, listener, useCapture );
|
3378
4498
|
}
|
4499
|
+
},
|
4500
|
+
|
4501
|
+
// Programatically triggers a keyboard event
|
4502
|
+
triggerKey: function( keyCode ) {
|
4503
|
+
onDocumentKeyDown( { keyCode: keyCode } );
|
3379
4504
|
}
|
3380
4505
|
};
|
3381
4506
|
|
3382
|
-
|
4507
|
+
return Reveal;
|
4508
|
+
|
4509
|
+
}));
|