diff options
38 files changed, 925 insertions, 383 deletions
@@ -225,7 +225,7 @@ We use [marked](https://github.com/chjj/marked) to parse Markdown. To customise ```javascript Reveal.initialize({ // Options which are passed into marked - // See https://github.com/chjj/marked#options-1 + // See https://marked.js.org/#/USING_ADVANCED.md#options markdown: { smartypants: true } @@ -326,6 +326,12 @@ Reveal.initialize({ // Enable slide navigation via mouse wheel mouseWheel: false, + // Hide cursor if inactive + hideInactiveCursor: true, + + // Time before the cursor is hidden (in ms) + hideCursorTime: 5000, + // Hides the address bar on mobile devices hideAddressBar: true, @@ -423,9 +429,6 @@ Reveal.js doesn't _rely_ on any third party scripts to work but a few optional l ```javascript Reveal.initialize({ dependencies: [ - // Cross-browser shim that fully implements classList - https://github.com/eligrey/classList.js/ - { src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } }, - // Interpret Markdown in <section> elements { src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, { src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, @@ -451,8 +454,6 @@ You can add your own extensions using the same syntax. The following properties - **callback**: [optional] Function to execute when the script has loaded - **condition**: [optional] Function which must return true for the script to be loaded -To load these dependencies, reveal.js requires [head.js](http://headjs.com/) *(a script loading library)* to be loaded before reveal.js. - ### Ready Event A `ready` event is fired when reveal.js has loaded all non-async dependencies and is ready to start navigating. To check if reveal.js is already 'ready' you can call `Reveal.isReady()`. @@ -516,7 +517,7 @@ If there's some part of your content that needs to remain accessible to touch ev When working on presentation with a lot of media or iframe content it's important to load lazily. Lazy loading means that reveal.js will only load content for the few slides nearest to the current slide. The number of slides that are preloaded is determined by the `viewDistance` configuration option. -To enable lazy loading all you need to do is change your `src` attributes to `data-src` as shown below. This is supported for image, video, audio and iframe elements. Lazy loaded iframes will also unload when the containing slide is no longer visible. +To enable lazy loading all you need to do is change your `src` attributes to `data-src` as shown below. This is supported for image, video, audio and iframe elements. ```html <section> @@ -529,6 +530,12 @@ To enable lazy loading all you need to do is change your `src` attributes to `da </section> ``` +#### Lazy Loading Iframes +Note that lazy loaded iframes ignore the `viewDistance` configuration and will only load when their containing slide becomes visible. Iframes are also unloaded as soon as the slide is hidden. + +When we lazy load a video or audio element, reveal.js won't start playing that content until the slide becomes visible. However there is no way to control this for an iframe since that could contain any kind of content. That means if we loaded an iframe before the slide is visible on screen it could begin playing media and sound in the background. + + ### API The `Reveal` object exposes a JavaScript API for controlling navigation and reading state: @@ -585,6 +592,9 @@ Reveal.isLastSlide(); Reveal.isOverview(); Reveal.isPaused(); Reveal.isAutoSliding(); + +// Returns the top-level DOM element +getRevealElement(); // <div class="reveal">...</div> ``` ### Custom Key Bindings @@ -1291,6 +1301,8 @@ Reveal.initialize({ math: { mathjax: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js', config: 'TeX-AMS_HTML-full' // See http://docs.mathjax.org/en/latest/config-files.html + // pass other options into `MathJax.Hub.Config()` + TeX: { Macros: macros } }, dependencies: [ diff --git a/css/reset.css b/css/reset.css new file mode 100644 index 0000000..e238539 --- /dev/null +++ b/css/reset.css @@ -0,0 +1,30 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v4.0 | 20180602 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +main, menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, main, menu, nav, section { + display: block; +}
\ No newline at end of file diff --git a/css/reveal.css b/css/reveal.css index eda311e..4a9c604 100644 --- a/css/reveal.css +++ b/css/reveal.css @@ -6,33 +6,6 @@ * Copyright (C) 2018 Hakim El Hattab, http://hakim.se */ /********************************************* - * RESET STYLES - *********************************************/ -html, body, .reveal div, .reveal span, .reveal applet, .reveal object, .reveal iframe, -.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal p, .reveal blockquote, .reveal pre, -.reveal a, .reveal abbr, .reveal acronym, .reveal address, .reveal big, .reveal cite, .reveal code, -.reveal del, .reveal dfn, .reveal em, .reveal img, .reveal ins, .reveal kbd, .reveal q, .reveal s, .reveal samp, -.reveal small, .reveal strike, .reveal strong, .reveal sub, .reveal sup, .reveal tt, .reveal var, -.reveal b, .reveal u, .reveal center, -.reveal dl, .reveal dt, .reveal dd, .reveal ol, .reveal ul, .reveal li, -.reveal fieldset, .reveal form, .reveal label, .reveal legend, -.reveal table, .reveal caption, .reveal tbody, .reveal tfoot, .reveal thead, .reveal tr, .reveal th, .reveal td, -.reveal article, .reveal aside, .reveal canvas, .reveal details, .reveal embed, -.reveal figure, .reveal figcaption, .reveal footer, .reveal header, .reveal hgroup, -.reveal menu, .reveal nav, .reveal output, .reveal ruby, .reveal section, .reveal summary, -.reveal time, .reveal mark, .reveal audio, .reveal video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; } - -.reveal article, .reveal aside, .reveal details, .reveal figcaption, .reveal figure, -.reveal footer, .reveal header, .reveal hgroup, .reveal menu, .reveal nav, .reveal section { - display: block; } - -/********************************************* * GLOBAL STYLES *********************************************/ html, @@ -44,6 +17,7 @@ body { body { position: relative; line-height: 1; + margin: 0; background-color: #fff; color: #000; } @@ -512,7 +486,8 @@ body { perspective-origin: 50% 40%; } .reveal .slides > section { - -ms-perspective: 600px; } + -webkit-perspective: 600px; + perspective: 600px; } .reveal .slides > section, .reveal .slides > section > section { @@ -989,34 +964,35 @@ body { .no-transforms { overflow-y: auto; } +.no-transforms .reveal { + overflow: visible; } + .no-transforms .reveal .slides { position: relative; width: 80%; - height: auto !important; + max-width: 1280px; + height: auto; top: 0; - left: 50%; - margin: 0; + margin: 0 auto; text-align: center; } .no-transforms .reveal .controls, .no-transforms .reveal .progress { - display: none !important; } + display: none; } .no-transforms .reveal .slides section { - display: block !important; - opacity: 1 !important; - position: relative !important; + display: block; + opacity: 1; + position: relative; height: auto; min-height: 0; top: 0; - left: -50%; + left: 0; + margin: 10vh 0; margin: 70px 0; -webkit-transform: none; transform: none; } -.no-transforms .reveal .slides section section { - left: 0; } - .reveal .no-transition, .reveal .no-transition * { transition: none !important; } @@ -1294,9 +1270,9 @@ body { transition-duration: 1200ms; } /********************************************* - * LINK PREVIEW OVERLAY + * OVERLAY FOR LINK PREVIEWS AND HELP *********************************************/ -.reveal .overlay { +.reveal > .overlay { position: absolute; top: 0; left: 0; @@ -1308,11 +1284,11 @@ body { visibility: hidden; transition: all 0.3s ease; } -.reveal .overlay.visible { +.reveal > .overlay.visible { opacity: 1; visibility: visible; } -.reveal .overlay .spinner { +.reveal > .overlay .spinner { position: absolute; display: block; top: 50%; @@ -1326,7 +1302,7 @@ body { opacity: 0.6; transition: all 0.3s ease; } -.reveal .overlay header { +.reveal > .overlay header { position: absolute; left: 0; top: 0; @@ -1335,7 +1311,7 @@ body { z-index: 2; border-bottom: 1px solid #222; } -.reveal .overlay header a { +.reveal > .overlay header a { display: inline-block; width: 40px; height: 40px; @@ -1345,10 +1321,10 @@ body { opacity: 0.6; box-sizing: border-box; } -.reveal .overlay header a:hover { +.reveal > .overlay header a:hover { opacity: 1; } -.reveal .overlay header a .icon { +.reveal > .overlay header a .icon { display: inline-block; width: 20px; height: 20px; @@ -1356,13 +1332,13 @@ body { background-size: 100%; background-repeat: no-repeat; } -.reveal .overlay header a.close .icon { +.reveal > .overlay header a.close .icon { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABkklEQVRYR8WX4VHDMAxG6wnoJrABZQPYBCaBTWAD2g1gE5gg6OOsXuxIlr40d81dfrSJ9V4c2VLK7spHuTJ/5wpM07QXuXc5X0opX2tEJcadjHuV80li/FgxTIEK/5QBCICBD6xEhSMGHgQPgBgLiYVAB1dpSqKDawxTohFw4JSEA3clzgIBPCURwE2JucBR7rhPJJv5OpJwDX+SfDjgx1wACQeJG1aChP9K/IMmdZ8DtESV1WyP3Bt4MwM6sj4NMxMYiqUWHQu4KYA/SYkIjOsm3BXYWMKFDwU2khjCQ4ELJUJ4SmClRArOCmSXGuKma0fYD5CbzHxFpCSGAhfAVSSUGDUk2BWZaff2g6GE15BsBQ9nwmpIGDiyHQddwNTMKkbZaf9fajXQca1EX44puJZUsnY0ObGmITE3GVLCbEhQUjGVt146j6oasWN+49Vph2w1pZ5EansNZqKBm1txbU57iRRcZ86RWMDdWtBJUHBHwoQPi1GV+JCbntmvok7iTX4/Up9mgyTc/FJYDTcndgH/AA5A/CHsyEkVAAAAAElFTkSuQmCC); } -.reveal .overlay header a.external .icon { +.reveal > .overlay header a.external .icon { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAcElEQVRYR+2WSQoAIQwEzf8f7XiOMkUQxUPlGkM3hVmiQfQR9GYnH1SsAQlI4DiBqkCMoNb9y2e90IAEJPAcgdznU9+engMaeJ7Azh5Y1U67gAho4DqBqmB1buAf0MB1AlVBek83ZPkmJMGc1wAR+AAqod/B97TRpQAAAABJRU5ErkJggg==); } -.reveal .overlay .viewport { +.reveal > .overlay .viewport { position: absolute; display: -webkit-box; display: -ms-flexbox; @@ -1372,7 +1348,7 @@ body { bottom: 0; left: 0; } -.reveal .overlay.overlay-preview .viewport iframe { +.reveal > .overlay.overlay-preview .viewport iframe { width: 100%; height: 100%; max-width: 100%; @@ -1382,11 +1358,11 @@ body { visibility: hidden; transition: all 0.3s ease; } -.reveal .overlay.overlay-preview.loaded .viewport iframe { +.reveal > .overlay.overlay-preview.loaded .viewport iframe { opacity: 1; visibility: visible; } -.reveal .overlay.overlay-preview.loaded .viewport-inner { +.reveal > .overlay.overlay-preview.loaded .viewport-inner { position: absolute; z-index: -1; left: 0; @@ -1395,46 +1371,46 @@ body { text-align: center; letter-spacing: normal; } -.reveal .overlay.overlay-preview .x-frame-error { +.reveal > .overlay.overlay-preview .x-frame-error { opacity: 0; transition: opacity 0.3s ease 0.3s; } -.reveal .overlay.overlay-preview.loaded .x-frame-error { +.reveal > .overlay.overlay-preview.loaded .x-frame-error { opacity: 1; } -.reveal .overlay.overlay-preview.loaded .spinner { +.reveal > .overlay.overlay-preview.loaded .spinner { opacity: 0; visibility: hidden; -webkit-transform: scale(0.2); transform: scale(0.2); } -.reveal .overlay.overlay-help .viewport { +.reveal > .overlay.overlay-help .viewport { overflow: auto; color: #fff; } -.reveal .overlay.overlay-help .viewport .viewport-inner { +.reveal > .overlay.overlay-help .viewport .viewport-inner { width: 600px; margin: auto; padding: 20px 20px 80px 20px; text-align: center; letter-spacing: normal; } -.reveal .overlay.overlay-help .viewport .viewport-inner .title { +.reveal > .overlay.overlay-help .viewport .viewport-inner .title { font-size: 20px; } -.reveal .overlay.overlay-help .viewport .viewport-inner table { +.reveal > .overlay.overlay-help .viewport .viewport-inner table { border: 1px solid #fff; border-collapse: collapse; font-size: 16px; } -.reveal .overlay.overlay-help .viewport .viewport-inner table th, -.reveal .overlay.overlay-help .viewport .viewport-inner table td { +.reveal > .overlay.overlay-help .viewport .viewport-inner table th, +.reveal > .overlay.overlay-help .viewport .viewport-inner table td { width: 200px; padding: 14px; border: 1px solid #fff; vertical-align: middle; } -.reveal .overlay.overlay-help .viewport .viewport-inner table th { +.reveal > .overlay.overlay-help .viewport .viewport-inner table th { padding-top: 20px; padding-bottom: 20px; } diff --git a/css/reveal.scss b/css/reveal.scss index e6608d4..63d1d45 100644 --- a/css/reveal.scss +++ b/css/reveal.scss @@ -8,37 +8,6 @@ /********************************************* - * RESET STYLES - *********************************************/ - -html, body, .reveal div, .reveal span, .reveal applet, .reveal object, .reveal iframe, -.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal p, .reveal blockquote, .reveal pre, -.reveal a, .reveal abbr, .reveal acronym, .reveal address, .reveal big, .reveal cite, .reveal code, -.reveal del, .reveal dfn, .reveal em, .reveal img, .reveal ins, .reveal kbd, .reveal q, .reveal s, .reveal samp, -.reveal small, .reveal strike, .reveal strong, .reveal sub, .reveal sup, .reveal tt, .reveal var, -.reveal b, .reveal u, .reveal center, -.reveal dl, .reveal dt, .reveal dd, .reveal ol, .reveal ul, .reveal li, -.reveal fieldset, .reveal form, .reveal label, .reveal legend, -.reveal table, .reveal caption, .reveal tbody, .reveal tfoot, .reveal thead, .reveal tr, .reveal th, .reveal td, -.reveal article, .reveal aside, .reveal canvas, .reveal details, .reveal embed, -.reveal figure, .reveal figcaption, .reveal footer, .reveal header, .reveal hgroup, -.reveal menu, .reveal nav, .reveal output, .reveal ruby, .reveal section, .reveal summary, -.reveal time, .reveal mark, .reveal audio, .reveal video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -.reveal article, .reveal aside, .reveal details, .reveal figcaption, .reveal figure, -.reveal footer, .reveal header, .reveal hgroup, .reveal menu, .reveal nav, .reveal section { - display: block; -} - - -/********************************************* * GLOBAL STYLES *********************************************/ @@ -52,6 +21,7 @@ body { body { position: relative; line-height: 1; + margin: 0; background-color: #fff; color: #000; @@ -618,7 +588,7 @@ $controlsArrowAngleActive: 36deg; } .reveal .slides>section { - -ms-perspective: 600px; + perspective: 600px; } .reveal .slides>section, @@ -1067,37 +1037,38 @@ $controlsArrowAngleActive: 36deg; overflow-y: auto; } +.no-transforms .reveal { + overflow: visible; +} + .no-transforms .reveal .slides { position: relative; width: 80%; - height: auto !important; + max-width: 1280px; + height: auto; top: 0; - left: 50%; - margin: 0; + margin: 0 auto; text-align: center; } .no-transforms .reveal .controls, .no-transforms .reveal .progress { - display: none !important; + display: none; } .no-transforms .reveal .slides section { - display: block !important; - opacity: 1 !important; - position: relative !important; + display: block; + opacity: 1; + position: relative; height: auto; min-height: 0; top: 0; - left: -50%; + left: 0; + margin: 10vh 0; margin: 70px 0; transform: none; } -.no-transforms .reveal .slides section section { - left: 0; -} - .reveal .no-transition, .reveal .no-transition * { transition: none !important; @@ -1416,10 +1387,10 @@ $controlsArrowAngleActive: 36deg; /********************************************* - * LINK PREVIEW OVERLAY + * OVERLAY FOR LINK PREVIEWS AND HELP *********************************************/ -.reveal .overlay { +.reveal > .overlay { position: absolute; top: 0; left: 0; @@ -1431,12 +1402,12 @@ $controlsArrowAngleActive: 36deg; visibility: hidden; transition: all 0.3s ease; } - .reveal .overlay.visible { + .reveal > .overlay.visible { opacity: 1; visibility: visible; } - .reveal .overlay .spinner { + .reveal > .overlay .spinner { position: absolute; display: block; top: 50%; @@ -1452,7 +1423,7 @@ $controlsArrowAngleActive: 36deg; transition: all 0.3s ease; } - .reveal .overlay header { + .reveal > .overlay header { position: absolute; left: 0; top: 0; @@ -1461,7 +1432,7 @@ $controlsArrowAngleActive: 36deg; z-index: 2; border-bottom: 1px solid #222; } - .reveal .overlay header a { + .reveal > .overlay header a { display: inline-block; width: 40px; height: 40px; @@ -1472,10 +1443,10 @@ $controlsArrowAngleActive: 36deg; box-sizing: border-box; } - .reveal .overlay header a:hover { + .reveal > .overlay header a:hover { opacity: 1; } - .reveal .overlay header a .icon { + .reveal > .overlay header a .icon { display: inline-block; width: 20px; height: 20px; @@ -1484,14 +1455,14 @@ $controlsArrowAngleActive: 36deg; background-size: 100%; background-repeat: no-repeat; } - .reveal .overlay header a.close .icon { + .reveal > .overlay header a.close .icon { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABkklEQVRYR8WX4VHDMAxG6wnoJrABZQPYBCaBTWAD2g1gE5gg6OOsXuxIlr40d81dfrSJ9V4c2VLK7spHuTJ/5wpM07QXuXc5X0opX2tEJcadjHuV80li/FgxTIEK/5QBCICBD6xEhSMGHgQPgBgLiYVAB1dpSqKDawxTohFw4JSEA3clzgIBPCURwE2JucBR7rhPJJv5OpJwDX+SfDjgx1wACQeJG1aChP9K/IMmdZ8DtESV1WyP3Bt4MwM6sj4NMxMYiqUWHQu4KYA/SYkIjOsm3BXYWMKFDwU2khjCQ4ELJUJ4SmClRArOCmSXGuKma0fYD5CbzHxFpCSGAhfAVSSUGDUk2BWZaff2g6GE15BsBQ9nwmpIGDiyHQddwNTMKkbZaf9fajXQca1EX44puJZUsnY0ObGmITE3GVLCbEhQUjGVt146j6oasWN+49Vph2w1pZ5EansNZqKBm1txbU57iRRcZ86RWMDdWtBJUHBHwoQPi1GV+JCbntmvok7iTX4/Up9mgyTc/FJYDTcndgH/AA5A/CHsyEkVAAAAAElFTkSuQmCC); } - .reveal .overlay header a.external .icon { + .reveal > .overlay header a.external .icon { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAcElEQVRYR+2WSQoAIQwEzf8f7XiOMkUQxUPlGkM3hVmiQfQR9GYnH1SsAQlI4DiBqkCMoNb9y2e90IAEJPAcgdznU9+engMaeJ7Azh5Y1U67gAho4DqBqmB1buAf0MB1AlVBek83ZPkmJMGc1wAR+AAqod/B97TRpQAAAABJRU5ErkJggg==); } - .reveal .overlay .viewport { + .reveal > .overlay .viewport { position: absolute; display: flex; top: 40px; @@ -1500,7 +1471,7 @@ $controlsArrowAngleActive: 36deg; left: 0; } - .reveal .overlay.overlay-preview .viewport iframe { + .reveal > .overlay.overlay-preview .viewport iframe { width: 100%; height: 100%; max-width: 100%; @@ -1512,12 +1483,12 @@ $controlsArrowAngleActive: 36deg; transition: all 0.3s ease; } - .reveal .overlay.overlay-preview.loaded .viewport iframe { + .reveal > .overlay.overlay-preview.loaded .viewport iframe { opacity: 1; visibility: visible; } - .reveal .overlay.overlay-preview.loaded .viewport-inner { + .reveal > .overlay.overlay-preview.loaded .viewport-inner { position: absolute; z-index: -1; left: 0; @@ -1526,26 +1497,26 @@ $controlsArrowAngleActive: 36deg; text-align: center; letter-spacing: normal; } - .reveal .overlay.overlay-preview .x-frame-error { + .reveal > .overlay.overlay-preview .x-frame-error { opacity: 0; transition: opacity 0.3s ease 0.3s; } - .reveal .overlay.overlay-preview.loaded .x-frame-error { + .reveal > .overlay.overlay-preview.loaded .x-frame-error { opacity: 1; } - .reveal .overlay.overlay-preview.loaded .spinner { + .reveal > .overlay.overlay-preview.loaded .spinner { opacity: 0; visibility: hidden; transform: scale(0.2); } - .reveal .overlay.overlay-help .viewport { + .reveal > .overlay.overlay-help .viewport { overflow: auto; color: #fff; } - .reveal .overlay.overlay-help .viewport .viewport-inner { + .reveal > .overlay.overlay-help .viewport .viewport-inner { width: 600px; margin: auto; padding: 20px 20px 80px 20px; @@ -1553,25 +1524,25 @@ $controlsArrowAngleActive: 36deg; letter-spacing: normal; } - .reveal .overlay.overlay-help .viewport .viewport-inner .title { + .reveal > .overlay.overlay-help .viewport .viewport-inner .title { font-size: 20px; } - .reveal .overlay.overlay-help .viewport .viewport-inner table { + .reveal > .overlay.overlay-help .viewport .viewport-inner table { border: 1px solid #fff; border-collapse: collapse; font-size: 16px; } - .reveal .overlay.overlay-help .viewport .viewport-inner table th, - .reveal .overlay.overlay-help .viewport .viewport-inner table td { + .reveal > .overlay.overlay-help .viewport .viewport-inner table th, + .reveal > .overlay.overlay-help .viewport .viewport-inner table td { width: 200px; padding: 14px; border: 1px solid #fff; vertical-align: middle; } - .reveal .overlay.overlay-help .viewport .viewport-inner table th { + .reveal > .overlay.overlay-help .viewport .viewport-inner table th { padding-top: 20px; padding-bottom: 20px; } diff --git a/css/theme/template/settings.scss b/css/theme/template/settings.scss index 63c02cf..5a917f8 100644 --- a/css/theme/template/settings.scss +++ b/css/theme/template/settings.scss @@ -28,6 +28,8 @@ $heading2Size: 2.11em; $heading3Size: 1.55em; $heading4Size: 1.00em; +$codeFont: monospace; + // Links and actions $linkColor: #13DAEC; $linkColorHover: lighten( $linkColor, 20% ); @@ -40,4 +42,4 @@ $selectionColor: #fff; // to return a background image or gradient @mixin bodyBackground() { background: $backgroundColor; -}
\ No newline at end of file +} diff --git a/css/theme/template/theme.scss b/css/theme/template/theme.scss index a8f142d..215e2d4 100644 --- a/css/theme/template/theme.scss +++ b/css/theme/template/theme.scss @@ -162,7 +162,7 @@ body { text-align: left; font-size: 0.55em; - font-family: monospace; + font-family: $codeFont; line-height: 1.2em; word-wrap: break-word; @@ -171,7 +171,7 @@ body { } .reveal code { - font-family: monospace; + font-family: $codeFont; text-transform: none; } @@ -14,6 +14,7 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <link rel="stylesheet" href="css/reset.css"> <link rel="stylesheet" href="css/reveal.css"> <link rel="stylesheet" href="css/theme/black.css" id="theme"> @@ -93,7 +94,7 @@ Press <strong>ESC</strong> to enter the slide overview. </p> <p> - Hold down alt and click on any element to zoom in on it using <a href="http://lab.hakim.se/zoom-js">zoom.js</a>. Alt + click anywhere to zoom back out. + Hold down the <strong>alt</strong> key (<strong>ctrl</strong> in Linux) and click on any element to zoom towards it using <a href="http://lab.hakim.se/zoom-js">zoom.js</a>. Click again to zoom back out. </p> </section> @@ -384,7 +385,6 @@ Reveal.addEventListener( 'customevent', function() { </div> - <script src="lib/js/head.min.js"></script> <script src="js/reveal.js"></script> <script> @@ -400,7 +400,6 @@ Reveal.addEventListener( 'customevent', function() { // More info https://github.com/hakimel/reveal.js#dependencies dependencies: [ - { src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } }, { src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, { src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, { src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }, @@ -6,6 +6,7 @@ <title>reveal.js</title> + <link rel="stylesheet" href="css/reset.css"> <link rel="stylesheet" href="css/reveal.css"> <link rel="stylesheet" href="css/theme/black.css"> @@ -29,7 +30,6 @@ </div> </div> - <script src="lib/js/head.min.js"></script> <script src="js/reveal.js"></script> <script> diff --git a/js/reveal.js b/js/reveal.js index 3c31b97..637ea63 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -220,6 +220,12 @@ // The display mode that will be used to show slides display: 'block', + // Hide cursor if inactive + hideInactiveCursor: true, + + // Time before the cursor is hidden (in ms) + hideCursorTime: 5000, + // Script dependencies to load dependencies: [] @@ -282,6 +288,12 @@ // Delays updates to the URL due to a Chrome thumbnailer bug writeURLTimeout = 0, + // Is the mouse pointer currently hidden from view + cursorHidden = false, + + // Timeout used to determine when the cursor is inactive + cursorInactiveTimeout = 0, + // Flags if the interaction event listeners are bound eventsAreBound = false, @@ -306,17 +318,17 @@ // Holds information about the keyboard shortcuts keyboardShortcuts = { - 'N , SPACE': 'Next slide', - 'P': 'Previous slide', - '← , H': 'Navigate left', - '→ , L': 'Navigate right', - '↑ , K': 'Navigate up', - '↓ , J': 'Navigate down', - 'Home': 'First slide', - 'End': 'Last slide', - 'B , .': 'Pause', - 'F': 'Fullscreen', - 'ESC, O': 'Slide overview' + 'N , SPACE': 'Next slide', + 'P': 'Previous slide', + '← , H': 'Navigate left', + '→ , L': 'Navigate right', + '↑ , K': 'Navigate up', + '↓ , J': 'Navigate down', + 'Home , ⌘/CTRL ←': 'First slide', + 'End , ⌘/CTRL →': 'Last slide', + 'B , .': 'Pause', + 'F': 'Fullscreen', + 'ESC, O': 'Slide overview' }, // Holds custom key code mappings @@ -436,41 +448,28 @@ scriptsToPreload = 0; // Called once synchronous scripts finish loading - function proceed() { + function afterSynchronousScriptsLoaded() { + // Load asynchronous scripts if( scriptsAsync.length ) { - // Load asynchronous scripts - head.js.apply( null, scriptsAsync ); + scriptsAsync.forEach( function( s ) { + loadScript( s.src, s.callback ); + } ); } start(); } - function loadScript( s ) { - head.ready( s.src.match( /([\w\d_\-]*)\.?js(\?[\w\d.=&]*)?$|[^\\\/]*$/i )[0], function() { - // Extension may contain callback functions - if( typeof s.callback === 'function' ) { - s.callback.apply( this ); - } - - if( --scriptsToPreload === 0 ) { - proceed(); - } - }); - } - for( var i = 0, len = config.dependencies.length; i < len; i++ ) { var s = config.dependencies[i]; // Load if there's no condition or the condition is truthy if( !s.condition || s.condition() ) { if( s.async ) { - scriptsAsync.push( s.src ); + scriptsAsync.push( s ); } else { - scripts.push( s.src ); + scripts.push( s ); } - - loadScript( s ); } } @@ -478,15 +477,74 @@ scriptsToPreload = scripts.length; // Load synchronous scripts - head.js.apply( null, scripts ); + scripts.forEach( function( s ) { + loadScript( s.src, function() { + + if( typeof s.callback === 'function' ) s.callback(); + + if( --scriptsToPreload === 0 ) { + + afterSynchronousScriptsLoaded(); + + } + + } ); + } ); } else { - proceed(); + afterSynchronousScriptsLoaded(); } } /** + * Loads a JavaScript file from the given URL and executes it. + * + * @param {string} url Address of the .js file to load + * @param {function} callback Method to invoke when the script + * has loaded and executed + */ + function loadScript( url, callback ) { + + var script = document.createElement( 'script' ); + script.type = 'text/javascript'; + script.async = false; + script.defer = false; + script.src = url; + + if( callback ) { + + // Success callback + script.onload = script.onreadystatechange = function( event ) { + if( event.type === "load" || (/loaded|complete/.test( script.readyState ) ) ) { + + // Kill event listeners + script.onload = script.onreadystatechange = script.onerror = null; + + callback(); + + } + }; + + // Error callback + script.onerror = function( err ) { + + // Kill event listeners + script.onload = script.onreadystatechange = script.onerror = null; + + callback( new Error( 'Failed loading script: ' + script.src + '\n' + err) ); + + }; + + } + + // Append the script at the end of <head> + var head = document.querySelector( 'head' ); + head.insertBefore( script, head.lastChild ); + + } + + /** * Starts up reveal.js by binding input events and navigating * to the current URL deeplink if there is one. */ @@ -593,8 +651,7 @@ dom.speakerNotes.setAttribute( 'tabindex', '0' ); // Overlay graphic which is displayed during the paused mode - dom.pauseOverlay = createSingletonNode( dom.wrapper, 'div', 'pause-overlay', '<button class="resume-button">Resume presentation</button>' ); - dom.resumeButton = dom.pauseOverlay.querySelector( '.resume-button' ); + dom.pauseOverlay = createSingletonNode( dom.wrapper, 'div', 'pause-overlay', config.controls ? '<button class="resume-button">Resume presentation</button>' : null ); dom.wrapper.setAttribute( 'role', 'application' ); @@ -1208,6 +1265,18 @@ disableRollingLinks(); } + // Auto-hide the mouse pointer when its inactive + if( config.hideInactiveCursor ) { + document.addEventListener( 'mousemove', onDocumentCursorActive, false ); + document.addEventListener( 'mousedown', onDocumentCursorActive, false ); + } + else { + showCursor(); + + document.removeEventListener( 'mousemove', onDocumentCursorActive, false ); + document.removeEventListener( 'mousedown', onDocumentCursorActive, false ); + } + // Iframe link previews if( config.previewLinks ) { enablePreviewLinks(); @@ -1299,7 +1368,7 @@ dom.progress.addEventListener( 'click', onProgressClicked, false ); } - dom.resumeButton.addEventListener( 'click', resume, false ); + dom.pauseOverlay.addEventListener( 'click', resume, false ); if( config.focusBodyOnPageVisibilityChange ) { var visibilityChange; @@ -1364,7 +1433,7 @@ dom.wrapper.removeEventListener( 'touchmove', onTouchMove, false ); dom.wrapper.removeEventListener( 'touchend', onTouchEnd, false ); - dom.resumeButton.removeEventListener( 'click', resume, false ); + dom.pauseOverlay.removeEventListener( 'click', resume, false ); if ( config.progress && dom.progress ) { dom.progress.removeEventListener( 'click', onProgressClicked, false ); @@ -2435,6 +2504,32 @@ } /** + * Shows the mouse pointer after it has been hidden with + * #hideCursor. + */ + function showCursor() { + + if( cursorHidden ) { + cursorHidden = false; + dom.wrapper.style.cursor = ''; + } + + } + + /** + * Hides the mouse pointer when it's on top of the .reveal + * container. + */ + function hideCursor() { + + if( cursorHidden === false ) { + cursorHidden = true; + dom.wrapper.style.cursor = 'none'; + } + + } + + /** * Enters the paused mode which fades everything on screen to * black. */ @@ -2576,28 +2671,6 @@ layout(); - // Apply the new state - stateLoop: for( var i = 0, len = state.length; i < len; i++ ) { - // Check if this state existed on the previous slide. If it - // did, we will avoid adding it repeatedly - for( var j = 0; j < stateBefore.length; j++ ) { - if( stateBefore[j] === state[i] ) { - stateBefore.splice( j, 1 ); - continue stateLoop; - } - } - - document.documentElement.classList.add( state[i] ); - - // Dispatch custom event matching the state's name - dispatchEvent( state[i] ); - } - - // Clean up the remains of the previous state - while( stateBefore.length ) { - document.documentElement.classList.remove( stateBefore.pop() ); - } - // Update the overview if it's currently active if( isOverview() ) { updateOverview(); @@ -2646,6 +2719,28 @@ } } + // Apply the new state + stateLoop: for( var i = 0, len = state.length; i < len; i++ ) { + // Check if this state existed on the previous slide. If it + // did, we will avoid adding it repeatedly + for( var j = 0; j < stateBefore.length; j++ ) { + if( stateBefore[j] === state[i] ) { + stateBefore.splice( j, 1 ); + continue stateLoop; + } + } + + document.documentElement.classList.add( state[i] ); + + // Dispatch custom event matching the state's name + dispatchEvent( state[i] ); + } + + // Clean up the remains of the previous state + while( stateBefore.length ) { + document.documentElement.classList.remove( stateBefore.pop() ); + } + if( slideChanged ) { dispatchEvent( 'slidechanged', { 'indexh': indexh, @@ -2671,6 +2766,7 @@ updateParallax(); updateSlideNumber(); updateNotes(); + updateFragments(); // Update the URL hash writeURL(); @@ -2895,14 +2991,11 @@ element.classList.add( reverse ? 'future' : 'past' ); if( config.fragments ) { - var pastFragments = toArray( element.querySelectorAll( '.fragment' ) ); - - // Show all fragments on prior slides - while( pastFragments.length ) { - var pastFragment = pastFragments.pop(); - pastFragment.classList.add( 'visible' ); - pastFragment.classList.remove( 'current-fragment' ); - } + // Show all fragments in prior slides + toArray( element.querySelectorAll( '.fragment' ) ).forEach( function( fragment ) { + fragment.classList.add( 'visible' ); + fragment.classList.remove( 'current-fragment' ); + } ); } } else if( i > index ) { @@ -2910,14 +3003,11 @@ element.classList.add( reverse ? 'past' : 'future' ); if( config.fragments ) { - var futureFragments = toArray( element.querySelectorAll( '.fragment.visible' ) ); - - // No fragments in future slides should be visible ahead of time - while( futureFragments.length ) { - var futureFragment = futureFragments.pop(); - futureFragment.classList.remove( 'visible' ); - futureFragment.classList.remove( 'current-fragment' ); - } + // Hide all fragments in future slides + toArray( element.querySelectorAll( '.fragment.visible' ) ).forEach( function( fragment ) { + fragment.classList.remove( 'visible' ); + fragment.classList.remove( 'current-fragment' ); + } ); } } } @@ -3980,10 +4070,13 @@ // Ensure that we're not already on a slide with the same name var isSameNameAsCurrentSlide = currentSlide ? currentSlide.getAttribute( 'id' ) === name : false; - if( element && !isSameNameAsCurrentSlide ) { - // Find the position of the named slide and navigate to it - var indices = Reveal.getIndices( element ); - slide( indices.h, indices.v ); + if( element ) { + // If the slide exists and is not the current slide... + if ( !isSameNameAsCurrentSlide ) { + // ...find the position of the named slide and navigate to it + var indices = Reveal.getIndices(element); + slide(indices.h, indices.v); + } } // If the slide doesn't exist, navigate to the current slide else { @@ -4100,6 +4193,25 @@ } /** + * Returns an array of objects where each object represents the + * attributes on its respective slide. + */ + function getSlidesAttributes() { + + return getSlides().map( function( slide ) { + + var attributes = {}; + for( var i = 0; i < slide.attributes.length; i++ ) { + var attribute = slide.attributes[ i ]; + attributes[ attribute.name ] = attribute.value; + } + return attributes; + + } ); + + } + + /** * Retrieves the total number of slides in this presentation. * * @return {number} @@ -4292,6 +4404,73 @@ } /** + * Refreshes the fragments on the current slide so that they + * have the appropriate classes (.visible + .current-fragment). + * + * @param {number} [index] The index of the current fragment + * @param {array} [fragments] Array containing all fragments + * in the current slide + * + * @return {{shown: array, hidden: array}} + */ + function updateFragments( index, fragments ) { + + var changedFragments = { + shown: [], + hidden: [] + }; + + if( currentSlide && config.fragments ) { + + fragments = fragments || sortFragments( currentSlide.querySelectorAll( '.fragment' ) ); + + if( fragments.length ) { + + if( typeof index !== 'number' ) { + var currentFragment = sortFragments( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop(); + if( currentFragment ) { + index = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 ); + } + } + + toArray( fragments ).forEach( function( el, i ) { + + if( el.hasAttribute( 'data-fragment-index' ) ) { + i = parseInt( el.getAttribute( 'data-fragment-index' ), 10 ); + } + + // Visible fragments + if( i <= index ) { + if( !el.classList.contains( 'visible' ) ) changedFragments.shown.push( el ); + el.classList.add( 'visible' ); + el.classList.remove( 'current-fragment' ); + + // Announce the fragments one by one to the Screen Reader + dom.statusDiv.textContent = getStatusText( el ); + + if( i === index ) { + el.classList.add( 'current-fragment' ); + startEmbeddedContent( el ); + } + } + // Hidden fragments + else { + if( el.classList.contains( 'visible' ) ) changedFragments.hidden.push( el ); + el.classList.remove( 'visible' ); + el.classList.remove( 'current-fragment' ); + } + + } ); + + } + + } + + return changedFragments; + + } + + /** * Navigate to the specified slide fragment. * * @param {?number} index The index of the fragment that @@ -4326,53 +4505,24 @@ index += offset; } - var fragmentsShown = [], - fragmentsHidden = []; - - toArray( fragments ).forEach( function( element, i ) { - - if( element.hasAttribute( 'data-fragment-index' ) ) { - i = parseInt( element.getAttribute( 'data-fragment-index' ), 10 ); - } - - // Visible fragments - if( i <= index ) { - if( !element.classList.contains( 'visible' ) ) fragmentsShown.push( element ); - element.classList.add( 'visible' ); - element.classList.remove( 'current-fragment' ); - - // Announce the fragments one by one to the Screen Reader - dom.statusDiv.textContent = getStatusText( element ); - - if( i === index ) { - element.classList.add( 'current-fragment' ); - startEmbeddedContent( element ); - } - } - // Hidden fragments - else { - if( element.classList.contains( 'visible' ) ) fragmentsHidden.push( element ); - element.classList.remove( 'visible' ); - element.classList.remove( 'current-fragment' ); - } + var changedFragments = updateFragments( index, fragments ); - } ); - - if( fragmentsHidden.length ) { - dispatchEvent( 'fragmenthidden', { fragment: fragmentsHidden[0], fragments: fragmentsHidden } ); + if( changedFragments.hidden.length ) { + dispatchEvent( 'fragmenthidden', { fragment: changedFragments.hidden[0], fragments: changedFragments.hidden } ); } - if( fragmentsShown.length ) { - dispatchEvent( 'fragmentshown', { fragment: fragmentsShown[0], fragments: fragmentsShown } ); + if( changedFragments.shown.length ) { + dispatchEvent( 'fragmentshown', { fragment: changedFragments.shown[0], fragments: changedFragments.shown } ); } updateControls(); updateProgress(); + if( config.fragmentInURL ) { writeURL(); } - return !!( fragmentsShown.length || fragmentsHidden.length ); + return !!( changedFragments.shown.length || changedFragments.hidden.length ); } @@ -4668,6 +4818,22 @@ } /** + * Called whenever there is mouse input at the document level + * to determine if the cursor is active or not. + * + * @param {object} event + */ + function onDocumentCursorActive( event ) { + + showCursor(); + + clearTimeout( cursorInactiveTimeout ); + + cursorInactiveTimeout = setTimeout( hideCursor, config.hideCursorTime ); + + } + + /** * Handler for the document level 'keypress' event. * * @param {object} event @@ -4699,15 +4865,23 @@ onUserInput( event ); - // Check if there's a focused element that could be using - // the keyboard + // Is there a focused element that could be using the keyboard? var activeElementIsCE = document.activeElement && document.activeElement.contentEditable !== 'inherit'; var activeElementIsInput = document.activeElement && document.activeElement.tagName && /input|textarea/i.test( document.activeElement.tagName ); var activeElementIsNotes = document.activeElement && document.activeElement.className && /speaker-notes/i.test( document.activeElement.className); + // Whitelist specific modified + keycode combinations + var prevSlideShortcut = event.shiftKey && event.keyCode === 32; + var firstSlideShortcut = ( event.metaKey || event.ctrlKey ) && event.keyCode === 37; + var lastSlideShortcut = ( event.metaKey || event.ctrlKey ) && event.keyCode === 39; + + // Prevent all other events when a modifier is pressed + var unusedModifier = !prevSlideShortcut && !firstSlideShortcut && !lastSlideShortcut && + ( event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ); + // Disregard the event if there's a focused element or a // keyboard modifier key is present - if( activeElementIsCE || activeElementIsInput || activeElementIsNotes || (event.shiftKey && event.keyCode !== 32) || event.altKey || event.ctrlKey || event.metaKey ) return; + if( activeElementIsCE || activeElementIsInput || activeElementIsNotes || unusedModifier ) return; // While paused only allow resume keyboard events; 'b', 'v', '.' var resumeKeyCodes = [66,86,190,191]; @@ -4791,9 +4965,9 @@ // n, page down case 78: case 34: navigateNext(); break; // h, left - case 72: case 37: navigateLeft(); break; + case 72: case 37: firstSlideShortcut ? slide( 0 ) : navigateLeft(); break; // l, right - case 76: case 39: navigateRight(); break; + case 76: case 39: lastSlideShortcut ? slide( Number.MAX_VALUE ) : navigateRight(); break; // k, up case 75: case 38: navigateUp(); break; // j, down @@ -5455,6 +5629,10 @@ // Returns an Array of all slides getSlides: getSlides, + // Returns an Array of objects representing the attributes on + // the slides + getSlidesAttributes: getSlidesAttributes, + // Returns the total number of slides getTotalSlides: getTotalSlides, @@ -5505,6 +5683,11 @@ return query; }, + // Returns the top-level DOM element + getRevealElement: function() { + return dom.wrapper || document.querySelector( '.reveal' ); + }, + // Returns true if we're currently on the first slide isFirstSlide: function() { return ( indexh === 0 && indexv === 0 ); @@ -5546,12 +5729,12 @@ // Forward event binding to the reveal DOM element addEventListener: function( type, listener, useCapture ) { if( 'addEventListener' in window ) { - ( dom.wrapper || document.querySelector( '.reveal' ) ).addEventListener( type, listener, useCapture ); + Reveal.getRevealElement().addEventListener( type, listener, useCapture ); } }, removeEventListener: function( type, listener, useCapture ) { if( 'addEventListener' in window ) { - ( dom.wrapper || document.querySelector( '.reveal' ) ).removeEventListener( type, listener, useCapture ); + Reveal.getRevealElement().removeEventListener( type, listener, useCapture ); } }, diff --git a/lib/js/classList.js b/lib/js/classList.js deleted file mode 100644 index 44f2b4c..0000000 --- a/lib/js/classList.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/ -if(typeof document!=="undefined"&&!("classList" in document.createElement("a"))){(function(j){var a="classList",f="prototype",m=(j.HTMLElement||j.Element)[f],b=Object,k=String[f].trim||function(){return this.replace(/^\s+|\s+$/g,"")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===""){throw new n("SYNTAX_ERR","An invalid or illegal string was specified")}if(/\s/.test(o)){throw new n("INVALID_CHARACTER_ERR","String contains an invalid character")}return c.call(p,o)},d=function(s){var r=k.call(s.className),q=r?r.split(/\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.className=this.toString()}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+="";return g(this,o)!==-1};e.add=function(o){o+="";if(g(this,o)===-1){this.push(o);this._updateClassName()}};e.remove=function(p){p+="";var o=g(this,p);if(o!==-1){this.splice(o,1);this._updateClassName()}};e.toggle=function(o){o+="";if(g(this,o)===-1){this.add(o)}else{this.remove(o)}};e.toString=function(){return this.join(" ")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))};
\ No newline at end of file diff --git a/lib/js/head.min.js b/lib/js/head.min.js deleted file mode 100644 index 1527167..0000000 --- a/lib/js/head.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! head.core - v1.0.2 */ -(function(n,t){"use strict";function r(n){a[a.length]=n}function k(n){var t=new RegExp(" ?\\b"+n+"\\b");c.className=c.className.replace(t,"")}function p(n,t){for(var i=0,r=n.length;i<r;i++)t.call(n,n[i],i)}function tt(){var t,e,f,o;c.className=c.className.replace(/ (w-|eq-|gt-|gte-|lt-|lte-|portrait|no-portrait|landscape|no-landscape)\d+/g,"");t=n.innerWidth||c.clientWidth;e=n.outerWidth||n.screen.width;u.screen.innerWidth=t;u.screen.outerWidth=e;r("w-"+t);p(i.screens,function(n){t>n?(i.screensCss.gt&&r("gt-"+n),i.screensCss.gte&&r("gte-"+n)):t<n?(i.screensCss.lt&&r("lt-"+n),i.screensCss.lte&&r("lte-"+n)):t===n&&(i.screensCss.lte&&r("lte-"+n),i.screensCss.eq&&r("e-q"+n),i.screensCss.gte&&r("gte-"+n))});f=n.innerHeight||c.clientHeight;o=n.outerHeight||n.screen.height;u.screen.innerHeight=f;u.screen.outerHeight=o;u.feature("portrait",f>t);u.feature("landscape",f<t)}function it(){n.clearTimeout(b);b=n.setTimeout(tt,50)}var y=n.document,rt=n.navigator,ut=n.location,c=y.documentElement,a=[],i={screens:[240,320,480,640,768,800,1024,1280,1440,1680,1920],screensCss:{gt:!0,gte:!1,lt:!0,lte:!1,eq:!1},browsers:[{ie:{min:6,max:11}}],browserCss:{gt:!0,gte:!1,lt:!0,lte:!1,eq:!0},html5:!0,page:"-page",section:"-section",head:"head"},v,u,s,w,o,h,l,d,f,g,nt,e,b;if(n.head_conf)for(v in n.head_conf)n.head_conf[v]!==t&&(i[v]=n.head_conf[v]);u=n[i.head]=function(){u.ready.apply(null,arguments)};u.feature=function(n,t,i){return n?(Object.prototype.toString.call(t)==="[object Function]"&&(t=t.call()),r((t?"":"no-")+n),u[n]=!!t,i||(k("no-"+n),k(n),u.feature()),u):(c.className+=" "+a.join(" "),a=[],u)};u.feature("js",!0);s=rt.userAgent.toLowerCase();w=/mobile|android|kindle|silk|midp|phone|(windows .+arm|touch)/.test(s);u.feature("mobile",w,!0);u.feature("desktop",!w,!0);s=/(chrome|firefox)[ \/]([\w.]+)/.exec(s)||/(iphone|ipad|ipod)(?:.*version)?[ \/]([\w.]+)/.exec(s)||/(android)(?:.*version)?[ \/]([\w.]+)/.exec(s)||/(webkit|opera)(?:.*version)?[ \/]([\w.]+)/.exec(s)||/(msie) ([\w.]+)/.exec(s)||/(trident).+rv:(\w.)+/.exec(s)||[];o=s[1];h=parseFloat(s[2]);switch(o){case"msie":case"trident":o="ie";h=y.documentMode||h;break;case"firefox":o="ff";break;case"ipod":case"ipad":case"iphone":o="ios";break;case"webkit":o="safari"}for(u.browser={name:o,version:h},u.browser[o]=!0,l=0,d=i.browsers.length;l<d;l++)for(f in i.browsers[l])if(o===f)for(r(f),g=i.browsers[l][f].min,nt=i.browsers[l][f].max,e=g;e<=nt;e++)h>e?(i.browserCss.gt&&r("gt-"+f+e),i.browserCss.gte&&r("gte-"+f+e)):h<e?(i.browserCss.lt&&r("lt-"+f+e),i.browserCss.lte&&r("lte-"+f+e)):h===e&&(i.browserCss.lte&&r("lte-"+f+e),i.browserCss.eq&&r("eq-"+f+e),i.browserCss.gte&&r("gte-"+f+e));else r("no-"+f);r(o);r(o+parseInt(h,10));i.html5&&o==="ie"&&h<9&&p("abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|progress|section|summary|time|video".split("|"),function(n){y.createElement(n)});p(ut.pathname.split("/"),function(n,u){if(this.length>2&&this[u+1]!==t)u&&r(this.slice(u,u+1).join("-").toLowerCase()+i.section);else{var f=n||"index",e=f.indexOf(".");e>0&&(f=f.substring(0,e));c.id=f.toLowerCase()+i.page;u||r("root"+i.section)}});u.screen={height:n.screen.height,width:n.screen.width};tt();b=0;n.addEventListener?n.addEventListener("resize",it,!1):n.attachEvent("onresize",it)})(window); -/*! head.css3 - v1.0.0 */ -(function(n,t){"use strict";function a(n){for(var r in n)if(i[n[r]]!==t)return!0;return!1}function r(n){var t=n.charAt(0).toUpperCase()+n.substr(1),i=(n+" "+c.join(t+" ")+t).split(" ");return!!a(i)}var h=n.document,o=h.createElement("i"),i=o.style,s=" -o- -moz- -ms- -webkit- -khtml- ".split(" "),c="Webkit Moz O ms Khtml".split(" "),l=n.head_conf&&n.head_conf.head||"head",u=n[l],f={gradient:function(){var n="background-image:";return i.cssText=(n+s.join("gradient(linear,left top,right bottom,from(#9f9),to(#fff));"+n)+s.join("linear-gradient(left top,#eee,#fff);"+n)).slice(0,-n.length),!!i.backgroundImage},rgba:function(){return i.cssText="background-color:rgba(0,0,0,0.5)",!!i.backgroundColor},opacity:function(){return o.style.opacity===""},textshadow:function(){return i.textShadow===""},multiplebgs:function(){i.cssText="background:url(https://),url(https://),red url(https://)";var n=(i.background||"").match(/url/g);return Object.prototype.toString.call(n)==="[object Array]"&&n.length===3},boxshadow:function(){return r("boxShadow")},borderimage:function(){return r("borderImage")},borderradius:function(){return r("borderRadius")},cssreflections:function(){return r("boxReflect")},csstransforms:function(){return r("transform")},csstransitions:function(){return r("transition")},touch:function(){return"ontouchstart"in n},retina:function(){return n.devicePixelRatio>1},fontface:function(){var t=u.browser.name,n=u.browser.version;switch(t){case"ie":return n>=9;case"chrome":return n>=13;case"ff":return n>=6;case"ios":return n>=5;case"android":return!1;case"webkit":return n>=5.1;case"opera":return n>=10;default:return!1}}};for(var e in f)f[e]&&u.feature(e,f[e].call(),!0);u.feature()})(window); -/*! head.load - v1.0.3 */ -(function(n,t){"use strict";function w(){}function u(n,t){if(n){typeof n=="object"&&(n=[].slice.call(n));for(var i=0,r=n.length;i<r;i++)t.call(n,n[i],i)}}function it(n,i){var r=Object.prototype.toString.call(i).slice(8,-1);return i!==t&&i!==null&&r===n}function s(n){return it("Function",n)}function a(n){return it("Array",n)}function et(n){var i=n.split("/"),t=i[i.length-1],r=t.indexOf("?");return r!==-1?t.substring(0,r):t}function f(n){(n=n||w,n._done)||(n(),n._done=1)}function ot(n,t,r,u){var f=typeof n=="object"?n:{test:n,success:!t?!1:a(t)?t:[t],failure:!r?!1:a(r)?r:[r],callback:u||w},e=!!f.test;return e&&!!f.success?(f.success.push(f.callback),i.load.apply(null,f.success)):e||!f.failure?u():(f.failure.push(f.callback),i.load.apply(null,f.failure)),i}function v(n){var t={},i,r;if(typeof n=="object")for(i in n)!n[i]||(t={name:i,url:n[i]});else t={name:et(n),url:n};return(r=c[t.name],r&&r.url===t.url)?r:(c[t.name]=t,t)}function y(n){n=n||c;for(var t in n)if(n.hasOwnProperty(t)&&n[t].state!==l)return!1;return!0}function st(n){n.state=ft;u(n.onpreload,function(n){n.call()})}function ht(n){n.state===t&&(n.state=nt,n.onpreload=[],rt({url:n.url,type:"cache"},function(){st(n)}))}function ct(){var n=arguments,t=n[n.length-1],r=[].slice.call(n,1),f=r[0];return(s(t)||(t=null),a(n[0]))?(n[0].push(t),i.load.apply(null,n[0]),i):(f?(u(r,function(n){s(n)||!n||ht(v(n))}),b(v(n[0]),s(f)?f:function(){i.load.apply(null,r)})):b(v(n[0])),i)}function lt(){var n=arguments,t=n[n.length-1],r={};return(s(t)||(t=null),a(n[0]))?(n[0].push(t),i.load.apply(null,n[0]),i):(u(n,function(n){n!==t&&(n=v(n),r[n.name]=n)}),u(n,function(n){n!==t&&(n=v(n),b(n,function(){y(r)&&f(t)}))}),i)}function b(n,t){if(t=t||w,n.state===l){t();return}if(n.state===tt){i.ready(n.name,t);return}if(n.state===nt){n.onpreload.push(function(){b(n,t)});return}n.state=tt;rt(n,function(){n.state=l;t();u(h[n.name],function(n){f(n)});o&&y()&&u(h.ALL,function(n){f(n)})})}function at(n){n=n||"";var t=n.split("?")[0].split(".");return t[t.length-1].toLowerCase()}function rt(t,i){function e(t){t=t||n.event;u.onload=u.onreadystatechange=u.onerror=null;i()}function o(f){f=f||n.event;(f.type==="load"||/loaded|complete/.test(u.readyState)&&(!r.documentMode||r.documentMode<9))&&(n.clearTimeout(t.errorTimeout),n.clearTimeout(t.cssTimeout),u.onload=u.onreadystatechange=u.onerror=null,i())}function s(){if(t.state!==l&&t.cssRetries<=20){for(var i=0,f=r.styleSheets.length;i<f;i++)if(r.styleSheets[i].href===u.href){o({type:"load"});return}t.cssRetries++;t.cssTimeout=n.setTimeout(s,250)}}var u,h,f;i=i||w;h=at(t.url);h==="css"?(u=r.createElement("link"),u.type="text/"+(t.type||"css"),u.rel="stylesheet",u.href=t.url,t.cssRetries=0,t.cssTimeout=n.setTimeout(s,500)):(u=r.createElement("script"),u.type="text/"+(t.type||"javascript"),u.src=t.url);u.onload=u.onreadystatechange=o;u.onerror=e;u.async=!1;u.defer=!1;t.errorTimeout=n.setTimeout(function(){e({type:"timeout"})},7e3);f=r.head||r.getElementsByTagName("head")[0];f.insertBefore(u,f.lastChild)}function vt(){for(var t,u=r.getElementsByTagName("script"),n=0,f=u.length;n<f;n++)if(t=u[n].getAttribute("data-headjs-load"),!!t){i.load(t);return}}function yt(n,t){var v,p,e;return n===r?(o?f(t):d.push(t),i):(s(n)&&(t=n,n="ALL"),a(n))?(v={},u(n,function(n){v[n]=c[n];i.ready(n,function(){y(v)&&f(t)})}),i):typeof n!="string"||!s(t)?i:(p=c[n],p&&p.state===l||n==="ALL"&&y()&&o)?(f(t),i):(e=h[n],e?e.push(t):e=h[n]=[t],i)}function e(){if(!r.body){n.clearTimeout(i.readyTimeout);i.readyTimeout=n.setTimeout(e,50);return}o||(o=!0,vt(),u(d,function(n){f(n)}))}function k(){r.addEventListener?(r.removeEventListener("DOMContentLoaded",k,!1),e()):r.readyState==="complete"&&(r.detachEvent("onreadystatechange",k),e())}var r=n.document,d=[],h={},c={},ut="async"in r.createElement("script")||"MozAppearance"in r.documentElement.style||n.opera,o,g=n.head_conf&&n.head_conf.head||"head",i=n[g]=n[g]||function(){i.ready.apply(null,arguments)},nt=1,ft=2,tt=3,l=4,p;if(r.readyState==="complete")e();else if(r.addEventListener)r.addEventListener("DOMContentLoaded",k,!1),n.addEventListener("load",e,!1);else{r.attachEvent("onreadystatechange",k);n.attachEvent("onload",e);p=!1;try{p=!n.frameElement&&r.documentElement}catch(wt){}p&&p.doScroll&&function pt(){if(!o){try{p.doScroll("left")}catch(t){n.clearTimeout(i.readyTimeout);i.readyTimeout=n.setTimeout(pt,50);return}e()}}()}i.load=i.js=ut?lt:ct;i.test=ot;i.ready=yt;i.ready(r,function(){y()&&u(h.ALL,function(n){f(n)});i.feature&&i.feature("domloaded",!0)})})(window);
\ No newline at end of file diff --git a/plugin/markdown/example.html b/plugin/markdown/example.html index 300e39e..b520304 100644 --- a/plugin/markdown/example.html +++ b/plugin/markdown/example.html @@ -109,7 +109,6 @@ </div> </div> - <script src="../../lib/js/head.min.js"></script> <script src="../../js/reveal.js"></script> <script> @@ -122,7 +121,6 @@ // Optional libraries used to extend on reveal.js dependencies: [ - { src: '../../lib/js/classList.js', condition: function() { return !document.body.classList; } }, { src: 'marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, { src: 'markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, { src: '../highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }, diff --git a/plugin/markdown/markdown.js b/plugin/markdown/markdown.js index aa08ee5..31029ae 100755 --- a/plugin/markdown/markdown.js +++ b/plugin/markdown/markdown.js @@ -273,7 +273,7 @@ /** * Check if a node value has the attributes pattern. * If yes, extract it and add that value as one or several attributes - * the the terget element. + * to the target element. * * You need Cache Killer on Chrome to see the effect on any FOM transformation * directly on refresh (F5) diff --git a/plugin/math/math.js b/plugin/math/math.js index 7867376..29445cd 100755 --- a/plugin/math/math.js +++ b/plugin/math/math.js @@ -7,19 +7,26 @@ var RevealMath = window.RevealMath || (function(){ var options = Reveal.getConfig().math || {}; - options.mathjax = options.mathjax || 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js'; - options.config = options.config || 'TeX-AMS_HTML-full'; - options.tex2jax = options.tex2jax || { - inlineMath: [['$','$'],['\\(','\\)']] , - skipTags: ['script','noscript','style','textarea','pre'] }; + var mathjax = options.mathjax || 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js'; + var config = options.config || 'TeX-AMS_HTML-full'; + var url = mathjax + '?config=' + config; - loadScript( options.mathjax + '?config=' + options.config, function() { + var defaultOptions = { + messageStyle: 'none', + tex2jax: { + inlineMath: [ [ '$', '$' ], [ '\\(', '\\)' ] ], + skipTags: [ 'script', 'noscript', 'style', 'textarea', 'pre' ] + }, + skipStartupTypeset: true + }; - MathJax.Hub.Config({ - messageStyle: 'none', - tex2jax: options.tex2jax, - skipStartupTypeset: true - }); + defaults( options, defaultOptions ); + defaults( options.tex2jax, defaultOptions.tex2jax ); + options.mathjax = options.config = null; + + loadScript( url, function() { + + MathJax.Hub.Config( options ); // Typeset followed by an immediate reveal.js layout since // the typesetting process could affect slide height @@ -35,6 +42,16 @@ var RevealMath = window.RevealMath || (function(){ } ); + function defaults( options, defaultOptions ) { + + for ( var i in defaultOptions ) { + if ( !options.hasOwnProperty( i ) ) { + options[i] = defaultOptions[i]; + } + } + + } + function loadScript( url, callback ) { var head = document.querySelector( 'head' ); diff --git a/plugin/notes/notes.html b/plugin/notes/notes.html index 0c4eca5..9e0b230 100644 --- a/plugin/notes/notes.html +++ b/plugin/notes/notes.html @@ -347,6 +347,8 @@ upcomingSlide, layoutLabel, layoutDropdown, + pendingCalls = {}, + lastRevealApiCallId = 0, connected = false; var SPEAKER_LAYOUTS = { @@ -382,6 +384,10 @@ else if( data.type === 'state' ) { handleStateMessage( data ); } + else if( data.type === 'return' ) { + pendingCalls[data.callId](data.result); + delete pendingCalls[data.callId]; + } } // Messages sent by the reveal.js inside of the current slide preview else if( data && data.namespace === 'reveal' ) { @@ -399,6 +405,23 @@ } ); /** + * Asynchronously calls the Reveal.js API of the main frame. + */ + function callRevealApi( methodName, methodArguments, callback ) { + + var callId = ++lastRevealApiCallId; + pendingCalls[callId] = callback; + window.opener.postMessage( JSON.stringify( { + namespace: 'reveal-notes', + type: 'call', + callId: callId, + methodName: methodName, + arguments: methodArguments + } ), '*' ); + + } + + /** * Called when the main window is trying to establish a * connection. */ @@ -512,28 +535,34 @@ } - function getTimings() { + function getTimings( callback ) { - var slides = Reveal.getSlides(); - var defaultTiming = Reveal.getConfig().defaultTiming; - if (defaultTiming == null) { - return null; - } - var timings = []; - for ( var i in slides ) { - var slide = slides[i]; - var timing = defaultTiming; - if( slide.hasAttribute( 'data-timing' )) { - var t = slide.getAttribute( 'data-timing' ); - timing = parseInt(t); - if( isNaN(timing) ) { - console.warn("Could not parse timing '" + t + "' of slide " + i + "; using default of " + defaultTiming); - timing = defaultTiming; + callRevealApi( 'getSlidesAttributes', [], function ( slideAttributes ) { + callRevealApi( 'getConfig', [], function ( config ) { + var defaultTiming = config.defaultTiming; + if (defaultTiming == null) { + callback(null); + return; + } + + var timings = []; + for ( var i in slideAttributes ) { + var slide = slideAttributes[ i ]; + var timing = defaultTiming; + if( slide.hasOwnProperty( 'data-timing' )) { + var t = slide[ 'data-timing' ]; + timing = parseInt(t); + if( isNaN(timing) ) { + console.warn("Could not parse timing '" + t + "' of slide " + i + "; using default of " + defaultTiming); + timing = defaultTiming; + } + } + timings.push(timing); } - } - timings.push(timing); - } - return timings; + + callback( timings ); + } ); + } ); } @@ -541,15 +570,15 @@ * Return the number of seconds allocated for presenting * all slides up to and including this one. */ - function getTimeAllocated(timings) { + function getTimeAllocated( timings, callback ) { - var slides = Reveal.getSlides(); - var allocated = 0; - var currentSlide = Reveal.getSlidePastCount(); - for (var i in slides.slice(0, currentSlide + 1)) { - allocated += timings[i]; - } - return allocated; + callRevealApi( 'getSlidePastCount', [], function ( currentSlide ) { + var allocated = 0; + for (var i in timings.slice(0, currentSlide + 1)) { + allocated += timings[i]; + } + callback( allocated ); + } ); } @@ -571,12 +600,51 @@ pacingMinutesEl = pacingEl.querySelector( '.minutes-value' ), pacingSecondsEl = pacingEl.querySelector( '.seconds-value' ); - var timings = getTimings(); - if (timings !== null) { - pacingTitleEl.style.removeProperty('display'); - pacingEl.style.removeProperty('display'); + var timings = null; + getTimings( function ( _timings ) { + + timings = _timings; + if (_timings !== null) { + pacingTitleEl.style.removeProperty('display'); + pacingEl.style.removeProperty('display'); + } + + // Update once directly + _updateTimer(); + + // Then update every second + setInterval( _updateTimer, 1000 ); + + } ); + + + function _resetTimer() { + + if (timings == null) { + start = new Date(); + _updateTimer(); + } + else { + // Reset timer to beginning of current slide + getTimeAllocated( timings, function ( slideEndTimingSeconds ) { + var slideEndTiming = slideEndTimingSeconds * 1000; + callRevealApi( 'getSlidePastCount', [], function ( currentSlide ) { + var currentSlideTiming = timings[currentSlide] * 1000; + var previousSlidesTiming = slideEndTiming - currentSlideTiming; + var now = new Date(); + start = new Date(now.getTime() - previousSlidesTiming); + _updateTimer(); + } ); + } ); + } + } + timeEl.addEventListener( 'click', function() { + _resetTimer(); + return false; + } ); + function _displayTime( hrEl, minEl, secEl, time) { var sign = Math.sign(time) == -1 ? "-" : ""; @@ -618,52 +686,26 @@ function _updatePacing(diff) { - var slideEndTiming = getTimeAllocated(timings) * 1000; - var currentSlide = Reveal.getSlidePastCount(); - var currentSlideTiming = timings[currentSlide] * 1000; - var timeLeftCurrentSlide = slideEndTiming - diff; - if (timeLeftCurrentSlide < 0) { - pacingEl.className = 'pacing behind'; - } - else if (timeLeftCurrentSlide < currentSlideTiming) { - pacingEl.className = 'pacing on-track'; - } - else { - pacingEl.className = 'pacing ahead'; - } - _displayTime( pacingHoursEl, pacingMinutesEl, pacingSecondsEl, timeLeftCurrentSlide ); - - } - - // Update once directly - _updateTimer(); - - // Then update every second - setInterval( _updateTimer, 1000 ); - - function _resetTimer() { - - if (timings == null) { - start = new Date(); - } - else { - // Reset timer to beginning of current slide - var slideEndTiming = getTimeAllocated(timings) * 1000; - var currentSlide = Reveal.getSlidePastCount(); - var currentSlideTiming = timings[currentSlide] * 1000; - var previousSlidesTiming = slideEndTiming - currentSlideTiming; - var now = new Date(); - start = new Date(now.getTime() - previousSlidesTiming); - } - _updateTimer(); - + getTimeAllocated( timings, function ( slideEndTimingSeconds ) { + var slideEndTiming = slideEndTimingSeconds * 1000; + + callRevealApi( 'getSlidePastCount', [], function ( currentSlide ) { + var currentSlideTiming = timings[currentSlide] * 1000; + var timeLeftCurrentSlide = slideEndTiming - diff; + if (timeLeftCurrentSlide < 0) { + pacingEl.className = 'pacing behind'; + } + else if (timeLeftCurrentSlide < currentSlideTiming) { + pacingEl.className = 'pacing on-track'; + } + else { + pacingEl.className = 'pacing ahead'; + } + _displayTime( pacingHoursEl, pacingMinutesEl, pacingSecondsEl, timeLeftCurrentSlide ); + } ); + } ); } - timeEl.addEventListener( 'click', function() { - _resetTimer(); - return false; - } ); - } /** diff --git a/plugin/notes/notes.js b/plugin/notes/notes.js index a5b15b4..8d58ad0 100644 --- a/plugin/notes/notes.js +++ b/plugin/notes/notes.js @@ -11,24 +11,28 @@ */ var RevealNotes = (function() { + var notesPopup = null; + function openNotes( notesFilePath ) { + if (notesPopup && !notesPopup.closed) { + notesPopup.focus(); + return; + } + if( !notesFilePath ) { var jsFileLocation = document.querySelector('script[src$="notes.js"]').src; // this js file path jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path notesFilePath = jsFileLocation + 'notes.html'; } - var notesPopup = window.open( notesFilePath, 'reveal.js - Notes', 'width=1100,height=700' ); + notesPopup = window.open( notesFilePath, 'reveal.js - Notes', 'width=1100,height=700' ); if( !notesPopup ) { alert( 'Speaker view popup failed to open. Please make sure popups are allowed and reopen the speaker view.' ); return; } - // Allow popup window access to Reveal API - notesPopup.Reveal = window.Reveal; - /** * Connect to the notes window through a postmessage handshake. * Using postmessage enables us to work in situations where the @@ -52,10 +56,29 @@ var RevealNotes = (function() { clearInterval( connectInterval ); onConnected(); } + if( data && data.namespace === 'reveal-notes' && data.type === 'call' ) { + callRevealApi( data.methodName, data.arguments, data.callId ); + } } ); } /** + * Calls the specified Reveal.js method with the provided argument + * and then pushes the result to the notes frame. + */ + function callRevealApi( methodName, methodArguments, callId ) { + + var result = Reveal[methodName].call( Reveal, methodArguments ); + notesPopup.postMessage( JSON.stringify( { + namespace: 'reveal-notes', + type: 'return', + result: result, + callId: callId + } ), '*' ); + + } + + /** * Posts the current slide data to the notes window */ function post( event ) { diff --git a/plugin/search/search.js b/plugin/search/search.js index 6d694d2..21c0367 100644 --- a/plugin/search/search.js +++ b/plugin/search/search.js @@ -200,7 +200,7 @@ function Hilitor(id, tag) toggleSearch(); } }, false ); - if( window.Reveal ) Reveal.registerKeyboardShortcut( 'Ctrl-Shift-F', 'Search' ); + if( window.Reveal ) Reveal.registerKeyboardShortcut( 'CTRL + Shift + F', 'Search' ); closeSearch(); return { open: openSearch }; })(); diff --git a/test/assets/external-script-a.js b/test/assets/external-script-a.js new file mode 100644 index 0000000..cbc8da1 --- /dev/null +++ b/test/assets/external-script-a.js @@ -0,0 +1 @@ +window.externalScriptSequence += 'A';
\ No newline at end of file diff --git a/test/assets/external-script-b.js b/test/assets/external-script-b.js new file mode 100644 index 0000000..e5bca5a --- /dev/null +++ b/test/assets/external-script-b.js @@ -0,0 +1 @@ +window.externalScriptSequence += 'B';
\ No newline at end of file diff --git a/test/assets/external-script-c.js b/test/assets/external-script-c.js new file mode 100644 index 0000000..7d4ccf6 --- /dev/null +++ b/test/assets/external-script-c.js @@ -0,0 +1 @@ +window.externalScriptSequence += 'C';
\ No newline at end of file diff --git a/test/assets/external-script-d.js b/test/assets/external-script-d.js new file mode 100644 index 0000000..1c5925b --- /dev/null +++ b/test/assets/external-script-d.js @@ -0,0 +1 @@ +window.externalScriptSequence += 'D';
\ No newline at end of file diff --git a/test/examples/assets/beeping.txt b/test/examples/assets/beeping.txt new file mode 100644 index 0000000..bf41997 --- /dev/null +++ b/test/examples/assets/beeping.txt @@ -0,0 +1,2 @@ +Source: https://freesound.org/people/fennelliott/sounds/379419/ +License: CC0 (public domain)
\ No newline at end of file diff --git a/test/examples/assets/beeping.wav b/test/examples/assets/beeping.wav Binary files differnew file mode 100644 index 0000000..38747a5 --- /dev/null +++ b/test/examples/assets/beeping.wav diff --git a/test/examples/embedded-media.html b/test/examples/embedded-media.html index bbad4be..91457e4 100644 --- a/test/examples/embedded-media.html +++ b/test/examples/embedded-media.html @@ -30,11 +30,15 @@ <h2>Empty Slide</h2> </section> + <section> + <h2>Auto-playing audio</h2> + <audio src="assets/beeping.wav" data-autoplay></audio> + </section> + </div> </div> - <script src="../../lib/js/head.min.js"></script> <script src="../../js/reveal.js"></script> <script> diff --git a/test/examples/math.html b/test/examples/math.html index d35e827..0f74a8f 100644 --- a/test/examples/math.html +++ b/test/examples/math.html @@ -83,6 +83,14 @@ </section> <section> + <h3>TeX Macros</h3> + + Here is a common vector space: + \[L^2(\R) = \set{u : \R \to \R}{\int_\R |u|^2 < +\infty}\] + used in functional analysis. + </section> + + <section> <section> <h3>The Lorenz Equations</h3> @@ -153,13 +161,20 @@ \] </div> </section> + + <section> + <h3>TeX Macros</h3> + + Here is a common vector space: + \[L^2(\R) = \set{u : \R \to \R}{\int_\R |u|^2 < +\infty}\] + used in functional analysis. + </section> </section> </div> </div> - <script src="../../lib/js/head.min.js"></script> <script src="../../js/reveal.js"></script> <script> @@ -170,11 +185,16 @@ math: { // mathjax: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js', - config: 'TeX-AMS_HTML-full' + config: 'TeX-AMS_HTML-full', + TeX: { + Macros: { + R: '\\mathbb{R}', + set: [ '\\left\\{#1 \\; ; \\; #2\\right\\}', 2 ] + } + } }, dependencies: [ - { src: '../../lib/js/classList.js' }, { src: '../../plugin/math/math.js', async: true } ] }); diff --git a/test/examples/slide-backgrounds.html b/test/examples/slide-backgrounds.html index 316c92a..e08d260 100644 --- a/test/examples/slide-backgrounds.html +++ b/test/examples/slide-backgrounds.html @@ -122,7 +122,6 @@ </div> - <script src="../../lib/js/head.min.js"></script> <script src="../../js/reveal.js"></script> <script> diff --git a/test/examples/slide-transitions.html b/test/examples/slide-transitions.html index 88119dc..b7520ab 100644 --- a/test/examples/slide-transitions.html +++ b/test/examples/slide-transitions.html @@ -81,7 +81,6 @@ </div> - <script src="../../lib/js/head.min.js"></script> <script src="../../js/reveal.js"></script> <script> diff --git a/test/test-dependencies-async.html b/test/test-dependencies-async.html new file mode 100644 index 0000000..b36c31b --- /dev/null +++ b/test/test-dependencies-async.html @@ -0,0 +1,78 @@ +<!doctype html> +<html lang="en"> + + <head> + <meta charset="utf-8"> + + <title>reveal.js - Test Async Dependencies</title> + + <link rel="stylesheet" href="../css/reveal.css"> + <link rel="stylesheet" href="qunit-2.5.0.css"> + </head> + + <body style="overflow: auto;"> + + <div id="qunit"></div> + <div id="qunit-fixture"></div> + + <div class="reveal" style="display: none;"> + + <div class="slides"> + + <section>Slide content</section> + + </div> + + </div> + + <script src="../js/reveal.js"></script> + <script src="qunit-2.5.0.js"></script> + + <script> + var externalScriptSequence = ''; + var scriptCount = 0; + + QUnit.config.autostart = false; + QUnit.module( 'Async Dependencies' ); + + QUnit.test( 'Async scripts are loaded', function( assert ) { + assert.expect( 5 ); + var done = assert.async( 5 ); + + function callback( event ) { + if( externalScriptSequence.length === 1 ) { + assert.ok( externalScriptSequence === 'A', 'first callback was sync script' ); + done(); + } + else { + assert.ok( true, 'async script loaded' ); + done(); + } + + if( externalScriptSequence.length === 4 ) { + assert.ok( externalScriptSequence.indexOf( 'A' ) !== -1 && + externalScriptSequence.indexOf( 'B' ) !== -1 && + externalScriptSequence.indexOf( 'C' ) !== -1 && + externalScriptSequence.indexOf( 'D' ) !== -1, 'four unique scripts were loaded' ); + done(); + } + + scriptCount ++; + } + + Reveal.initialize({ + dependencies: [ + { src: 'assets/external-script-a.js', async: false, callback: callback }, + { src: 'assets/external-script-b.js', async: true, callback: callback }, + { src: 'assets/external-script-c.js', async: true, callback: callback }, + { src: 'assets/external-script-d.js', async: true, callback: callback } + ] + }); + }); + + QUnit.start(); + + </script> + + </body> +</html> diff --git a/test/test-dependencies.html b/test/test-dependencies.html new file mode 100644 index 0000000..49aaf60 --- /dev/null +++ b/test/test-dependencies.html @@ -0,0 +1,54 @@ +<!doctype html> +<html lang="en"> + + <head> + <meta charset="utf-8"> + + <title>reveal.js - Test Dependencies</title> + + <link rel="stylesheet" href="../css/reveal.css"> + <link rel="stylesheet" href="qunit-2.5.0.css"> + </head> + + <body style="overflow: auto;"> + + <div id="qunit"></div> + <div id="qunit-fixture"></div> + + <div class="reveal" style="display: none;"> + + <div class="slides"> + + <section>Slide content</section> + + </div> + + </div> + + <script src="../js/reveal.js"></script> + <script src="qunit-2.5.0.js"></script> + + <script> + window.externalScriptSequence = ''; + + Reveal.addEventListener( 'ready', function() { + + QUnit.module( 'Dependencies' ); + + QUnit.test( 'Load synchronous scripts', function( assert ) { + assert.strictEqual( window.externalScriptSequence, 'ABC', 'Loaded and executed in order' ); + }); + + } ); + + Reveal.initialize({ + dependencies: [ + { src: 'assets/external-script-a.js' }, + { src: 'assets/external-script-b.js' }, + { src: 'assets/external-script-c.js' } + ] + }); + </script> + + </body> +</html> diff --git a/test/test-markdown-element-attributes.html b/test/test-markdown-element-attributes.html index 4a09272..409d068 100644 --- a/test/test-markdown-element-attributes.html +++ b/test/test-markdown-element-attributes.html @@ -122,7 +122,6 @@ </div> - <script src="../lib/js/head.min.js"></script> <script src="../js/reveal.js"></script> <script src="../plugin/markdown/marked.js"></script> <script src="../plugin/markdown/markdown.js"></script> diff --git a/test/test-markdown-external.html b/test/test-markdown-external.html index d4912b0..76c6ae6 100644 --- a/test/test-markdown-external.html +++ b/test/test-markdown-external.html @@ -23,7 +23,6 @@ </div> - <script src="../lib/js/head.min.js"></script> <script src="../js/reveal.js"></script> <script src="../plugin/highlight/highlight.js"></script> <script src="../plugin/markdown/marked.js"></script> diff --git a/test/test-markdown-options.html b/test/test-markdown-options.html index 598243a..5391a19 100644 --- a/test/test-markdown-options.html +++ b/test/test-markdown-options.html @@ -31,7 +31,6 @@ </div> - <script src="../lib/js/head.min.js"></script> <script src="../js/reveal.js"></script> <script src="qunit-2.5.0.js"></script> diff --git a/test/test-markdown-slide-attributes.html b/test/test-markdown-slide-attributes.html index e90a9cf..ba9e710 100644 --- a/test/test-markdown-slide-attributes.html +++ b/test/test-markdown-slide-attributes.html @@ -116,7 +116,6 @@ </div> - <script src="../lib/js/head.min.js"></script> <script src="../js/reveal.js"></script> <script src="../plugin/markdown/marked.js"></script> <script src="../plugin/markdown/markdown.js"></script> diff --git a/test/test-markdown.html b/test/test-markdown.html index 00f7e7a..e1e5926 100644 --- a/test/test-markdown.html +++ b/test/test-markdown.html @@ -40,7 +40,6 @@ </div> - <script src="../lib/js/head.min.js"></script> <script src="../js/reveal.js"></script> <script src="../plugin/markdown/marked.js"></script> <script src="../plugin/markdown/markdown.js"></script> diff --git a/test/test-pdf.html b/test/test-pdf.html index 5ab8578..1455fb9 100644 --- a/test/test-pdf.html +++ b/test/test-pdf.html @@ -73,7 +73,6 @@ </div> - <script src="../lib/js/head.min.js"></script> <script src="../js/reveal.js"></script> <script src="qunit-2.5.0.js"></script> diff --git a/test/test-state.html b/test/test-state.html new file mode 100644 index 0000000..e6ae423 --- /dev/null +++ b/test/test-state.html @@ -0,0 +1,139 @@ +<!doctype html> +<html lang="en"> + + <head> + <meta charset="utf-8"> + + <title>reveal.js - Test State</title> + + <link rel="stylesheet" href="../css/reveal.css"> + <link rel="stylesheet" href="qunit-2.5.0.css"> + </head> + + <body style="overflow: auto;"> + + <div id="qunit"></div> + <div id="qunit-fixture"></div> + + <div class="reveal" style="display: none;"> + + <div class="slides"> + + <section>No state</section> + <section id="slide2" data-state="state1">State 1</section> + <section data-state="state1">State 1</section> + <section data-state="state2">State 2</section> + <section> + <section>No state</section> + <section data-state="state1">State 1</section> + <section data-state="state3">State 3</section> + <section>No state</section> + </section> + <section>No state</section> + + </div> + + </div> + + <script src="../js/reveal.js"></script> + <script src="qunit-2.5.0.js"></script> + + <script> + + + Reveal.addEventListener( 'ready', function() { + + QUnit.module( 'State' ); + + QUnit.test( 'Fire events when changing slide', function( assert ) { + assert.expect( 2 ); + var state1 = assert.async(); + var state2 = assert.async(); + + var _onState1 = function( event ) { + assert.ok( true, 'state1 fired' ); + state1(); + } + + var _onState2 = function( event ) { + assert.ok( true, 'state2 fired' ); + state2(); + } + + Reveal.addEventListener( 'state1', _onState1 ); + Reveal.addEventListener( 'state2', _onState2 ); + + Reveal.slide( 1 ); + Reveal.slide( 3 ); + + Reveal.removeEventListener( 'state1', _onState1 ); + Reveal.removeEventListener( 'state2', _onState2 ); + }); + + QUnit.test( 'Fire state events for vertical slides', function( assert ) { + assert.expect( 2 ); + var done = assert.async( 2 ); + + var _onState1 = function( event ) { + assert.ok( true, 'state1 fired' ); + done(); + } + + var _onState3 = function( event ) { + assert.ok( true, 'state3 fired' ); + done(); + } + + Reveal.addEventListener( 'state1', _onState1 ); + Reveal.addEventListener( 'state3', _onState3 ); + + Reveal.slide( 0 ); + Reveal.slide( 4, 1 ); + Reveal.slide( 4, 2 ); + + Reveal.removeEventListener( 'state1', _onState1 ); + Reveal.removeEventListener( 'state3', _onState3 ); + }); + + QUnit.test( 'No events if state remains unchanged', function( assert ) { + var stateChanges = 0; + + var _onEvent = function( event ) { + stateChanges += 1; + } + + Reveal.addEventListener( 'state1', _onEvent ); + + Reveal.slide( 0 ); // no state + Reveal.slide( 1 ); // state1 + Reveal.slide( 2 ); // state1 + Reveal.prev(); // state1 + Reveal.next(); // state1 + Reveal.slide( 4, 1 ); // state1 + Reveal.slide( 0 ); // no state + + Reveal.removeEventListener( 'state1', _onEvent ); + + assert.strictEqual( stateChanges, 1, 'no event was fired when going to slide with same state' ); + }); + + QUnit.test( 'Event order', function( assert ) { + var _onEvent = function( event ) { + assert.ok( Reveal.getCurrentSlide() == document.querySelector( '#slide2' ), 'correct current slide immediately after state event' ); + } + + Reveal.addEventListener( 'state1', _onEvent ); + + Reveal.slide( 0 ); + Reveal.slide( 1 ); + + Reveal.removeEventListener( 'state1', _onEvent ); + }); + + } ); + + Reveal.initialize(); + </script> + + </body> +</html> diff --git a/test/test.html b/test/test.html index f0a5050..67932b7 100644 --- a/test/test.html +++ b/test/test.html @@ -76,7 +76,6 @@ </div> - <script src="../lib/js/head.min.js"></script> <script src="../js/reveal.js"></script> <script src="qunit-2.5.0.js"></script> diff --git a/test/test.js b/test/test.js index f8515a0..2738403 100644 --- a/test/test.js +++ b/test/test.js @@ -262,6 +262,7 @@ Reveal.addEventListener( 'ready', function() { QUnit.test( 'Current fragment', function( assert ) { var fragmentSlide = document.querySelector( '#fragment-slides>section:nth-child(1)' ); + var lastFragmentIndex = [].slice.call( fragmentSlide.querySelectorAll( '.fragment' ) ).pop().getAttribute( 'data-fragment-index' ); Reveal.slide( 2, 0 ); assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 0, 'no current fragment at index -1' ); @@ -274,6 +275,10 @@ Reveal.addEventListener( 'ready', function() { Reveal.slide( 3, 0, 0 ); assert.strictEqual( fragmentSlide.querySelectorAll( '.fragment.current-fragment' ).length, 0, 'no current fragment when navigating to next slide' ); + + Reveal.slide( 2, 1, -1 ); + Reveal.prev(); + assert.strictEqual( fragmentSlide.querySelector( '.fragment.current-fragment' ).getAttribute( 'data-fragment-index' ), lastFragmentIndex, 'last fragment is current fragment when returning from future slide' ); }); QUnit.test( 'Stepping through fragments', function( assert ) { |