aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gruntfile.js11
-rw-r--r--LICENSE2
-rw-r--r--README.md70
-rw-r--r--css/print/pdf.css7
-rw-r--r--css/reveal.css34
-rw-r--r--css/reveal.scss31
-rw-r--r--index.html7
-rw-r--r--js/reveal.js270
-rw-r--r--package.json15
-rwxr-xr-xplugin/markdown/markdown.js3
-rwxr-xr-xplugin/math/math.js2
-rw-r--r--plugin/notes/notes.js29
-rw-r--r--plugin/print-pdf/print-pdf.js50
-rw-r--r--test/examples/math.html2
14 files changed, 375 insertions, 158 deletions
diff --git a/Gruntfile.js b/Gruntfile.js
index 96a4f52..aa04b68 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -15,7 +15,7 @@ module.exports = function(grunt) {
' * http://lab.hakim.se/reveal-js\n' +
' * MIT licensed\n' +
' *\n' +
- ' * Copyright (C) 2016 Hakim El Hattab, http://hakim.se\n' +
+ ' * Copyright (C) 2017 Hakim El Hattab, http://hakim.se\n' +
' */'
},
@@ -44,7 +44,7 @@ module.exports = function(grunt) {
{
expand: true,
cwd: 'css/theme/source',
- src: ['*.scss'],
+ src: ['*.sass', '*.scss'],
dest: 'css/theme',
ext: '.css'
}
@@ -122,7 +122,12 @@ module.exports = function(grunt) {
tasks: 'js'
},
theme: {
- files: [ 'css/theme/source/*.scss', 'css/theme/template/*.scss' ],
+ files: [
+ 'css/theme/source/*.sass',
+ 'css/theme/source/*.scss',
+ 'css/theme/template/*.sass',
+ 'css/theme/template/*.scss'
+ ],
tasks: 'css-themes'
},
css: {
diff --git a/LICENSE b/LICENSE
index 924cd89..c3e6e5f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (C) 2016 Hakim El Hattab, http://hakim.se, and reveal.js contributors
+Copyright (C) 2017 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 76ca321..2991ed1 100644
--- a/README.md
+++ b/README.md
@@ -105,17 +105,17 @@ The presentation markup hierarchy needs to be `.reveal > .slides > section` wher
### Markdown
-It's possible to write your slides using Markdown. To enable Markdown, add the `data-markdown` attribute to your `<section>` elements and wrap the contents in a `<script type="text/template">` like the example below.
+It's possible to write your slides using Markdown. To enable Markdown, add the `data-markdown` attribute to your `<section>` elements and wrap the contents in a `<textarea data-template>` like the example below.
This is based on [data-markdown](https://gist.github.com/1343518) from [Paul Irish](https://github.com/paulirish) modified to use [marked](https://github.com/chjj/marked) to support [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown). Sensitive to indentation (avoid mixing tabs and spaces) and line breaks (avoid consecutive breaks).
```html
<section data-markdown>
- <script type="text/template">
+ <textarea data-template>
## Page title
A paragraph with some text and a [link](http://hakim.se).
- </script>
+ </textarea>
</section>
```
@@ -228,6 +228,12 @@ Reveal.initialize({
// Flags if speaker notes should be visible to all viewers
showNotes: false,
+ // Global override for autolaying embedded media (video/audio/iframe)
+ // - null: Media will only autoplay if data-autoplay is present
+ // - true: All media will autoplay, regardless of individual setting
+ // - false: No media will autoplay, regardless of individual setting
+ autoPlayMedia: null,
+
// Number of milliseconds between automatically proceeding to the
// next slide, disabled when set to 0, this value can be overwritten
// by using a data-autoslide attribute on your slides
@@ -270,7 +276,10 @@ Reveal.initialize({
// - Calculated automatically unless specified
// - Set to 0 to disable movement along an axis
parallaxBackgroundHorizontal: null,
- parallaxBackgroundVertical: null
+ parallaxBackgroundVertical: null,
+
+ // The display mode that will be used to show slides
+ display: 'block'
});
```
@@ -463,14 +472,15 @@ Reveal.nextFragment();
// Randomize the order of slides
Reveal.shuffle();
-// Shows a help overlay with keyboard shortcuts
-Reveal.showHelp();
-
// Toggle presentation states, optionally pass true/false to force on/off
Reveal.toggleOverview();
Reveal.togglePause();
Reveal.toggleAutoSlide();
+// Shows a help overlay with keyboard shortcuts, optionally pass true/false
+// to force on/off
+Reveal.toggleHelp();
+
// Change a config value at runtime
Reveal.configure({ controls: true });
@@ -578,6 +588,7 @@ Automatically plays a full size video behind the slide.
| data-background-video | | A single video source, or a comma separated list of video sources. |
| data-background-video-loop | false | Flags if the video should play repeatedly. |
| data-background-video-muted | false | Flags if the audio should be muted. |
+| data-background-size | cover | Use `cover` for full screen and some cropping or `contain` for letterboxing. |
```html
<section data-background-video="https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.webm" data-background-video-loop data-background-video-muted>
@@ -749,7 +760,7 @@ By default, Reveal is configured with [highlight.js](https://highlightjs.org/) f
```
### Slide number
-If you would like to display the page number of the current slide you can do so using the ```slideNumber``` configuration value.
+If you would like to display the page number of the current slide you can do so using the ```slideNumber``` and ```showSlideNumber``` configuration values.
```javascript
// Shows the slide number using default formatting
@@ -762,6 +773,12 @@ Reveal.configure({ slideNumber: true });
// "c/t": flattened slide number / total slides
Reveal.configure({ slideNumber: 'c/t' });
+// Control which views the slide number displays on using the "showSlideNumber" value:
+// "all": show on all views (default)
+// "speaker": only show slide numbers on speaker notes view
+// "print": only show slide numbers when printing to PDF
+Reveal.configure({ showSlideNumber: 'speaker' });
+
```
@@ -778,20 +795,26 @@ Reveal.addEventListener( 'overviewhidden', function( event ) { /* ... */ } );
Reveal.toggleOverview();
```
+
### Fullscreen mode
Just press »F« on your keyboard to show your presentation in fullscreen mode. Press the »ESC« key to exit fullscreen mode.
### Embedded media
-Embedded HTML5 `<video>`/`<audio>` and YouTube iframes are automatically paused when you navigate away from a slide. This can be disabled by decorating your element with a `data-ignore` attribute.
-
Add `data-autoplay` to your media element if you want it to automatically start playing when the slide is shown:
```html
<video data-autoplay src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
```
-Additionally the framework automatically pushes two [post messages](https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage) to all iframes, ```slide:start``` when the slide containing the iframe is made visible and ```slide:stop``` when it is hidden.
+If you want to enable or disable autoplay globally, for all embedded media, you can use the `autoPlayMedia` configuration option. If you set this to `true` ALL media will autoplay regardless of individual `data-autoplay` attributes. If you initialize with `autoPlayMedia: false` NO media will autoplay.
+
+Note that embedded HTML5 `<video>`/`<audio>` and YouTube/Vimeo iframes are automatically paused when you navigate away from a slide. This can be disabled by decorating your element with a `data-ignore` attribute.
+
+
+### Embedded iframes
+
+reveal.js automatically pushes two [post messages](https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage) to embedded iframes. ```slide:start``` when the slide containing the iframe is made visible and ```slide:stop``` when it is hidden.
### Stretching elements
@@ -865,12 +888,13 @@ To enable the PDF print capability in your presentation, the special print style
### Instructions
1. Open your presentation with `print-pdf` included in the query string i.e. http://localhost:8000/?print-pdf. You can test this with [lab.hakim.se/reveal-js?print-pdf](http://lab.hakim.se/reveal-js?print-pdf).
-2. Open the in-browser print dialog (CTRL/CMD+P).
-3. Change the **Destination** setting to **Save as PDF**.
-4. Change the **Layout** to **Landscape**.
-5. Change the **Margins** to **None**.
-6. Enable the **Background graphics** option.
-7. Click **Save**.
+ * If you want to include [speaker notes](#speaker-notes) in your export, you can append `showNotes=true` to the query string: http://localhost:8000/?print-pdf&showNotes=true
+1. Open the in-browser print dialog (CTRL/CMD+P).
+1. Change the **Destination** setting to **Save as PDF**.
+1. Change the **Layout** to **Landscape**.
+1. Change the **Margins** to **None**.
+1. Enable the **Background graphics** option.
+1. Click **Save**.
![Chrome Print Settings](https://s3.amazonaws.com/hakim-static/reveal-js/pdf-print-settings-2.png)
@@ -939,7 +963,7 @@ This will only display in the notes window.
Notes are only visible to the speaker inside of the speaker view. If you wish to share your notes with others you can initialize reveal.js with the `showNotes` config value set to `true`. Notes will appear along the bottom of the presentations.
-When `showNotes` is enabled notes are also included when you [export to PDF](https://github.com/hakimel/reveal.js#pdf-export). By default, notes are printed in a semi-transparent box on top of slide. If you'd rather print them on a separate page after the slide, set `showNotes: "separate-page"`.
+When `showNotes` is enabled notes are also included when you [export to PDF](https://github.com/hakimel/reveal.js#pdf-export). By default, notes are printed in a semi-transparent box on top of the slide. If you'd rather print them on a separate page after the slide, set `showNotes: "separate-page"`.
## Server Side Speaker Notes
@@ -1041,11 +1065,13 @@ Server that receives the slideChanged events from the master presentation and br
1. ```npm install```
2. ```node plugin/multiplex```
-Or you use the socket.io server at [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/).
+Or you can use the socket.io server at [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/).
You'll need to generate a unique secret and token pair for your master and client presentations. To do so, visit ```http://example.com/token```, where ```http://example.com``` is the location of your socket.io server. Or if you're going to use the socket.io server at [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/), visit [https://reveal-js-multiplex-ccjbegmaii.now.sh/token](https://reveal-js-multiplex-ccjbegmaii.now.sh/token).
-You are very welcome to point your presentations at the Socket.io server running at [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/), but availability and stability are not guaranteed. For anything mission critical I recommend you run your own server. It is simple to deploy to nodejitsu, heroku, your own environment, etc.
+You are very welcome to point your presentations at the Socket.io server running at [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/), but availability and stability are not guaranteed.
+
+For anything mission critical I recommend you run your own server. The easiest way to do this is by installing [now](https://zeit.co/now). With that installed, deploying your own Multiplex server is as easy running the following command from the reveal.js folder: `now plugin/multiplex`.
##### socket.io server as file static server
@@ -1111,7 +1137,7 @@ Reveal.initialize({
// other options ...
math: {
- mathjax: 'https://cdn.mathjax.org/mathjax/latest/MathJax.js',
+ 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
},
@@ -1182,4 +1208,4 @@ Some reveal.js features, like external Markdown and speaker notes, require that
MIT licensed
-Copyright (C) 2016 Hakim El Hattab, http://hakim.se
+Copyright (C) 2017 Hakim El Hattab, http://hakim.se
diff --git a/css/print/pdf.css b/css/print/pdf.css
index 8c3234c..20c646a 100644
--- a/css/print/pdf.css
+++ b/css/print/pdf.css
@@ -87,14 +87,14 @@ ul, ol, div, p {
position: relative;
overflow: hidden;
z-index: 1;
+
+ page-break-after: always;
}
.reveal .slides section {
- page-break-after: always !important;
-
visibility: visible !important;
display: block !important;
- position: relative !important;
+ position: absolute !important;
margin: 0 !important;
padding: 0 !important;
@@ -115,6 +115,7 @@ ul, ol, div, p {
}
.reveal section.stack {
+ position: relative !important;
margin: 0 !important;
padding: 0 !important;
page-break-after: avoid !important;
diff --git a/css/reveal.css b/css/reveal.css
index 430dcde..f675977 100644
--- a/css/reveal.css
+++ b/css/reveal.css
@@ -3,7 +3,7 @@
* http://lab.hakim.se/reveal-js
* MIT licensed
*
- * Copyright (C) 2016 Hakim El Hattab, http://hakim.se
+ * Copyright (C) 2017 Hakim El Hattab, http://hakim.se
*/
/*********************************************
* RESET STYLES
@@ -323,6 +323,7 @@ body {
bottom: 0;
left: 0;
margin: auto;
+ pointer-events: none;
overflow: visible;
z-index: 1;
text-align: center;
@@ -340,6 +341,7 @@ body {
position: absolute;
width: 100%;
padding: 20px 0px;
+ pointer-events: auto;
z-index: 10;
-webkit-transform-style: flat;
transform-style: flat;
@@ -374,6 +376,10 @@ body {
z-index: 11;
opacity: 1; }
+.reveal .slides > section:empty,
+.reveal .slides > section > section:empty {
+ pointer-events: none; }
+
.reveal.center,
.reveal.center .slides,
.reveal.center .slides section {
@@ -589,6 +595,10 @@ body {
/*********************************************
* CUBE TRANSITION
+ *
+ * WARNING:
+ * this is deprecated and will be removed in a
+ * future version.
*********************************************/
.reveal.cube .slides {
-webkit-perspective: 1300px;
@@ -664,6 +674,10 @@ body {
/*********************************************
* PAGE TRANSITION
+ *
+ * WARNING:
+ * this is deprecated and will be removed in a
+ * future version.
*********************************************/
.reveal.page .slides {
-webkit-perspective-origin: 0% 50%;
@@ -839,6 +853,7 @@ body {
height: 100%;
opacity: 0;
visibility: hidden;
+ overflow: hidden;
background-color: transparent;
background-position: 50% 50%;
background-repeat: no-repeat;
@@ -851,7 +866,8 @@ body {
.reveal .slide-background.present {
opacity: 1;
- visibility: visible; }
+ visibility: visible;
+ z-index: 2; }
.print-pdf .reveal .slide-background {
opacity: 1 !important;
@@ -865,7 +881,13 @@ body {
max-width: none;
max-height: none;
top: 0;
- left: 0; }
+ left: 0;
+ -o-object-fit: cover;
+ object-fit: cover; }
+
+.reveal .slide-background[data-background-size="contain"] video {
+ -o-object-fit: contain;
+ object-fit: contain; }
/* Immediate transition style */
.reveal[data-background-transition=none] > .backgrounds .slide-background,
@@ -1037,6 +1059,8 @@ body {
visibility: visible;
outline: 10px solid rgba(150, 150, 150, 0.1);
outline-offset: 10px; }
+ .reveal.overview .backgrounds .slide-background.stack {
+ overflow: visible; }
.reveal.overview .slides section,
.reveal.overview-deactivating .slides section {
@@ -1048,10 +1072,6 @@ body {
-webkit-transition: none;
transition: none; }
-.reveal.overview-animated .slides {
- -webkit-transition: -webkit-transform 0.4s ease;
- transition: transform 0.4s ease; }
-
/*********************************************
* RTL SUPPORT
*********************************************/
diff --git a/css/reveal.scss b/css/reveal.scss
index 22fb3fe..fba248e 100644
--- a/css/reveal.scss
+++ b/css/reveal.scss
@@ -3,7 +3,7 @@
* http://lab.hakim.se/reveal-js
* MIT licensed
*
- * Copyright (C) 2016 Hakim El Hattab, http://hakim.se
+ * Copyright (C) 2017 Hakim El Hattab, http://hakim.se
*/
@@ -388,6 +388,7 @@ body {
bottom: 0;
left: 0;
margin: auto;
+ pointer-events: none;
overflow: visible;
z-index: 1;
@@ -406,6 +407,7 @@ body {
position: absolute;
width: 100%;
padding: 20px 0px;
+ pointer-events: auto;
z-index: 10;
transform-style: flat;
@@ -443,6 +445,11 @@ body {
opacity: 1;
}
+.reveal .slides>section:empty,
+.reveal .slides>section>section:empty {
+ pointer-events: none;
+}
+
.reveal.center,
.reveal.center .slides,
.reveal.center .slides section {
@@ -610,6 +617,10 @@ body {
/*********************************************
* CUBE TRANSITION
+ *
+ * WARNING:
+ * this is deprecated and will be removed in a
+ * future version.
*********************************************/
.reveal.cube .slides {
@@ -682,6 +693,10 @@ body {
/*********************************************
* PAGE TRANSITION
+ *
+ * WARNING:
+ * this is deprecated and will be removed in a
+ * future version.
*********************************************/
.reveal.page .slides {
@@ -866,6 +881,7 @@ body {
height: 100%;
opacity: 0;
visibility: hidden;
+ overflow: hidden;
background-color: rgba( 0, 0, 0, 0 );
background-position: 50% 50%;
@@ -882,6 +898,7 @@ body {
.reveal .slide-background.present {
opacity: 1;
visibility: visible;
+ z-index: 2;
}
.print-pdf .reveal .slide-background {
@@ -898,7 +915,11 @@ body {
max-height: none;
top: 0;
left: 0;
+ object-fit: cover;
}
+ .reveal .slide-background[data-background-size="contain"] video {
+ object-fit: contain;
+ }
/* Immediate transition style */
.reveal[data-background-transition=none]>.backgrounds .slide-background,
@@ -1080,6 +1101,10 @@ body {
outline: 10px solid rgba(150,150,150,0.1);
outline-offset: 10px;
}
+
+ .backgrounds .slide-background.stack {
+ overflow: visible;
+ }
}
// Disable transitions transitions while we're activating
@@ -1094,10 +1119,6 @@ body {
transition: none;
}
-.reveal.overview-animated .slides {
- transition: transform 0.4s ease;
-}
-
/*********************************************
* RTL SUPPORT
diff --git a/index.html b/index.html
index 0c7a672..98accc3 100644
--- a/index.html
+++ b/index.html
@@ -33,11 +33,10 @@
<script src="js/reveal.js"></script>
<script>
- // More info https://github.com/hakimel/reveal.js#configuration
+ // More info about config & dependencies:
+ // - https://github.com/hakimel/reveal.js#configuration
+ // - https://github.com/hakimel/reveal.js#dependencies
Reveal.initialize({
- history: true,
-
- // More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'plugin/markdown/marked.js' },
{ src: 'plugin/markdown/markdown.js' },
diff --git a/js/reveal.js b/js/reveal.js
index 43c599c..8655f51 100644
--- a/js/reveal.js
+++ b/js/reveal.js
@@ -3,7 +3,7 @@
* http://lab.hakim.se/reveal-js
* MIT licensed
*
- * Copyright (C) 2016 Hakim El Hattab, http://hakim.se
+ * Copyright (C) 2017 Hakim El Hattab, http://hakim.se
*/
(function( root, factory ) {
if( typeof define === 'function' && define.amd ) {
@@ -58,6 +58,9 @@
// Display the page number of the current slide
slideNumber: false,
+ // Determine which displays to show the slide number on
+ showSlideNumber: 'all',
+
// Push each slide change to the browser history
history: false,
@@ -102,6 +105,12 @@
// Flags if speaker notes should be visible to all viewers
showNotes: false,
+ // Global override for autolaying embedded media (video/audio/iframe)
+ // - null: Media will only autoplay if data-autoplay is present
+ // - true: All media will autoplay, regardless of individual setting
+ // - false: No media will autoplay, regardless of individual setting
+ autoPlayMedia: null,
+
// Number of milliseconds between automatically proceeding to the
// next slide, disabled when set to 0, this value can be overwritten
// by using a data-autoslide attribute on your slides
@@ -157,9 +166,19 @@
// to PDF, unlimited by default
pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY,
+ // Offset used to reduce the height of content within exported PDF pages.
+ // This exists to account for environment differences based on how you
+ // print to PDF. CLI printing options, like phantomjs and wkpdf, can end
+ // on precisely the total height of the document whereas in-browser
+ // printing has to end one pixel before.
+ pdfPageHeightOffset: -1,
+
// Number of slides away from the current that are visible
viewDistance: 3,
+ // The display mode that will be used to show slides
+ display: 'block',
+
// Script dependencies to load
dependencies: []
@@ -605,7 +624,7 @@
slideHeight = slideSize.height;
// Let the browser know what page size we want to print
- injectStyleSheet( '@page{size:'+ pageWidth +'px '+ pageHeight +'px; margin: 0 0 -1px 0;}' );
+ injectStyleSheet( '@page{size:'+ pageWidth +'px '+ pageHeight +'px; margin: 0px;}' );
// Limit the size of certain elements to the dimensions of the slide
injectStyleSheet( '.reveal section>img, .reveal section>video, .reveal section>iframe{max-width: '+ slideWidth +'px; max-height:'+ slideHeight +'px}' );
@@ -614,6 +633,9 @@
document.body.style.width = pageWidth + 'px';
document.body.style.height = pageHeight + 'px';
+ // Make sure stretch elements fit on slide
+ layoutSlideContents( slideWidth, slideHeight );
+
// Add each slide's index as attributes on itself, we need these
// indices to generate slide numbers below
toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).forEach( function( hslide, h ) {
@@ -652,7 +674,7 @@
// so that no page ever flows onto another
var page = document.createElement( 'div' );
page.className = 'pdf-page';
- page.style.height = ( pageHeight * numberOfPages ) + 'px';
+ page.style.height = ( ( pageHeight + config.pdfPageHeightOffset ) * numberOfPages ) + 'px';
slide.parentNode.insertBefore( page, slide );
page.appendChild( slide );
@@ -695,7 +717,7 @@
}
// Inject slide numbers if `slideNumbers` are enabled
- if( config.slideNumber ) {
+ if( config.slideNumber && /all|print/i.test( config.showSlideNumber ) ) {
var slideNumberH = parseInt( slide.getAttribute( 'data-index-h' ), 10 ) + 1,
slideNumberV = parseInt( slide.getAttribute( 'data-index-v' ), 10 ) + 1;
@@ -859,7 +881,7 @@
if( data.background ) {
// Auto-wrap image urls in url(...)
- if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)$/gi.test( data.background ) ) {
+ if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)([?#]|$)/gi.test( data.background ) ) {
slide.setAttribute( 'data-background-image', data.background );
}
else {
@@ -884,6 +906,7 @@
// Additional and optional background properties
if( data.backgroundSize ) element.style.backgroundSize = data.backgroundSize;
+ if( data.backgroundSize ) element.setAttribute( 'data-background-size', data.backgroundSize );
if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor;
if( data.backgroundRepeat ) element.style.backgroundRepeat = data.backgroundRepeat;
if( data.backgroundPosition ) element.style.backgroundPosition = data.backgroundPosition;
@@ -977,7 +1000,6 @@
dom.controls.style.display = config.controls ? 'block' : 'none';
dom.progress.style.display = config.progress ? 'block' : 'none';
- dom.slideNumber.style.display = config.slideNumber && !isPrintingPDF() ? 'block' : 'none';
if( config.shuffle ) {
shuffle();
@@ -1030,10 +1052,11 @@
// Iframe link previews
if( config.previewLinks ) {
enablePreviewLinks();
+ disablePreviewLinks( '[data-preview-link=false]' );
}
else {
disablePreviewLinks();
- enablePreviewLinks( '[data-preview-link]' );
+ enablePreviewLinks( '[data-preview-link]:not([data-preview-link=false])' );
}
// Remove existing auto-slide controls
@@ -1060,6 +1083,19 @@
} );
}
+ // Slide numbers
+ var slideNumberDisplay = 'none';
+ if( config.slideNumber && !isPrintingPDF() ) {
+ if( config.showSlideNumber === 'all' ) {
+ slideNumberDisplay = 'block';
+ }
+ else if( config.showSlideNumber === 'speaker' && isSpeakerNotes() ) {
+ slideNumberDisplay = 'block';
+ }
+ }
+
+ dom.slideNumber.style.display = slideNumberDisplay;
+
sync();
}
@@ -1225,7 +1261,7 @@
if( value === 'null' ) return null;
else if( value === 'true' ) return true;
else if( value === 'false' ) return false;
- else if( value.match( /^\d+$/ ) ) return parseFloat( value );
+ else if( value.match( /^[\d\.]+$/ ) ) return parseFloat( value );
}
return value;
@@ -1569,9 +1605,9 @@
/**
* Unbind preview frame links.
*/
- function disablePreviewLinks() {
+ function disablePreviewLinks( selector ) {
- var anchors = toArray( document.querySelectorAll( 'a' ) );
+ var anchors = toArray( document.querySelectorAll( selector ? selector : 'a' ) );
anchors.forEach( function( element ) {
if( /^(http|www)/gi.test( element.getAttribute( 'href' ) ) ) {
@@ -1629,6 +1665,28 @@
}
/**
+ * Open or close help overlay window.
+ *
+ * @param {Boolean} [override] Flag which overrides the
+ * toggle logic and forcibly sets the desired state. True means
+ * help is open, false means it's closed.
+ */
+ function toggleHelp( override ){
+
+ if( typeof override === 'boolean' ) {
+ override ? showHelp() : closeOverlay();
+ }
+ else {
+ if( dom.overlay ) {
+ closeOverlay();
+ }
+ else {
+ showHelp();
+ }
+ }
+ }
+
+ /**
* Opens an overlay window with help material.
*/
function showHelp() {
@@ -1770,6 +1828,10 @@
updateProgress();
updateParallax();
+ if( isOverview() ) {
+ updateOverview();
+ }
+
}
}
@@ -1985,11 +2047,14 @@
*/
function updateOverview() {
+ var vmin = Math.min( window.innerWidth, window.innerHeight );
+ var scale = Math.max( vmin / 5, 150 ) / vmin;
+
transformSlides( {
overview: [
+ 'scale('+ scale +')',
'translateX('+ ( -indexh * overviewSlideWidth ) +'px)',
- 'translateY('+ ( -indexv * overviewSlideHeight ) +'px)',
- 'translateZ('+ ( window.innerWidth < 400 ? -1000 : -2500 ) +'px)'
+ 'translateY('+ ( -indexv * overviewSlideHeight ) +'px)'
].join( ' ' )
} );
@@ -2395,13 +2460,20 @@
updateControls();
updateProgress();
- updateBackground( true );
updateSlideNumber();
updateSlidesVisibility();
+ updateBackground( true );
updateNotes();
formatEmbeddedContent();
- startEmbeddedContent( currentSlide );
+
+ // Start or stop embedded content depending on global config
+ if( config.autoPlayMedia === false ) {
+ stopEmbeddedContent( currentSlide );
+ }
+ else {
+ startEmbeddedContent( currentSlide );
+ }
if( isOverview() ) {
layoutOverview();
@@ -2873,34 +2945,17 @@
} );
- // Stop any currently playing video background
+ // Stop content inside of previous backgrounds
if( previousBackground ) {
- var previousVideo = previousBackground.querySelector( 'video' );
- if( previousVideo ) previousVideo.pause();
+ stopEmbeddedContent( previousBackground );
}
+ // Start content in the current background
if( currentBackground ) {
- // Start video playback
- var currentVideo = currentBackground.querySelector( 'video' );
- if( currentVideo ) {
-
- var startVideo = function() {
- currentVideo.currentTime = 0;
- currentVideo.play();
- currentVideo.removeEventListener( 'loadeddata', startVideo );
- };
-
- if( currentVideo.readyState > 1 ) {
- startVideo();
- }
- else {
- currentVideo.addEventListener( 'loadeddata', startVideo );
- }
-
- }
+ startEmbeddedContent( currentBackground );
var backgroundImageURL = currentBackground.style.backgroundImage || '';
@@ -3009,7 +3064,7 @@
function showSlide( slide ) {
// Show the slide element
- slide.style.display = 'block';
+ slide.style.display = config.display;
// Media elements with data-src attributes
toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src]' ) ).forEach( function( element ) {
@@ -3079,11 +3134,23 @@
// Iframes
else if( backgroundIframe ) {
var iframe = document.createElement( 'iframe' );
+ iframe.setAttribute( 'allowfullscreen', '' );
+ iframe.setAttribute( 'mozallowfullscreen', '' );
+ iframe.setAttribute( 'webkitallowfullscreen', '' );
+
+ // Only load autoplaying content when the slide is shown to
+ // avoid having it play in the background
+ if( /autoplay=(1|true|yes)/gi.test( backgroundIframe ) ) {
+ iframe.setAttribute( 'data-src', backgroundIframe );
+ }
+ else {
iframe.setAttribute( 'src', backgroundIframe );
- iframe.style.width = '100%';
- iframe.style.height = '100%';
- iframe.style.maxHeight = '100%';
- iframe.style.maxWidth = '100%';
+ }
+
+ iframe.style.width = '100%';
+ iframe.style.height = '100%';
+ iframe.style.maxHeight = '100%';
+ iframe.style.maxWidth = '100%';
background.appendChild( iframe );
}
@@ -3191,11 +3258,12 @@
* Start playback of any embedded content inside of
* the given element.
*
- * @param {HTMLElement} slide
+ * @param {HTMLElement} element
*/
function startEmbeddedContent( element ) {
if( element && !isSpeakerNotes() ) {
+
// Restart GIFs
toArray( element.querySelectorAll( 'img[src$=".gif"]' ) ).forEach( function( el ) {
// Setting the same unchanged source like this was confirmed
@@ -3209,8 +3277,25 @@
return;
}
- if( el.hasAttribute( 'data-autoplay' ) && typeof el.play === 'function' ) {
- el.play();
+ // Prefer an explicit global autoplay setting
+ var autoplay = config.autoPlayMedia;
+
+ // If no global setting is available, fall back on the element's
+ // own autoplay setting
+ if( typeof autoplay !== 'boolean' ) {
+ autoplay = el.hasAttribute( 'data-autoplay' ) || !!closestParent( el, '.slide-background' );
+ }
+
+ if( autoplay && typeof el.play === 'function' ) {
+
+ if( el.readyState > 1 ) {
+ startEmbeddedMedia( { target: el } );
+ }
+ else {
+ el.removeEventListener( 'loadeddata', startEmbeddedMedia ); // remove first to avoid dupes
+ el.addEventListener( 'loadeddata', startEmbeddedMedia );
+ }
+
}
} );
@@ -3235,15 +3320,36 @@
el.setAttribute( 'src', el.getAttribute( 'data-src' ) );
}
} );
+
}
}
/**
+ * Starts playing an embedded video/audio element after
+ * it has finished loading.
+ *
+ * @param {object} event
+ */
+ function startEmbeddedMedia( event ) {
+
+ var isAttachedToDOM = !!closestParent( event.target, 'html' ),
+ isVisible = !!closestParent( event.target, '.present' );
+
+ if( isAttachedToDOM && isVisible ) {
+ event.target.currentTime = 0;
+ event.target.play();
+ }
+
+ event.target.removeEventListener( 'loadeddata', startEmbeddedMedia );
+
+ }
+
+ /**
* "Starts" the content of an embedded iframe using the
* postMessage API.
*
- * @param {object} event - postMessage API event
+ * @param {object} event
*/
function startEmbeddedIframe( event ) {
@@ -3251,17 +3357,33 @@
if( iframe && iframe.contentWindow ) {
- // YouTube postMessage API
- if( /youtube\.com\/embed\//.test( iframe.getAttribute( 'src' ) ) && iframe.hasAttribute( 'data-autoplay' ) ) {
- iframe.contentWindow.postMessage( '{"event":"command","func":"playVideo","args":""}', '*' );
- }
- // Vimeo postMessage API
- else if( /player\.vimeo\.com\//.test( iframe.getAttribute( 'src' ) ) && iframe.hasAttribute( 'data-autoplay' ) ) {
- iframe.contentWindow.postMessage( '{"method":"play"}', '*' );
- }
- // Generic postMessage API
- else {
- iframe.contentWindow.postMessage( 'slide:start', '*' );
+ var isAttachedToDOM = !!closestParent( event.target, 'html' ),
+ isVisible = !!closestParent( event.target, '.present' );
+
+ if( isAttachedToDOM && isVisible ) {
+
+ // Prefer an explicit global autoplay setting
+ var autoplay = config.autoPlayMedia;
+
+ // If no global setting is available, fall back on the element's
+ // own autoplay setting
+ if( typeof autoplay !== 'boolean' ) {
+ autoplay = iframe.hasAttribute( 'data-autoplay' ) || !!closestParent( iframe, '.slide-background' );
+ }
+
+ // YouTube postMessage API
+ if( /youtube\.com\/embed\//.test( iframe.getAttribute( 'src' ) ) && autoplay ) {
+ iframe.contentWindow.postMessage( '{"event":"command","func":"playVideo","args":""}', '*' );
+ }
+ // Vimeo postMessage API
+ else if( /player\.vimeo\.com\//.test( iframe.getAttribute( 'src' ) ) && autoplay ) {
+ iframe.contentWindow.postMessage( '{"method":"play"}', '*' );
+ }
+ // Generic postMessage API
+ else {
+ iframe.contentWindow.postMessage( 'slide:start', '*' );
+ }
+
}
}
@@ -3272,40 +3394,43 @@
* Stop playback of any embedded content inside of
* the targeted slide.
*
- * @param {HTMLElement} slide
+ * @param {HTMLElement} element
+ * @param {boolean} autoplay Optionally override the
+ * autoplay setting of media elements
*/
- function stopEmbeddedContent( slide ) {
+ function stopEmbeddedContent( element, autoplay ) {
- if( slide && slide.parentNode ) {
+ if( element && element.parentNode ) {
// HTML5 media elements
- toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
+ toArray( element.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
if( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) {
+ el.setAttribute('data-paused-by-reveal', '');
el.pause();
}
} );
// Generic postMessage API for non-lazy loaded iframes
- toArray( slide.querySelectorAll( 'iframe' ) ).forEach( function( el ) {
- el.contentWindow.postMessage( 'slide:stop', '*' );
+ toArray( element.querySelectorAll( 'iframe' ) ).forEach( function( el ) {
+ if( el.contentWindow ) el.contentWindow.postMessage( 'slide:stop', '*' );
el.removeEventListener( 'load', startEmbeddedIframe );
});
// YouTube postMessage API
- toArray( slide.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) {
- if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) {
+ toArray( element.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) {
+ if( !el.hasAttribute( 'data-ignore' ) && el.contentWindow && typeof el.contentWindow.postMessage === 'function' ) {
el.contentWindow.postMessage( '{"event":"command","func":"pauseVideo","args":""}', '*' );
}
});
// Vimeo postMessage API
- toArray( slide.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) {
- if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) {
+ toArray( element.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) {
+ if( !el.hasAttribute( 'data-ignore' ) && el.contentWindow && typeof el.contentWindow.postMessage === 'function' ) {
el.contentWindow.postMessage( '{"method":"pause"}', '*' );
}
});
// Lazy loading iframes
- toArray( slide.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) {
+ toArray( element.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) {
// Only removing the src doesn't actually unload the frame
// in all browsers (Firefox) so we set it to blank first
el.setAttribute( 'src', 'about:blank' );
@@ -4115,12 +4240,7 @@
// Check if the pressed key is question mark
if( event.shiftKey && event.charCode === 63 ) {
- if( dom.overlay ) {
- closeOverlay();
- }
- else {
- showHelp( true );
- }
+ toggleHelp();
}
}
@@ -4818,9 +4938,6 @@
navigatePrev: navigatePrev,
navigateNext: navigateNext,
- // Shows a help overlay with keyboard shortcuts
- showHelp: showHelp,
-
// Forces an update in slide layout
layout: layout,
@@ -4833,6 +4950,9 @@
// Returns an object with the available fragments as booleans (prev/next)
availableFragments: availableFragments,
+ // Toggles a help overlay with keyboard shortcuts
+ toggleHelp: toggleHelp,
+
// Toggles the overview mode on/off
toggleOverview: toggleOverview,
diff --git a/package.json b/package.json
index 1f866ea..37ffde2 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"main": "js/reveal.js",
"scripts": {
"test": "grunt test",
- "start": "grunt serve"
+ "start": "grunt serve",
+ "build": "grunt"
},
"author": {
"name": "Hakim El Hattab",
@@ -21,15 +22,11 @@
"engines": {
"node": ">=4.0.0"
},
- "dependencies": {
- "express": "~4.14.0",
- "grunt-cli": "~1.2.0",
- "mustache": "~2.2.1",
- "socket.io": "^1.4.8"
- },
"devDependencies": {
+ "express": "~4.14.0",
"grunt": "~1.0.1",
"grunt-autoprefixer": "~3.0.3",
+ "grunt-cli": "~1.2.0",
"grunt-contrib-connect": "~0.11.2",
"grunt-contrib-cssmin": "~0.14.0",
"grunt-contrib-jshint": "~0.11.3",
@@ -39,7 +36,9 @@
"grunt-sass": "~1.2.0",
"grunt-retire": "~0.3.10",
"grunt-zip": "~0.17.1",
- "node-sass": "~3.13.0"
+ "mustache": "~2.2.1",
+ "node-sass": "~3.13.0",
+ "socket.io": "^1.4.8"
},
"license": "MIT"
}
diff --git a/plugin/markdown/markdown.js b/plugin/markdown/markdown.js
index 29aabf5..d9ff1ba 100755
--- a/plugin/markdown/markdown.js
+++ b/plugin/markdown/markdown.js
@@ -31,7 +31,8 @@
*/
function getMarkdownFromSlide( section ) {
- var template = section.querySelector( 'script' );
+ // look for a <script> or <textarea data-template> wrapper
+ var template = section.querySelector( '[data-template]' ) || section.querySelector( 'script' );
// strip leading whitespace so it isn't evaluated as code
var text = ( template || section ).textContent;
diff --git a/plugin/math/math.js b/plugin/math/math.js
index c0a691d..e3b4089 100755
--- a/plugin/math/math.js
+++ b/plugin/math/math.js
@@ -7,7 +7,7 @@
var RevealMath = window.RevealMath || (function(){
var options = Reveal.getConfig().math || {};
- options.mathjax = options.mathjax || 'https://cdn.mathjax.org/mathjax/latest/MathJax.js';
+ options.mathjax = options.mathjax || 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js';
options.config = options.config || 'TeX-AMS_HTML-full';
loadScript( options.mathjax + '?config=' + options.config, function() {
diff --git a/plugin/notes/notes.js b/plugin/notes/notes.js
index 46bf5de..44efe15 100644
--- a/plugin/notes/notes.js
+++ b/plugin/notes/notes.js
@@ -50,10 +50,11 @@ var RevealNotes = (function() {
/**
* Posts the current slide data to the notes window
*/
- function post(event) {
+ function post( event ) {
var slideElement = Reveal.getCurrentSlide(),
- notesElement = slideElement.querySelector( 'aside.notes' );
+ notesElement = slideElement.querySelector( 'aside.notes' ),
+ fragmentElement = slideElement.querySelector( '.current-fragment' );
var messageData = {
namespace: 'reveal-notes',
@@ -64,21 +65,27 @@ var RevealNotes = (function() {
state: Reveal.getState()
};
- // Look for notes defined in a fragment, if it is a fragmentshown event
- if (event && event.hasOwnProperty('fragment')) {
- var innerNotes = event.fragment.querySelector( 'aside.notes' );
-
- if ( innerNotes) {
- notesElement = innerNotes;
- }
- }
-
// Look for notes defined in a slide attribute
if( slideElement.hasAttribute( 'data-notes' ) ) {
messageData.notes = slideElement.getAttribute( 'data-notes' );
messageData.whitespace = 'pre-wrap';
}
+ // Look for notes defined in a fragment
+ if( fragmentElement ) {
+ var fragmentNotes = fragmentElement.querySelector( 'aside.notes' );
+ if( fragmentNotes ) {
+ notesElement = fragmentNotes;
+ }
+ else if( fragmentElement.hasAttribute( 'data-notes' ) ) {
+ messageData.notes = fragmentElement.getAttribute( 'data-notes' );
+ messageData.whitespace = 'pre-wrap';
+
+ // In case there are slide notes
+ notesElement = null;
+ }
+ }
+
// Look for notes defined in an aside element
if( notesElement ) {
messageData.notes = notesElement.innerHTML;
diff --git a/plugin/print-pdf/print-pdf.js b/plugin/print-pdf/print-pdf.js
index c3c5d94..9ffc261 100644
--- a/plugin/print-pdf/print-pdf.js
+++ b/plugin/print-pdf/print-pdf.js
@@ -6,6 +6,7 @@
*
* @author Manuel Bieh (https://github.com/manuelbieh)
* @author Hakim El Hattab (https://github.com/hakimel)
+ * @author Manuel Riezebosch (https://github.com/riezebosch)
*/
// html2pdf.js
@@ -21,31 +22,48 @@ if( outputFile.match( /\.pdf$/gi ) === null ) {
outputFile += '.pdf';
}
-console.log( 'Export PDF: Reading reveal.js config [1/3]' );
+console.log( 'Export PDF: Reading reveal.js config [1/4]' );
probePage.open( inputFile, function( status ) {
- console.log( 'Export PDF: Preparing print layout [2/3]' );
+ console.log( 'Export PDF: Preparing print layout [2/4]' );
var config = probePage.evaluate( function() {
return Reveal.getConfig();
} );
- printPage.paperSize = {
- width: config.width * ( 1 + config.margin ),
- height: config.height * ( 1 + config.margin ),
- border: 0
- };
-
- printPage.open( inputFile, function( status ) {
- window.setTimeout( function() {
- console.log( 'Export PDF: Writing file [3/3]' );
- printPage.render( outputFile );
- console.log( 'Export PDF: Finished successfully!' );
- phantom.exit();
- }, 1000 );
- } );
+ if( config ) {
+
+ printPage.paperSize = {
+ width: Math.floor( config.width * ( 1 + config.margin ) ),
+ height: Math.floor( config.height * ( 1 + config.margin ) ),
+ border: 0
+ };
+
+ printPage.open( inputFile, function( status ) {
+ console.log( 'Export PDF: Preparing pdf [3/4]')
+ printPage.evaluate(function() {
+ Reveal.isReady() ? window.callPhantom() : Reveal.addEventListener( 'pdf-ready', window.callPhantom );
+ });
+ } );
+
+ printPage.onCallback = function(data) {
+ // For some reason we need to "jump the queue" for syntax highlighting to work.
+ // See: http://stackoverflow.com/a/3580132/129269
+ setTimeout(function() {
+ console.log( 'Export PDF: Writing file [4/4]' );
+ printPage.render( outputFile );
+ console.log( 'Export PDF: Finished successfully!' );
+ phantom.exit();
+ }, 0);
+ };
+ }
+ else {
+
+ console.log( 'Export PDF: Unable to read reveal.js config. Make sure the input address points to a reveal.js page.' );
+ phantom.exit(1);
+ }
} );
diff --git a/test/examples/math.html b/test/examples/math.html
index 1b80e03..d35e827 100644
--- a/test/examples/math.html
+++ b/test/examples/math.html
@@ -169,7 +169,7 @@
transition: 'linear',
math: {
- // mathjax: 'http://cdn.mathjax.org/mathjax/latest/MathJax.js',
+ // mathjax: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js',
config: 'TeX-AMS_HTML-full'
},