aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gruntfile.js11
-rw-r--r--LICENSE2
-rw-r--r--README.md26
-rw-r--r--css/reveal.css20
-rw-r--r--css/reveal.scss15
-rw-r--r--index.html7
-rw-r--r--js/reveal.js151
-rw-r--r--package.json12
-rwxr-xr-xplugin/markdown/markdown.js3
9 files changed, 160 insertions, 87 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 8797a07..0aa0f29 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>
```
@@ -578,6 +578,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>
@@ -849,13 +850,14 @@ Here's an example of an exported presentation that's been uploaded to SlideShare
Export dimensions are inferred from the configured [presentation size](#presentation-size). Slides that are too tall to fit within a single page will expand onto multiple pages. You can limit how many pages a slide may expand onto using the `pdfMaxPagesPerSlide` config option, for example `Reveal.configure({ pdfMaxPagesPerSlide: 1 })` ensures that no slide ever grows to more than one printed page.
-1. Open your presentation with `print-pdf` included in the query string i.e. http://localhost:8000/?print-pdf#/. This triggers the default index HTML to load the PDF print stylesheet ([css/print/pdf.css](https://github.com/hakimel/reveal.js/blob/master/css/print/pdf.css)). 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**.
+1. Open your presentation with `print-pdf` included in the query string i.e. http://localhost:8000/?print-pdf. This triggers the default index HTML to load the PDF print stylesheet ([css/print/pdf.css](https://github.com/hakimel/reveal.js/blob/master/css/print/pdf.css)). You can test this with [lab.hakim.se/reveal-js?print-pdf](http://lab.hakim.se/reveal-js?print-pdf).
+ * 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)
@@ -924,7 +926,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
@@ -1167,4 +1169,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/reveal.css b/css/reveal.css
index 430dcde..296c8e9 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 {
@@ -839,6 +845,7 @@ body {
height: 100%;
opacity: 0;
visibility: hidden;
+ overflow: hidden;
background-color: transparent;
background-position: 50% 50%;
background-repeat: no-repeat;
@@ -851,7 +858,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 +873,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,
diff --git a/css/reveal.scss b/css/reveal.scss
index 22fb3fe..ee3c440 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 {
@@ -866,6 +873,7 @@ body {
height: 100%;
opacity: 0;
visibility: hidden;
+ overflow: hidden;
background-color: rgba( 0, 0, 0, 0 );
background-position: 50% 50%;
@@ -882,6 +890,7 @@ body {
.reveal .slide-background.present {
opacity: 1;
visibility: visible;
+ z-index: 2;
}
.print-pdf .reveal .slide-background {
@@ -898,7 +907,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,
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 9251dc0..7a561a1 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 ) {
@@ -859,7 +859,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 +884,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;
@@ -1030,10 +1031,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
@@ -1569,9 +1571,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' ) ) ) {
@@ -2395,9 +2397,9 @@
updateControls();
updateProgress();
- updateBackground( true );
updateSlideNumber();
updateSlidesVisibility();
+ updateBackground( true );
updateNotes();
formatEmbeddedContent();
@@ -2873,34 +2875,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 || '';
@@ -3077,11 +3062,20 @@
// Iframes
else if( backgroundIframe ) {
var iframe = document.createElement( 'iframe' );
+
+ // 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 );
}
@@ -3189,11 +3183,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
@@ -3207,8 +3202,22 @@
return;
}
- if( el.hasAttribute( 'data-autoplay' ) && typeof el.play === 'function' ) {
- el.play();
+ // Autoplay is always on for slide backgrounds
+ var 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 );
+
+ // `loadeddata` never fires unless we start playing on iPad
+ if( /ipad/gi.test( UA ) ) el.play();
+ }
+
}
} );
@@ -3233,15 +3242,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 ) {
@@ -3249,17 +3279,26 @@
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 ) {
+
+ var 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', '*' );
+ }
+
}
}
@@ -3270,40 +3309,42 @@
* 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.pause();
}
} );
// Generic postMessage API for non-lazy loaded iframes
- toArray( slide.querySelectorAll( 'iframe' ) ).forEach( function( el ) {
+ toArray( element.querySelectorAll( 'iframe' ) ).forEach( function( el ) {
el.contentWindow.postMessage( 'slide:stop', '*' );
el.removeEventListener( 'load', startEmbeddedIframe );
});
// YouTube postMessage API
- toArray( slide.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) {
+ toArray( element.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) {
if( !el.hasAttribute( 'data-ignore' ) && 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 ) {
+ toArray( element.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) {
if( !el.hasAttribute( 'data-ignore' ) && 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' );
@@ -3900,7 +3941,7 @@
// If there are media elements with data-autoplay,
// automatically set the autoSlide duration to the
// length of that media. Not applicable if the slide
- // is divided up into fragments.
+ // is divided up into fragments.
// playbackRate is accounted for in the duration.
if( currentSlide.querySelectorAll( '.fragment' ).length === 0 ) {
toArray( currentSlide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
diff --git a/package.json b/package.json
index 1f866ea..177e720 100644
--- a/package.json
+++ b/package.json
@@ -21,15 +21,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 +35,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;