aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gruntfile.js2
-rw-r--r--LICENSE2
-rw-r--r--README.md61
-rw-r--r--css/reset.css30
-rw-r--r--css/reveal.css140
-rw-r--r--css/reveal.scss146
-rw-r--r--css/theme/template/settings.scss4
-rw-r--r--css/theme/template/theme.scss4
-rw-r--r--demo.html9
-rw-r--r--index.html2
-rw-r--r--js/reveal.js728
-rw-r--r--lib/js/classList.js2
-rw-r--r--lib/js/head.min.js6
-rw-r--r--package.json2
-rw-r--r--plugin/markdown/example.html2
-rwxr-xr-xplugin/markdown/markdown.js2
-rw-r--r--plugin/markdown/marked.js6
-rwxr-xr-xplugin/math/math.js39
-rw-r--r--plugin/notes/notes.html194
-rw-r--r--plugin/notes/notes.js31
-rw-r--r--plugin/search/search.js2
-rw-r--r--test/assets/external-script-a.js1
-rw-r--r--test/assets/external-script-b.js1
-rw-r--r--test/assets/external-script-c.js1
-rw-r--r--test/assets/external-script-d.js1
-rw-r--r--test/examples/assets/beeping.txt2
-rw-r--r--test/examples/assets/beeping.wavbin0 -> 422472 bytes
-rw-r--r--test/examples/embedded-media.html6
-rw-r--r--test/examples/math.html26
-rw-r--r--test/examples/slide-backgrounds.html1
-rw-r--r--test/examples/slide-transitions.html1
-rw-r--r--test/test-dependencies-async.html78
-rw-r--r--test/test-dependencies.html54
-rw-r--r--test/test-grid-navigation.html74
-rw-r--r--test/test-markdown-element-attributes.html4
-rw-r--r--test/test-markdown-external.html1
-rw-r--r--test/test-markdown-options.html1
-rw-r--r--test/test-markdown-slide-attributes.html1
-rw-r--r--test/test-markdown.html1
-rw-r--r--test/test-pdf.html1
-rw-r--r--test/test-state.html139
-rw-r--r--test/test.html1
-rw-r--r--test/test.js5
43 files changed, 1280 insertions, 534 deletions
diff --git a/Gruntfile.js b/Gruntfile.js
index 8d8300b..59ad896 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -15,7 +15,7 @@ module.exports = function(grunt) {
' * http://revealjs.com\n' +
' * MIT licensed\n' +
' *\n' +
- ' * Copyright (C) 2018 Hakim El Hattab, http://hakim.se\n' +
+ ' * Copyright (C) 2019 Hakim El Hattab, http://hakim.se\n' +
' */'
},
diff --git a/LICENSE b/LICENSE
index 1b8b5a7..697d156 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (C) 2018 Hakim El Hattab, http://hakim.se, and reveal.js contributors
+Copyright (C) 2019 Hakim El Hattab, http://hakim.se, and reveal.js contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 9bf6b22..8439017 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ reveal.js comes with a broad range of features including [nested slides](https:/
- [Ready Event](#ready-event)
- [Auto-sliding](#auto-sliding)
- [Keyboard Bindings](#keyboard-bindings)
+- [Vertical Slide Navigation](#vertical-slide-navigation)
- [Touch Navigation](#touch-navigation)
- [Lazy Loading](#lazy-loading)
- [API](#api)
@@ -226,7 +227,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
}
@@ -260,7 +261,11 @@ Reveal.initialize({
// Display the page number of the current slide
slideNumber: false,
- // Push each slide change to the browser history
+ // Add the current slide number to the URL hash so that reloading the
+ // page/copying the URL will return you to the same slide
+ hash: false,
+
+ // Push each slide change to the browser history. Implies `hash: true`
history: false,
// Enable keyboard shortcuts for navigation
@@ -281,6 +286,9 @@ Reveal.initialize({
// Change the presentation direction to be RTL
rtl: false,
+ // See https://github.com/hakimel/reveal.js/#navigation-mode
+ navigationMode: 'default',
+
// Randomizes the order of slides each time the presentation loads
shuffle: false,
@@ -327,6 +335,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,
@@ -424,9 +438,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]' ); } },
@@ -452,8 +463,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()`.
@@ -507,6 +516,21 @@ Reveal.configure({
});
```
+### Vertical Slide Navigation
+
+Slides can be nested within other slides to create vertical stacks (see [Markup](#markup)). When presenting, you use the left/right arrows to step through the main (horizontal) slides. When you arrive at a vertical stack you can optionally press the up/down arrows to view the vertical slides or skip past them by pressing the right arrow. Here's an example showing a bird's-eye view of what this looks like in action:
+
+<img src="https://static.slid.es/support/reveal.js-vertical-slides.gif" width="450">
+
+#### Navigation Mode
+You can finetune the reveal.js navigation behavior by using the `navigationMode` config option. Note that these options are only useful for presnetations that use a mix of horizontal and vertical slides. The following navigation modes are available:
+
+| Value | Description |
+| :--------------------------- | :---------- |
+| default | Left/right arrow keys step between horizontal slides. Up/down arrow keys step between vertical slides. Space key steps through all slides (both horizontal and vertical). |
+| linear | Removes the up/down arrows. Left/right arrows step through all slides (both horizontal and vertical). |
+| grid | When this is enabled, stepping left/right from a vertical stack to an adjacent vertical stack will land you at the same vertical index.<br><br>Consider a deck with six slides ordered in two vertical stacks:<br>`1.1`&nbsp;&nbsp;&nbsp;&nbsp;`2.1`<br>`1.2`&nbsp;&nbsp;&nbsp;&nbsp;`2.2`<br>`1.3`&nbsp;&nbsp;&nbsp;&nbsp;`2.3`<br><br>If you're on slide 1.3 and navigate right, you will normally move from 1.3 -> 2.1. With navigationMode set to "grid" the same navigation takes you from 1.3 -> 2.3. |
+
### Touch Navigation
You can swipe to navigate through a presentation on any touch-enabled device. Horizontal swipes change between horizontal slides, vertical swipes change between vertical slides. If you wish to disable this you can set the `touch` config option to false when initializing reveal.js.
@@ -517,7 +541,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>
@@ -530,6 +554,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:
@@ -586,6 +616,9 @@ Reveal.isLastSlide();
Reveal.isOverview();
Reveal.isPaused();
Reveal.isAutoSliding();
+
+// Returns the top-level DOM element
+getRevealElement(); // <div class="reveal">...</div>
```
### Custom Key Bindings
@@ -1179,7 +1212,7 @@ Reveal.initialize({
// Don't forget to add the dependencies
dependencies: [
- { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },
+ { src: '//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js', async: true },
{ src: 'plugin/multiplex/master.js', async: true },
// and if you want speaker notes
@@ -1209,7 +1242,7 @@ Reveal.initialize({
// Don't forget to add the dependencies
dependencies: [
- { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },
+ { src: '//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js', async: true },
{ src: 'plugin/multiplex/client.js', async: true }
// other dependencies...
@@ -1251,7 +1284,7 @@ Reveal.initialize({
// Don't forget to add the dependencies
dependencies: [
- { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },
+ { src: '//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js', async: true },
{ src: 'plugin/multiplex/client.js', async: true }
// other dependencies...
@@ -1275,7 +1308,7 @@ Reveal.initialize({
// Don't forget to add the dependencies
dependencies: [
- { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },
+ { src: '//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js', async: true },
{ src: 'plugin/multiplex/master.js', async: true },
{ src: 'plugin/multiplex/client.js', async: true }
@@ -1300,6 +1333,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: [
@@ -1321,4 +1356,4 @@ If you want to include math inside of a presentation written in Markdown you nee
MIT licensed
-Copyright (C) 2018 Hakim El Hattab, http://hakim.se
+Copyright (C) 2019 Hakim El Hattab, http://hakim.se
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..63ba646 100644
--- a/css/reveal.css
+++ b/css/reveal.css
@@ -3,47 +3,24 @@
* http://revealjs.com
* MIT licensed
*
- * Copyright (C) 2018 Hakim El Hattab, http://hakim.se
+ * Copyright (C) 2019 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,
-body {
+html {
width: 100%;
height: 100%;
+ height: 100vh;
+ height: calc( var(--vh, 1vh) * 100);
overflow: hidden; }
body {
+ height: 100%;
+ overflow: hidden;
position: relative;
line-height: 1;
+ margin: 0;
background-color: #fff;
color: #000; }
@@ -366,10 +343,16 @@ body {
.reveal .controls .enabled.fragmented:hover {
opacity: 1; }
+.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-up,
+.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-down {
+ display: none; }
+
+.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-left,
.reveal:not(.has-vertical-slides) .controls .navigate-left {
bottom: 1.4em;
right: 5.5em; }
+.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-right,
.reveal:not(.has-vertical-slides) .controls .navigate-right {
bottom: 1.4em;
right: 0.5em; }
@@ -486,12 +469,8 @@ body {
width: 100%;
height: 100%;
overflow: hidden;
- -ms-touch-action: none;
- touch-action: none; }
-
-@media only screen and (orientation: landscape) {
- .reveal.ua-iphone {
- position: fixed; } }
+ -ms-touch-action: pinch-zoom;
+ touch-action: pinch-zoom; }
.reveal .slides {
position: absolute;
@@ -512,7 +491,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 +969,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 +1275,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 +1289,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 +1307,7 @@ body {
opacity: 0.6;
transition: all 0.3s ease; }
-.reveal .overlay header {
+.reveal > .overlay header {
position: absolute;
left: 0;
top: 0;
@@ -1335,7 +1316,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 +1326,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 +1337,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 +1353,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 +1363,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 +1376,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; }
@@ -1512,7 +1493,7 @@ body {
.reveal .speaker-notes {
display: none;
position: absolute;
- width: 25vw;
+ width: 33.3333333333%;
height: 100%;
top: 0;
left: 100%;
@@ -1540,7 +1521,7 @@ body {
opacity: 0.5; }
.reveal.show-notes {
- max-width: 75vw;
+ max-width: 75%;
overflow: visible; }
.reveal.show-notes .speaker-notes {
@@ -1555,19 +1536,24 @@ body {
border-left: 0;
max-width: none;
max-height: 70%;
+ max-height: 70vh;
overflow: visible; }
.reveal.show-notes .speaker-notes {
top: 100%;
left: 0;
width: 100%;
- height: 42.8571428571%; } }
+ height: 42.8571428571%;
+ height: 30vh;
+ border: 0; } }
@media screen and (max-width: 600px) {
.reveal.show-notes {
- max-height: 60%; }
+ max-height: 60%;
+ max-height: 60vh; }
.reveal.show-notes .speaker-notes {
top: 100%;
- height: 66.6666666667%; }
+ height: 66.6666666667%;
+ height: 40vh; }
.reveal .speaker-notes {
font-size: 14px; } }
diff --git a/css/reveal.scss b/css/reveal.scss
index e6608d4..ad6d1f5 100644
--- a/css/reveal.scss
+++ b/css/reveal.scss
@@ -3,55 +3,28 @@
* http://revealjs.com
* MIT licensed
*
- * Copyright (C) 2018 Hakim El Hattab, http://hakim.se
+ * Copyright (C) 2019 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,
-body {
+html {
width: 100%;
height: 100%;
+ height: 100vh;
+ height: calc( var(--vh, 1vh) * 100 );
overflow: hidden;
}
body {
+ height: 100%;
+ overflow: hidden;
position: relative;
line-height: 1;
+ margin: 0;
background-color: #fff;
color: #000;
@@ -434,12 +407,19 @@ $controlsArrowAngleActive: 36deg;
}
}
+.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-up,
+.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-down {
+ display: none;
+}
+
// Adjust the layout when there are no vertical slides
+.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-left,
.reveal:not(.has-vertical-slides) .controls .navigate-left {
bottom: $controlArrowSpacing;
right: 0.5em + $controlArrowSpacing + $controlArrowSize;
}
+.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-right,
.reveal:not(.has-vertical-slides) .controls .navigate-right {
bottom: $controlArrowSpacing;
right: 0.5em;
@@ -586,17 +566,7 @@ $controlsArrowAngleActive: 36deg;
width: 100%;
height: 100%;
overflow: hidden;
- touch-action: none;
-}
-
-// Mobile Safari sometimes overlays a header at the top
-// of the page when in landscape mode. Using fixed
-// positioning ensures that reveal.js reduces its height
-// when this header is visible.
-@media only screen and (orientation : landscape) {
- .reveal.ua-iphone {
- position: fixed;
- }
+ touch-action: pinch-zoom;
}
.reveal .slides {
@@ -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;
}
@@ -1648,6 +1619,8 @@ $controlsArrowAngleActive: 36deg;
* SPEAKER NOTES
*********************************************/
+$notesWidthPercent: 25%;
+
// Hide on-page notes
.reveal aside.notes {
display: none;
@@ -1658,7 +1631,7 @@ $controlsArrowAngleActive: 36deg;
.reveal .speaker-notes {
display: none;
position: absolute;
- width: 25vw;
+ width: $notesWidthPercent / (1-$notesWidthPercent/100) * 1%;
height: 100%;
top: 0;
left: 100%;
@@ -1694,7 +1667,7 @@ $controlsArrowAngleActive: 36deg;
.reveal.show-notes {
- max-width: 75vw;
+ max-width: 100% - $notesWidthPercent;
overflow: visible;
}
@@ -1713,6 +1686,7 @@ $controlsArrowAngleActive: 36deg;
border-left: 0;
max-width: none;
max-height: 70%;
+ max-height: 70vh;
overflow: visible;
}
@@ -1721,17 +1695,21 @@ $controlsArrowAngleActive: 36deg;
left: 0;
width: 100%;
height: (30/0.7)*1%;
+ height: 30vh;
+ border: 0;
}
}
@media screen and (max-width: 600px) {
.reveal.show-notes {
max-height: 60%;
+ max-height: 60vh;
}
.reveal.show-notes .speaker-notes {
top: 100%;
height: (40/0.6)*1%;
+ height: 40vh;
}
.reveal .speaker-notes {
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;
}
diff --git a/demo.html b/demo.html
index 8aa4aba..6269746 100644
--- a/demo.html
+++ b/demo.html
@@ -12,8 +12,9 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <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>
@@ -393,14 +393,13 @@ Reveal.addEventListener( 'customevent', function() {
Reveal.initialize({
controls: true,
progress: true,
- history: true,
center: true,
+ hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// 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(); } },
diff --git a/index.html b/index.html
index 98accc3..ad28d21 100644
--- a/index.html
+++ b/index.html
@@ -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 b291bc7..8d150d8 100644
--- a/js/reveal.js
+++ b/js/reveal.js
@@ -3,7 +3,7 @@
* http://revealjs.com
* MIT licensed
*
- * Copyright (C) 2018 Hakim El Hattab, http://hakim.se
+ * Copyright (C) 2019 Hakim El Hattab, http://hakim.se
*/
(function( root, factory ) {
if( typeof define === 'function' && define.amd ) {
@@ -76,7 +76,11 @@
// Determine which displays to show the slide number on
showSlideNumber: 'all',
- // Push each slide change to the browser history
+ // Add the current slide number to the URL hash so that reloading the
+ // page/copying the URL will return you to the same slide
+ hash: false,
+
+ // Push each slide change to the browser history. Implies `hash: true`
history: false,
// Enable keyboard shortcuts for navigation
@@ -104,6 +108,32 @@
// Change the presentation direction to be RTL
rtl: false,
+ // Changes the behavior of our navigation directions.
+ //
+ // "default"
+ // Left/right arrow keys step between horizontal slides, up/down
+ // arrow keys step between vertical slides. Space key steps through
+ // all slides (both horizontal and vertical).
+ //
+ // "linear"
+ // Removes the up/down arrows. Left/right arrows step through all
+ // slides (both horizontal and vertical).
+ //
+ // "grid"
+ // When this is enabled, stepping left/right from a vertical stack
+ // to an adjacent vertical stack will land you at the same vertical
+ // index.
+ //
+ // Consider a deck with six slides ordered in two vertical stacks:
+ // 1.1 2.1
+ // 1.2 2.2
+ // 1.3 2.3
+ //
+ // If you're on slide 1.3 and navigate right, you will normally move
+ // from 1.3 -> 2.1. With "gridNavigation" enabled the same navigation
+ // takes you from 1.3 -> 2.3.
+ navigationMode: 'default',
+
// Randomizes the order of slides each time the presentation loads
shuffle: false,
@@ -220,6 +250,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 +318,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,
@@ -298,7 +340,6 @@
touch = {
startX: 0,
startY: 0,
- startSpan: 0,
startCount: 0,
captured: false,
threshold: 40
@@ -306,17 +347,17 @@
// Holds information about the keyboard shortcuts
keyboardShortcuts = {
- 'N , SPACE': 'Next slide',
- 'P': 'Previous slide',
- '&#8592; , H': 'Navigate left',
- '&#8594; , L': 'Navigate right',
- '&#8593; , K': 'Navigate up',
- '&#8595; , J': 'Navigate down',
- 'Home': 'First slide',
- 'End': 'Last slide',
- 'B , .': 'Pause',
- 'F': 'Fullscreen',
- 'ESC, O': 'Slide overview'
+ 'N , SPACE': 'Next slide',
+ 'P': 'Previous slide',
+ '&#8592; , H': 'Navigate left',
+ '&#8594; , L': 'Navigate right',
+ '&#8593; , K': 'Navigate up',
+ '&#8595; , J': 'Navigate down',
+ 'Home , &#8984;/CTRL &#8592;': 'First slide',
+ 'End , &#8984;/CTRL &#8594;': 'Last slide',
+ 'B , .': 'Pause',
+ 'F': 'Fullscreen',
+ 'ESC, O': 'Slide overview'
},
// Holds custom key code mappings
@@ -436,41 +477,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 +506,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 +680,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' );
@@ -1074,18 +1160,27 @@
if( data.backgroundPosition ) contentElement.style.backgroundPosition = data.backgroundPosition;
if( data.backgroundOpacity ) contentElement.style.opacity = data.backgroundOpacity;
- // If this slide has a background color, add a class that
+ // If this slide has a background color, we add a class that
// signals if it is light or dark. If the slide has no background
- // color, no class will be set
- var computedBackgroundStyle = window.getComputedStyle( element );
- if( computedBackgroundStyle && computedBackgroundStyle.backgroundColor ) {
- var rgb = colorToRgb( computedBackgroundStyle.backgroundColor );
+ // color, no class will be added
+ var contrastColor = data.backgroundColor;
+
+ // If no bg color was found, check the computed background
+ if( !contrastColor ) {
+ var computedBackgroundStyle = window.getComputedStyle( element );
+ if( computedBackgroundStyle && computedBackgroundStyle.backgroundColor ) {
+ contrastColor = computedBackgroundStyle.backgroundColor;
+ }
+ }
+
+ if( contrastColor ) {
+ var rgb = colorToRgb( contrastColor );
// Ignore fully transparent backgrounds. Some browsers return
// rgba(0,0,0,0) when reading the computed background color of
// an element with no background
if( rgb && rgb.a !== 0 ) {
- if( colorBrightness( computedBackgroundStyle.backgroundColor ) < 128 ) {
+ if( colorBrightness( contrastColor ) < 128 ) {
slide.classList.add( 'has-dark-background' );
}
else {
@@ -1208,6 +1303,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();
@@ -1255,6 +1362,14 @@
dom.slideNumber.style.display = slideNumberDisplay;
+ // Add the navigation mode to the DOM so we can adjust styling
+ if( config.navigationMode !== 'default' ) {
+ dom.wrapper.setAttribute( 'data-navigation-mode', config.navigationMode );
+ }
+ else {
+ dom.wrapper.removeAttribute( 'data-navigation-mode' );
+ }
+
sync();
}
@@ -1299,7 +1414,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 +1479,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 );
@@ -1669,11 +1784,19 @@
// Change the .stretch element height to 0 in order find the height of all
// the other elements
element.style.height = '0px';
+
+ // In Overview mode, the parent (.slide) height is set of 700px.
+ // Restore it temporarily to its natural height.
+ element.parentNode.style.height = 'auto';
+
newHeight = height - element.parentNode.offsetHeight;
// Restore the old height, just in case
element.style.height = oldHeight + 'px';
+ // Clear the parent (.slide) height. .removeProperty works in IE9+
+ element.parentNode.style.removeProperty('height');
+
return newHeight;
}
@@ -1962,6 +2085,16 @@
if( !config.disableLayout ) {
+ // On some mobile devices '100vh' is taller than the visible
+ // viewport which leads to part of the presentation being
+ // cut off. To work around this we define our own '--vh' custom
+ // property where 100x adds up to the correct height.
+ //
+ // https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
+ if( isMobileDevice ) {
+ document.documentElement.style.setProperty( '--vh', ( window.innerHeight * 0.01 ) + 'px' );
+ }
+
var size = getComputedSlideSize();
// Layout the contents of the slides
@@ -2443,6 +2576,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.
*/
@@ -2584,28 +2743,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();
@@ -2654,6 +2791,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,
@@ -2679,6 +2838,7 @@
updateParallax();
updateSlideNumber();
updateNotes();
+ updateFragments();
// Update the URL hash
writeURL();
@@ -2903,14 +3063,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 ) {
@@ -2918,14 +3075,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' );
+ } );
}
}
}
@@ -3663,13 +3817,6 @@
_appendParamToIframeSource( 'src', 'player.vimeo.com/', 'api=1' );
_appendParamToIframeSource( 'data-src', 'player.vimeo.com/', 'api=1' );
- // Always show media controls on mobile devices
- if( isMobileDevice ) {
- toArray( dom.slides.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
- el.controls = true;
- } );
- }
-
}
/**
@@ -3713,7 +3860,20 @@
// Mobile devices never fire a loaded event so instead
// of waiting, we initiate playback
else if( isMobileDevice ) {
- el.play();
+ var promise = el.play();
+
+ // If autoplay does not work, ensure that the controls are visible so
+ // that the viewer can start the media on their own
+ if( promise && typeof promise.catch === 'function' && el.controls === false ) {
+ promise.catch( function() {
+ el.controls = true;
+
+ // Once the video does start playing, hide the controls again
+ el.addEventListener( 'play', function() {
+ el.controls = false;
+ } );
+ } );
+ }
}
// If the media isn't loaded, wait before playing
else {
@@ -3988,10 +4148,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 {
@@ -4029,18 +4192,20 @@
*/
function writeURL( delay ) {
- if( config.history ) {
-
- // Make sure there's never more than one timeout running
- clearTimeout( writeURLTimeout );
+ // Make sure there's never more than one timeout running
+ clearTimeout( writeURLTimeout );
- // If a delay is specified, timeout this call
- if( typeof delay === 'number' ) {
- writeURLTimeout = setTimeout( writeURL, delay );
- }
- else if( currentSlide ) {
+ // If a delay is specified, timeout this call
+ if( typeof delay === 'number' ) {
+ writeURLTimeout = setTimeout( writeURL, delay );
+ }
+ else if( currentSlide ) {
+ if( config.history || !window.history ) {
window.location.hash = locationHash();
}
+ else if( config.hash ) {
+ window.history.replaceState(null, null, '#' + locationHash());
+ }
}
}
@@ -4108,6 +4273,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}
@@ -4300,6 +4484,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
@@ -4334,53 +4585,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 );
+ var changedFragments = updateFragments( index, fragments );
- 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' );
- }
-
- } );
-
- 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 );
}
@@ -4527,12 +4749,12 @@
// Reverse for RTL
if( config.rtl ) {
if( ( isOverview() || nextFragment() === false ) && availableRoutes().left ) {
- slide( indexh + 1 );
+ slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
}
}
// Normal navigation
else if( ( isOverview() || previousFragment() === false ) && availableRoutes().left ) {
- slide( indexh - 1 );
+ slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
}
}
@@ -4544,12 +4766,12 @@
// Reverse for RTL
if( config.rtl ) {
if( ( isOverview() || previousFragment() === false ) && availableRoutes().right ) {
- slide( indexh - 1 );
+ slide( indexh - 1, config.navigationMode === 'grid' ? indexv : undefined );
}
}
// Normal navigation
else if( ( isOverview() || nextFragment() === false ) && availableRoutes().right ) {
- slide( indexh + 1 );
+ slide( indexh + 1, config.navigationMode === 'grid' ? indexv : undefined );
}
}
@@ -4676,6 +4898,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
@@ -4702,20 +4940,31 @@
return true;
}
+ // Shorthand
+ var keyCode = event.keyCode;
+
// Remember if auto-sliding was paused so we can toggle it
var autoSlideWasPaused = autoSlidePaused;
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 ) && keyCode === 37;
+ var lastSlideShortcut = ( event.metaKey || event.ctrlKey ) && 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];
@@ -4730,7 +4979,7 @@
}
}
- if( isPaused() && resumeKeyCodes.indexOf( event.keyCode ) === -1 ) {
+ if( isPaused() && resumeKeyCodes.indexOf( keyCode ) === -1 ) {
return false;
}
@@ -4742,7 +4991,7 @@
for( key in config.keyboard ) {
// Check if this binding matches the pressed key
- if( parseInt( key, 10 ) === event.keyCode ) {
+ if( parseInt( key, 10 ) === keyCode ) {
var value = config.keyboard[ key ];
@@ -4769,7 +5018,7 @@
for( key in registeredKeyBindings ) {
// Check if this binding matches the pressed key
- if( parseInt( key, 10 ) === event.keyCode ) {
+ if( parseInt( key, 10 ) === keyCode ) {
var action = registeredKeyBindings[ key ].callback;
@@ -4793,35 +5042,92 @@
// Assume true and try to prove false
triggered = true;
- switch( event.keyCode ) {
- // p, page up
- case 80: case 33: navigatePrev(); break;
- // n, page down
- case 78: case 34: navigateNext(); break;
- // h, left
- case 72: case 37: navigateLeft(); break;
- // l, right
- case 76: case 39: navigateRight(); break;
- // k, up
- case 75: case 38: navigateUp(); break;
- // j, down
- case 74: case 40: navigateDown(); break;
- // home
- case 36: slide( 0 ); break;
- // end
- case 35: slide( Number.MAX_VALUE ); break;
- // space
- case 32: isOverview() ? deactivateOverview() : event.shiftKey ? navigatePrev() : navigateNext(); break;
- // return
- case 13: isOverview() ? deactivateOverview() : triggered = false; break;
- // two-spot, semicolon, b, v, period, Logitech presenter tools "black screen" button
- case 58: case 59: case 66: case 86: case 190: case 191: togglePause(); break;
- // f
- case 70: enterFullscreen(); break;
- // a
- case 65: if ( config.autoSlideStoppable ) toggleAutoSlide( autoSlideWasPaused ); break;
- default:
- triggered = false;
+ // P, PAGE UP
+ if( keyCode === 80 || keyCode === 33 ) {
+ navigatePrev();
+ }
+ // N, PAGE DOWN
+ else if( keyCode === 78 || keyCode === 34 ) {
+ navigateNext();
+ }
+ // H, LEFT
+ else if( keyCode === 72 || keyCode === 37 ) {
+ if( firstSlideShortcut ) {
+ slide( 0 );
+ }
+ else if( !isOverview() && config.navigationMode === 'linear' ) {
+ navigatePrev();
+ }
+ else {
+ navigateLeft();
+ }
+ }
+ // L, RIGHT
+ else if( keyCode === 76 || keyCode === 39 ) {
+ if( lastSlideShortcut ) {
+ slide( Number.MAX_VALUE );
+ }
+ else if( !isOverview() && config.navigationMode === 'linear' ) {
+ navigateNext();
+ }
+ else {
+ navigateRight();
+ }
+ }
+ // K, UP
+ else if( keyCode === 75 || keyCode === 38 ) {
+ if( !isOverview() && config.navigationMode === 'linear' ) {
+ navigatePrev();
+ }
+ else {
+ navigateUp();
+ }
+ }
+ // J, DOWN
+ else if( keyCode === 74 || keyCode === 40 ) {
+ if( !isOverview() && config.navigationMode === 'linear' ) {
+ navigateNext();
+ }
+ else {
+ navigateDown();
+ }
+ }
+ // HOME
+ else if( keyCode === 36 ) {
+ slide( 0 );
+ }
+ // END
+ else if( keyCode === 35 ) {
+ slide( Number.MAX_VALUE );
+ }
+ // SPACE
+ else if( keyCode === 32 ) {
+ if( isOverview() ) {
+ deactivateOverview();
+ }
+ if( event.shiftKey ) {
+ navigatePrev();
+ }
+ else {
+ navigateNext();
+ }
+ }
+ // TWO-SPOT, SEMICOLON, B, V, PERIOD, LOGITECH PRESENTER TOOLS "BLACK SCREEN" BUTTON
+ else if( keyCode === 58 || keyCode === 59 || keyCode === 66 || keyCode === 86 || keyCode === 190 || keyCode === 191 ) {
+ togglePause();
+ }
+ // F
+ else if( keyCode === 70 ) {
+ enterFullscreen();
+ }
+ // A
+ else if( keyCode === 65 ) {
+ if ( config.autoSlideStoppable ) {
+ toggleAutoSlide( autoSlideWasPaused );
+ }
+ }
+ else {
+ triggered = false;
}
}
@@ -4832,7 +5138,7 @@
event.preventDefault && event.preventDefault();
}
// ESC or O key
- else if ( ( event.keyCode === 27 || event.keyCode === 79 ) && features.transforms3d ) {
+ else if ( ( keyCode === 27 || keyCode === 79 ) && features.transforms3d ) {
if( dom.overlay ) {
closeOverlay();
}
@@ -4863,18 +5169,6 @@
touch.startY = event.touches[0].clientY;
touch.startCount = event.touches.length;
- // If there's two touches we need to memorize the distance
- // between those two points to detect pinching
- if( event.touches.length === 2 && config.overview ) {
- touch.startSpan = distanceBetween( {
- x: event.touches[1].clientX,
- y: event.touches[1].clientY
- }, {
- x: touch.startX,
- y: touch.startY
- } );
- }
-
}
/**
@@ -4893,37 +5187,8 @@
var currentX = event.touches[0].clientX;
var currentY = event.touches[0].clientY;
- // If the touch started with two points and still has
- // two active touches; test for the pinch gesture
- if( event.touches.length === 2 && touch.startCount === 2 && config.overview ) {
-
- // The current distance in pixels between the two touch points
- var currentSpan = distanceBetween( {
- x: event.touches[1].clientX,
- y: event.touches[1].clientY
- }, {
- x: touch.startX,
- y: touch.startY
- } );
-
- // If the span is larger than the desire amount we've got
- // ourselves a pinch
- if( Math.abs( touch.startSpan - currentSpan ) > touch.threshold ) {
- touch.captured = true;
-
- if( currentSpan < touch.startSpan ) {
- activateOverview();
- }
- else {
- deactivateOverview();
- }
- }
-
- event.preventDefault();
-
- }
// There was only one touch point, look for a swipe
- else if( event.touches.length === 1 && touch.startCount !== 2 ) {
+ if( event.touches.length === 1 && touch.startCount !== 2 ) {
var deltaX = currentX - touch.startX,
deltaY = currentY - touch.startY;
@@ -5073,8 +5338,8 @@
/**
* Event handler for navigation control buttons.
*/
- function onNavigateLeftClicked( event ) { event.preventDefault(); onUserInput(); navigateLeft(); }
- function onNavigateRightClicked( event ) { event.preventDefault(); onUserInput(); navigateRight(); }
+ function onNavigateLeftClicked( event ) { event.preventDefault(); onUserInput(); config.navigationMode === 'linear' ? navigatePrev() : navigateLeft(); }
+ function onNavigateRightClicked( event ) { event.preventDefault(); onUserInput(); config.navigationMode === 'linear' ? navigateNext() : navigateRight(); }
function onNavigateUpClicked( event ) { event.preventDefault(); onUserInput(); navigateUp(); }
function onNavigateDownClicked( event ) { event.preventDefault(); onUserInput(); navigateDown(); }
function onNavigatePrevClicked( event ) { event.preventDefault(); onUserInput(); navigatePrev(); }
@@ -5463,6 +5728,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,
@@ -5513,6 +5782,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 );
@@ -5554,12 +5828,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/package.json b/package.json
index cb8a711..35fcc51 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"grunt-retire": "^1.0.7",
"grunt-zip": "~0.17.1",
"mustache": "^2.3.0",
- "socket.io": "^1.7.3"
+ "socket.io": "^2.2.0"
},
"license": "MIT"
}
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/markdown/marked.js b/plugin/markdown/marked.js
index 555c1dc..481b9d8 100644
--- a/plugin/markdown/marked.js
+++ b/plugin/markdown/marked.js
@@ -1,6 +1,6 @@
/**
* marked - a markdown parser
- * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
- * https://github.com/chjj/marked
+ * Copyright (c) 2011-2018, Christopher Jeffrey. (MIT Licensed)
+ * https://github.com/markedjs/marked
*/
-(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]||""});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&(cap[1]==="pre"||cap[1]==="script"||cap[1]==="style"),text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="\n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};inline._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;inline._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^<a /i.test(cap[0])){this.inLink=true}else if(this.inLink&&/^<\/a>/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(cap[0]):escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.text(escape(this.smartypants(cap[0])));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){if(!this.options.mangle)return text;var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"<pre><code>"+(escaped?code:escape(code,true))+"\n</code></pre>"}return'<pre><code class="'+this.options.langPrefix+escape(lang,true)+'">'+(escaped?code:escape(code,true))+"\n</code></pre>\n"};Renderer.prototype.blockquote=function(quote){return"<blockquote>\n"+quote+"</blockquote>\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^\w]+/g,"-")+'">'+text+"</h"+level+">\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"</"+type+">\n"};Renderer.prototype.listitem=function(text){return"<li>"+text+"</li>\n"};Renderer.prototype.paragraph=function(text){return"<p>"+text+"</p>\n"};Renderer.prototype.table=function(header,body){return"<table>\n"+"<thead>\n"+header+"</thead>\n"+"<tbody>\n"+body+"</tbody>\n"+"</table>\n"};Renderer.prototype.tablerow=function(content){return"<tr>\n"+content+"</tr>\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"</"+type+">\n"};Renderer.prototype.strong=function(text){return"<strong>"+text+"</strong>"};Renderer.prototype.em=function(text){return"<em>"+text+"</em>"};Renderer.prototype.codespan=function(text){return"<code>"+text+"</code>"};Renderer.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"};Renderer.prototype.del=function(text){return"<del>"+text+"</del>"};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='<a href="'+href+'"';if(title){out+=' title="'+title+'"'}out+=">"+text+"</a>";return out};Renderer.prototype.image=function(href,title,text){var out='<img src="'+href+'" alt="'+text+'"';if(title){out+=' title="'+title+'"'}out+=this.options.xhtml?"/>":">";return out};Renderer.prototype.text=function(text){return text};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]})}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body)}case"blockquote_start":{var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body)}case"list_start":{var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered)}case"list_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body)}case"loose_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body)}case"html":{var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html)}case"paragraph":{return this.renderer.paragraph(this.inline.output(this.token.text))}case"text":{return this.renderer.paragraph(this.parseText())}}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(err){if(err){opt.highlight=highlight;return callback(err)}var out;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending)return done();for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return--pending||done()}return highlight(token.text,token.lang,function(err,code){if(err)return done(err);if(code==null||code===token.text){return--pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt)opt=merge({},marked.defaults,opt);return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="\nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"<p>An error occured:</p><pre>"+escape(e.message+"",true)+"</pre>"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,sanitizer:null,mangle:true,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file
+!function(e){"use strict";var k={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:f,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,nptable:f,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|<![A-Z][\\s\\S]*?>\\n*|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:f,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,text:/^[^\n]+/};function a(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||m.defaults,this.rules=k.normal,this.options.pedantic?this.rules=k.pedantic:this.options.gfm&&(this.options.tables?this.rules=k.tables:this.rules=k.gfm)}k._label=/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,k._title=/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/,k.def=i(k.def).replace("label",k._label).replace("title",k._title).getRegex(),k.bullet=/(?:[*+-]|\d{1,9}\.)/,k.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,k.item=i(k.item,"gm").replace(/bull/g,k.bullet).getRegex(),k.list=i(k.list).replace(/bull/g,k.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+k.def.source+")").getRegex(),k._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",k._comment=/<!--(?!-?>)[\s\S]*?-->/,k.html=i(k.html,"i").replace("comment",k._comment).replace("tag",k._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),k.paragraph=i(k.paragraph).replace("hr",k.hr).replace("heading",k.heading).replace("lheading",k.lheading).replace("tag",k._tag).getRegex(),k.blockquote=i(k.blockquote).replace("paragraph",k.paragraph).getRegex(),k.normal=d({},k),k.gfm=d({},k.normal,{fences:/^ {0,3}(`{3,}|~{3,})([^`\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),k.gfm.paragraph=i(k.paragraph).replace("(?!","(?!"+k.gfm.fences.source.replace("\\1","\\2")+"|"+k.list.source.replace("\\1","\\3")+"|").getRegex(),k.tables=d({},k.gfm,{nptable:/^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,table:/^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/}),k.pedantic=d({},k.normal,{html:i("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",k._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/}),a.rules=k,a.lex=function(e,t){return new a(t).lex(e)},a.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},a.prototype.token=function(e,t){var n,r,s,i,l,o,a,h,p,u,c,g,f,d,m,b;for(e=e.replace(/^ +$/gm,"");e;)if((s=this.rules.newline.exec(e))&&(e=e.substring(s[0].length),1<s[0].length&&this.tokens.push({type:"space"})),s=this.rules.code.exec(e))e=e.substring(s[0].length),s=s[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?s:y(s,"\n")});else if(s=this.rules.fences.exec(e))e=e.substring(s[0].length),this.tokens.push({type:"code",lang:s[2]?s[2].trim():s[2],text:s[3]||""});else if(s=this.rules.heading.exec(e))e=e.substring(s[0].length),this.tokens.push({type:"heading",depth:s[1].length,text:s[2]});else if(t&&(s=this.rules.nptable.exec(e))&&(o={type:"table",header:x(s[1].replace(/^ *| *\| *$/g,"")),align:s[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:s[3]?s[3].replace(/\n$/,"").split("\n"):[]}).header.length===o.align.length){for(e=e.substring(s[0].length),c=0;c<o.align.length;c++)/^ *-+: *$/.test(o.align[c])?o.align[c]="right":/^ *:-+: *$/.test(o.align[c])?o.align[c]="center":/^ *:-+ *$/.test(o.align[c])?o.align[c]="left":o.align[c]=null;for(c=0;c<o.cells.length;c++)o.cells[c]=x(o.cells[c],o.header.length);this.tokens.push(o)}else if(s=this.rules.hr.exec(e))e=e.substring(s[0].length),this.tokens.push({type:"hr"});else if(s=this.rules.blockquote.exec(e))e=e.substring(s[0].length),this.tokens.push({type:"blockquote_start"}),s=s[0].replace(/^ *> ?/gm,""),this.token(s,t),this.tokens.push({type:"blockquote_end"});else if(s=this.rules.list.exec(e)){for(e=e.substring(s[0].length),a={type:"list_start",ordered:d=1<(i=s[2]).length,start:d?+i:"",loose:!1},this.tokens.push(a),n=!(h=[]),f=(s=s[0].match(this.rules.item)).length,c=0;c<f;c++)u=(o=s[c]).length,~(o=o.replace(/^ *([*+-]|\d+\.) */,"")).indexOf("\n ")&&(u-=o.length,o=this.options.pedantic?o.replace(/^ {1,4}/gm,""):o.replace(new RegExp("^ {1,"+u+"}","gm"),"")),c!==f-1&&(l=k.bullet.exec(s[c+1])[0],(1<i.length?1===l.length:1<l.length||this.options.smartLists&&l!==i)&&(e=s.slice(c+1).join("\n")+e,c=f-1)),r=n||/\n\n(?!\s*$)/.test(o),c!==f-1&&(n="\n"===o.charAt(o.length-1),r||(r=n)),r&&(a.loose=!0),b=void 0,(m=/^\[[ xX]\] /.test(o))&&(b=" "!==o[1],o=o.replace(/^\[[ xX]\] +/,"")),p={type:"list_item_start",task:m,checked:b,loose:r},h.push(p),this.tokens.push(p),this.token(o,!1),this.tokens.push({type:"list_item_end"});if(a.loose)for(f=h.length,c=0;c<f;c++)h[c].loose=!0;this.tokens.push({type:"list_end"})}else if(s=this.rules.html.exec(e))e=e.substring(s[0].length),this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&("pre"===s[1]||"script"===s[1]||"style"===s[1]),text:s[0]});else if(t&&(s=this.rules.def.exec(e)))e=e.substring(s[0].length),s[3]&&(s[3]=s[3].substring(1,s[3].length-1)),g=s[1].toLowerCase().replace(/\s+/g," "),this.tokens.links[g]||(this.tokens.links[g]={href:s[2],title:s[3]});else if(t&&(s=this.rules.table.exec(e))&&(o={type:"table",header:x(s[1].replace(/^ *| *\| *$/g,"")),align:s[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:s[3]?s[3].replace(/(?: *\| *)?\n$/,"").split("\n"):[]}).header.length===o.align.length){for(e=e.substring(s[0].length),c=0;c<o.align.length;c++)/^ *-+: *$/.test(o.align[c])?o.align[c]="right":/^ *:-+: *$/.test(o.align[c])?o.align[c]="center":/^ *:-+ *$/.test(o.align[c])?o.align[c]="left":o.align[c]=null;for(c=0;c<o.cells.length;c++)o.cells[c]=x(o.cells[c].replace(/^ *\| *| *\| *$/g,""),o.header.length);this.tokens.push(o)}else if(s=this.rules.lheading.exec(e))e=e.substring(s[0].length),this.tokens.push({type:"heading",depth:"="===s[2]?1:2,text:s[1]});else if(t&&(s=this.rules.paragraph.exec(e)))e=e.substring(s[0].length),this.tokens.push({type:"paragraph",text:"\n"===s[1].charAt(s[1].length-1)?s[1].slice(0,-1):s[1]});else if(s=this.rules.text.exec(e))e=e.substring(s[0].length),this.tokens.push({type:"text",text:s[0]});else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0));return this.tokens};var n={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:f,tag:"^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",link:/^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:f,text:/^(`+|[^`])[\s\S]*?(?=[\\<!\[`*]|\b_| {2,}\n|$)/};function h(e,t){if(this.options=t||m.defaults,this.links=e,this.rules=n.normal,this.renderer=this.options.renderer||new r,this.renderer.options=this.options,!this.links)throw new Error("Tokens array requires a `links` property.");this.options.pedantic?this.rules=n.pedantic:this.options.gfm&&(this.options.breaks?this.rules=n.breaks:this.rules=n.gfm)}function r(e){this.options=e||m.defaults}function s(){}function p(e){this.tokens=[],this.token=null,this.options=e||m.defaults,this.options.renderer=this.options.renderer||new r,this.renderer=this.options.renderer,this.renderer.options=this.options,this.slugger=new t}function t(){this.seen={}}function u(e,t){if(t){if(u.escapeTest.test(e))return e.replace(u.escapeReplace,function(e){return u.replacements[e]})}else if(u.escapeTestNoEncode.test(e))return e.replace(u.escapeReplaceNoEncode,function(e){return u.replacements[e]});return e}function c(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function i(n,e){return n=n.source||n,e=e||"",{replace:function(e,t){return t=(t=t.source||t).replace(/(^|[^\[])\^/g,"$1"),n=n.replace(e,t),this},getRegex:function(){return new RegExp(n,e)}}}function l(e,t,n){if(e){try{var r=decodeURIComponent(c(n)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return null}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:")||0===r.indexOf("data:"))return null}t&&!g.test(n)&&(n=function(e,t){o[" "+e]||(/^[^:]+:\/*[^/]*$/.test(e)?o[" "+e]=e+"/":o[" "+e]=y(e,"/",!0));return e=o[" "+e],"//"===t.slice(0,2)?e.replace(/:[\s\S]*/,":")+t:"/"===t.charAt(0)?e.replace(/(:\/*[^/]*)[\s\S]*/,"$1")+t:e+t}(t,n));try{n=encodeURI(n).replace(/%25/g,"%")}catch(e){return null}return n}n._punctuation="!\"#$%&'()*+,\\-./:;<=>?@\\[^_{|}~",n.em=i(n.em).replace(/punctuation/g,n._punctuation).getRegex(),n._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,n._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,n._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,n.autolink=i(n.autolink).replace("scheme",n._scheme).replace("email",n._email).getRegex(),n._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,n.tag=i(n.tag).replace("comment",k._comment).replace("attribute",n._attribute).getRegex(),n._label=/(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/,n._href=/\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)/,n._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,n.link=i(n.link).replace("label",n._label).replace("href",n._href).replace("title",n._title).getRegex(),n.reflink=i(n.reflink).replace("label",n._label).getRegex(),n.normal=d({},n),n.pedantic=d({},n.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:i(/^!?\[(label)\]\((.*?)\)/).replace("label",n._label).getRegex(),reflink:i(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",n._label).getRegex()}),n.gfm=d({},n.normal,{escape:i(n.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:i(n.text).replace("]|","~]|").replace("|$","|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\|}~-]+@|$").getRegex()}),n.gfm.url=i(n.gfm.url,"i").replace("email",n.gfm._extended_email).getRegex(),n.breaks=d({},n.gfm,{br:i(n.br).replace("{2,}","*").getRegex(),text:i(n.gfm.text).replace("{2,}","*").getRegex()}),h.rules=n,h.output=function(e,t,n){return new h(t,n).output(e)},h.prototype.output=function(e){for(var t,n,r,s,i,l,o="";e;)if(i=this.rules.escape.exec(e))e=e.substring(i[0].length),o+=u(i[1]);else if(i=this.rules.tag.exec(e))!this.inLink&&/^<a /i.test(i[0])?this.inLink=!0:this.inLink&&/^<\/a>/i.test(i[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(i[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(i[0])&&(this.inRawBlock=!1),e=e.substring(i[0].length),o+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):u(i[0]):i[0];else if(i=this.rules.link.exec(e))e=e.substring(i[0].length),this.inLink=!0,r=i[2],this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r))?(r=t[1],s=t[3]):s="":s=i[3]?i[3].slice(1,-1):"",r=r.trim().replace(/^<([\s\S]*)>$/,"$1"),o+=this.outputLink(i,{href:h.escapes(r),title:h.escapes(s)}),this.inLink=!1;else if((i=this.rules.reflink.exec(e))||(i=this.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){o+=i[0].charAt(0),e=i[0].substring(1)+e;continue}this.inLink=!0,o+=this.outputLink(i,t),this.inLink=!1}else if(i=this.rules.strong.exec(e))e=e.substring(i[0].length),o+=this.renderer.strong(this.output(i[4]||i[3]||i[2]||i[1]));else if(i=this.rules.em.exec(e))e=e.substring(i[0].length),o+=this.renderer.em(this.output(i[6]||i[5]||i[4]||i[3]||i[2]||i[1]));else if(i=this.rules.code.exec(e))e=e.substring(i[0].length),o+=this.renderer.codespan(u(i[2].trim(),!0));else if(i=this.rules.br.exec(e))e=e.substring(i[0].length),o+=this.renderer.br();else if(i=this.rules.del.exec(e))e=e.substring(i[0].length),o+=this.renderer.del(this.output(i[1]));else if(i=this.rules.autolink.exec(e))e=e.substring(i[0].length),r="@"===i[2]?"mailto:"+(n=u(this.mangle(i[1]))):n=u(i[1]),o+=this.renderer.link(r,null,n);else if(this.inLink||!(i=this.rules.url.exec(e))){if(i=this.rules.text.exec(e))e=e.substring(i[0].length),this.inRawBlock?o+=this.renderer.text(i[0]):o+=this.renderer.text(u(this.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else{if("@"===i[2])r="mailto:"+(n=u(i[0]));else{for(;l=i[0],i[0]=this.rules._backpedal.exec(i[0])[0],l!==i[0];);n=u(i[0]),r="www."===i[1]?"http://"+n:n}e=e.substring(i[0].length),o+=this.renderer.link(r,null,n)}return o},h.escapes=function(e){return e?e.replace(h.rules._escapes,"$1"):e},h.prototype.outputLink=function(e,t){var n=t.href,r=t.title?u(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,u(e[1]))},h.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},h.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,s=0;s<r;s++)t=e.charCodeAt(s),.5<Math.random()&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},r.prototype.code=function(e,t,n){var r=(t||"").match(/\S*/)[0];if(this.options.highlight){var s=this.options.highlight(e,r);null!=s&&s!==e&&(n=!0,e=s)}return r?'<pre><code class="'+this.options.langPrefix+u(r,!0)+'">'+(n?e:u(e,!0))+"</code></pre>\n":"<pre><code>"+(n?e:u(e,!0))+"</code></pre>"},r.prototype.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},r.prototype.html=function(e){return e},r.prototype.heading=function(e,t,n,r){return this.options.headerIds?"<h"+t+' id="'+this.options.headerPrefix+r.slug(n)+'">'+e+"</h"+t+">\n":"<h"+t+">"+e+"</h"+t+">\n"},r.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},r.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"</"+r+">\n"},r.prototype.listitem=function(e){return"<li>"+e+"</li>\n"},r.prototype.checkbox=function(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox"'+(this.options.xhtml?" /":"")+"> "},r.prototype.paragraph=function(e){return"<p>"+e+"</p>\n"},r.prototype.table=function(e,t){return t&&(t="<tbody>"+t+"</tbody>"),"<table>\n<thead>\n"+e+"</thead>\n"+t+"</table>\n"},r.prototype.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},r.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"</"+n+">\n"},r.prototype.strong=function(e){return"<strong>"+e+"</strong>"},r.prototype.em=function(e){return"<em>"+e+"</em>"},r.prototype.codespan=function(e){return"<code>"+e+"</code>"},r.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"},r.prototype.del=function(e){return"<del>"+e+"</del>"},r.prototype.link=function(e,t,n){if(null===(e=l(this.options.sanitize,this.options.baseUrl,e)))return n;var r='<a href="'+u(e)+'"';return t&&(r+=' title="'+t+'"'),r+=">"+n+"</a>"},r.prototype.image=function(e,t,n){if(null===(e=l(this.options.sanitize,this.options.baseUrl,e)))return n;var r='<img src="'+e+'" alt="'+n+'"';return t&&(r+=' title="'+t+'"'),r+=this.options.xhtml?"/>":">"},r.prototype.text=function(e){return e},s.prototype.strong=s.prototype.em=s.prototype.codespan=s.prototype.del=s.prototype.text=function(e){return e},s.prototype.link=s.prototype.image=function(e,t,n){return""+n},s.prototype.br=function(){return""},p.parse=function(e,t){return new p(t).parse(e)},p.prototype.parse=function(e){this.inline=new h(e.links,this.options),this.inlineText=new h(e.links,d({},this.options,{renderer:new s})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},p.prototype.next=function(){return this.token=this.tokens.pop()},p.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},p.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},p.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,c(this.inlineText.output(this.token.text)),this.slugger);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,s="",i="";for(n="",e=0;e<this.token.header.length;e++)n+=this.renderer.tablecell(this.inline.output(this.token.header[e]),{header:!0,align:this.token.align[e]});for(s+=this.renderer.tablerow(n),e=0;e<this.token.cells.length;e++){for(t=this.token.cells[e],n="",r=0;r<t.length;r++)n+=this.renderer.tablecell(this.inline.output(t[r]),{header:!1,align:this.token.align[r]});i+=this.renderer.tablerow(n)}return this.renderer.table(s,i);case"blockquote_start":for(i="";"blockquote_end"!==this.next().type;)i+=this.tok();return this.renderer.blockquote(i);case"list_start":i="";for(var l=this.token.ordered,o=this.token.start;"list_end"!==this.next().type;)i+=this.tok();return this.renderer.list(i,l,o);case"list_item_start":i="";var a=this.token.loose;for(this.token.task&&(i+=this.renderer.checkbox(this.token.checked));"list_item_end"!==this.next().type;)i+=a||"text"!==this.token.type?this.tok():this.parseText();return this.renderer.listitem(i);case"html":return this.renderer.html(this.token.text);case"paragraph":return this.renderer.paragraph(this.inline.output(this.token.text));case"text":return this.renderer.paragraph(this.parseText());default:var h='Token with "'+this.token.type+'" type was not found.';if(!this.options.silent)throw new Error(h);console.log(h)}},t.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},u.escapeTest=/[&<>"']/,u.escapeReplace=/[&<>"']/g,u.replacements={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},u.escapeTestNoEncode=/[<>"']|&(?!#?\w+;)/,u.escapeReplaceNoEncode=/[<>"']|&(?!#?\w+;)/g;var o={},g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function f(){}function d(e){for(var t,n,r=1;r<arguments.length;r++)for(n in t=arguments[r])Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e}function x(e,t){var n=e.replace(/\|/g,function(e,t,n){for(var r=!1,s=t;0<=--s&&"\\"===n[s];)r=!r;return r?"|":" |"}).split(/ \|/),r=0;if(n.length>t)n.splice(t);else for(;n.length<t;)n.push("");for(;r<n.length;r++)n[r]=n[r].trim().replace(/\\\|/g,"|");return n}function y(e,t,n){if(0===e.length)return"";for(var r=0;r<e.length;){var s=e.charAt(e.length-r-1);if(s!==t||n){if(s===t||!n)break;r++}else r++}return e.substr(0,e.length-r)}function m(e,n,r){if(null==e)throw new Error("marked(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");if(r||"function"==typeof n){r||(r=n,n=null);var s,i,l=(n=d({},m.defaults,n||{})).highlight,t=0;try{s=a.lex(e,n)}catch(e){return r(e)}i=s.length;var o=function(t){if(t)return n.highlight=l,r(t);var e;try{e=p.parse(s,n)}catch(e){t=e}return n.highlight=l,t?r(t):r(null,e)};if(!l||l.length<3)return o();if(delete n.highlight,!i)return o();for(;t<s.length;t++)!function(n){"code"!==n.type?--i||o():l(n.text,n.lang,function(e,t){return e?o(e):null==t||t===n.text?--i||o():(n.text=t,n.escaped=!0,void(--i||o()))})}(s[t])}else try{return n&&(n=d({},m.defaults,n)),p.parse(a.lex(e,n),n)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",(n||m.defaults).silent)return"<p>An error occurred:</p><pre>"+u(e.message+"",!0)+"</pre>";throw e}}f.exec=f,m.options=m.setOptions=function(e){return d(m.defaults,e),m},m.getDefaults=function(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:new r,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tables:!0,xhtml:!1}},m.defaults=m.getDefaults(),m.Parser=p,m.parser=p.parse,m.Renderer=r,m.TextRenderer=s,m.Lexer=a,m.lexer=a.lex,m.InlineLexer=h,m.inlineLexer=h.output,m.Slugger=t,m.parse=m,"undefined"!=typeof module&&"object"==typeof exports?module.exports=m:"function"==typeof define&&define.amd?define(function(){return m}):e.marked=m}(this||("undefined"!=typeof window?window:global)); \ No newline at end of file
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
new file mode 100644
index 0000000..38747a5
--- /dev/null
+++ b/test/examples/assets/beeping.wav
Binary files differ
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 &lt; +\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 &lt; +\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-grid-navigation.html b/test/test-grid-navigation.html
new file mode 100644
index 0000000..21e7636
--- /dev/null
+++ b/test/test-grid-navigation.html
@@ -0,0 +1,74 @@
+<!doctype html>
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+
+ <title>reveal.js - Test Grid</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>0</section>
+ <section>
+ <section>1.1</section>
+ <section>1.2</section>
+ <section>1.3</section>
+ <section>1.4</section>
+ </section>
+ <section>
+ <section>2.1</section>
+ <section>2.2</section>
+ <section>2.3</section>
+ <section>2.4</section>
+ </section>
+
+ </div>
+
+ </div>
+
+ <script src="../js/reveal.js"></script>
+ <script src="qunit-2.5.0.js"></script>
+
+ <script>
+ Reveal.addEventListener( 'ready', function() {
+
+ QUnit.module( 'Grid Navigation' );
+
+ QUnit.test( 'Disabled', function( assert ) {
+ Reveal.right();
+ Reveal.down();
+ Reveal.down();
+ assert.deepEqual( Reveal.getIndices(), { h: 1, v: 2, f: undefined }, 'Correct starting point' );
+ Reveal.right();
+ assert.deepEqual( Reveal.getIndices(), { h: 2, v: 0, f: undefined }, 'Moves to top when going to adjacent stack' );
+ });
+
+ QUnit.test( 'Enabled', function( assert ) {
+ Reveal.configure({ navigationMode: 'grid' });
+ Reveal.slide( 0, 0 );
+ Reveal.right();
+ Reveal.down();
+ Reveal.down();
+ assert.deepEqual( Reveal.getIndices(), { h: 1, v: 2, f: undefined }, 'Correct starting point' );
+ Reveal.right();
+ assert.deepEqual( Reveal.getIndices(), { h: 2, v: 2, f: undefined }, 'Remains at same vertical index when going to adjacent stack' );
+ });
+
+ } );
+
+ Reveal.initialize();
+ </script>
+
+ </body>
+</html>
diff --git a/test/test-markdown-element-attributes.html b/test/test-markdown-element-attributes.html
index 4a09272..741131f 100644
--- a/test/test-markdown-element-attributes.html
+++ b/test/test-markdown-element-attributes.html
@@ -66,8 +66,7 @@
Test
- ![Example Picture](examples/assets/image2.png)
- <!-- {_class="reveal stretch"} -->
+ ![Example Picture](examples/assets/image2.png) <!-- {_class="reveal stretch"} -->
</script>
</section>
@@ -122,7 +121,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 ) {