summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Gruntfile.js4
-rw-r--r--README.md98
-rw-r--r--bower.json2
-rw-r--r--css/print/pdf.css15
-rw-r--r--css/reveal.css5
-rw-r--r--css/reveal.scss3
-rw-r--r--css/theme/beige.css5
-rw-r--r--css/theme/black.css5
-rw-r--r--css/theme/blood.css5
-rw-r--r--css/theme/league.css5
-rw-r--r--css/theme/moon.css5
-rw-r--r--css/theme/night.css5
-rw-r--r--css/theme/serif.css5
-rw-r--r--css/theme/simple.css5
-rw-r--r--css/theme/sky.css5
-rw-r--r--css/theme/solarized.css5
-rw-r--r--css/theme/template/theme.scss6
-rw-r--r--css/theme/white.css5
-rw-r--r--demo.html25
-rw-r--r--js/reveal.js220
-rw-r--r--lib/js/head.min.js17
-rw-r--r--package.json2
-rw-r--r--plugin/multiplex/index.js10
-rw-r--r--plugin/multiplex/package.json19
-rw-r--r--plugin/zoom-js/zoom.js12
25 files changed, 292 insertions, 201 deletions
diff --git a/Gruntfile.js b/Gruntfile.js
index 5b11c2b..87630d5 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -126,10 +126,10 @@ module.exports = function(grunt) {
tasks: 'css-core'
},
html: {
- files: [ 'index.html']
+ files: [ '*.html']
},
markdown: {
- files: [ './*.md' ]
+ files: [ '*.md' ]
},
options: {
livereload: true
diff --git a/README.md b/README.md
index af1d6d7..579cfe8 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,57 @@
A framework for easily creating beautiful presentations using HTML. [Check out the live demo](http://lab.hakim.se/reveal-js/).
-reveal.js comes with a broad range of features including [nested slides](https://github.com/hakimel/reveal.js#markup), [Markdown contents](https://github.com/hakimel/reveal.js#markdown), [PDF export](https://github.com/hakimel/reveal.js#pdf-export), [speaker notes](https://github.com/hakimel/reveal.js#speaker-notes) and a [JavaScript API](https://github.com/hakimel/reveal.js#api). It's best viewed in a modern browser but [fallbacks](https://github.com/hakimel/reveal.js/wiki/Browser-Support) are available to make sure your presentation can still be viewed elsewhere.
-
-
-#### More reading:
-- [Installation](#installation): Step-by-step instructions for getting reveal.js running on your computer.
+reveal.js comes with a broad range of features including [nested slides](https://github.com/hakimel/reveal.js#markup), [Markdown contents](https://github.com/hakimel/reveal.js#markdown), [PDF export](https://github.com/hakimel/reveal.js#pdf-export), [speaker notes](https://github.com/hakimel/reveal.js#speaker-notes) and a [JavaScript API](https://github.com/hakimel/reveal.js#api). There's also a fully featured visual editor and platform for sharing reveal.js presentations at [slides.com](https://slides.com).
+
+## Table of contents
+- [Online Editor](#online-editor)
+- [Instructions](#instructions)
+ - [Markup](#markup)
+ - [Markdown](#markdown)
+ - [Element Attributes](#element-attributes)
+ - [Slide Attributes](#slide-attributes)
+- [Configuration](#configuration)
+- [Presentation Size](#presentation-size)
+- [Dependencies](#dependencies)
+- [Ready Event](#ready-event)
+- [Auto-sliding](#auto-sliding)
+- [Keyboard Bindings](#keyboard-bindings)
+- [Touch Navigation](#touch-navigation)
+- [Lazy Loading](#lazy-loading)
+- [API](#api)
+ - [Slide Changed Event](#slide-changed-event)
+ - [Presentation State](#presentation-state)
+ - [Slide States](#slide-states)
+ - [Slide Backgrounds](#slide-backgrounds)
+ - [Parallax Background](#parallax-background)
+ - [Slide Transitions](#slide-transitions)
+ - [Internal links](#internal-links)
+ - [Fragments](#fragments)
+ - [Fragment events](#fragment-events)
+ - [Code syntax highlighting](#code-syntax-highlighting)
+ - [Slide number](#slide-number)
+ - [Overview mode](#overview-mode)
+ - [Fullscreen mode](#fullscreen-mode)
+ - [Embedded media](#embedded-media)
+ - [Stretching elements](#stretching-elements)
+ - [postMessage API](#postmessage-api)
+- [PDF Export](#pdf-export)
+- [Theming](#theming)
+- [Speaker Notes](#speaker-notes)
+ - [Share and Print Speaker Notes](#share-and-print-speaker-notes)
+ - [Server Side Speaker Notes](#server-side-speaker-notes)
+- [Multiplexing](#multiplexing)
+ - [Master presentation](#master-presentation)
+ - [Client presentation](#client-presentation)
+ - [Socket.io server](#socketio-server)
+- [MathJax](#mathjax)
+- [Installation](#installation)
+ - [Basic setup](#basic-setup)
+ - [Full setup](#full-setup)
+ - [Folder Structure](#folder-structure)
+- [License](#license)
+
+#### More reading
- [Changelog](https://github.com/hakimel/reveal.js/releases): Up-to-date version history.
- [Examples](https://github.com/hakimel/reveal.js/wiki/Example-Presentations): Presentations created with reveal.js, add your own!
- [Browser Support](https://github.com/hakimel/reveal.js/wiki/Browser-Support): Explanation of browser support and fallbacks.
@@ -734,10 +780,12 @@ Reveal.initialize({
## PDF Export
-Presentations can be exported to PDF via a special print stylesheet. This feature requires that you use [Google Chrome](http://google.com/chrome) or [Chromium](https://www.chromium.org/Home).
+Presentations can be exported to PDF via a special print stylesheet. This feature requires that you use [Google Chrome](http://google.com/chrome) or [Chromium](https://www.chromium.org/Home) and to be serving the presention from a webserver.
Here's an example of an exported presentation that's been uploaded to SlideShare: http://www.slideshare.net/hakimel/revealjs-300.
-1. Open your presentation with `print-pdf` included anywhere in the query string. 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).
+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**.
@@ -829,14 +877,14 @@ Reveal.initialize({
Then:
-1. Install [Node.js](http://nodejs.org/)
+1. Install [Node.js](http://nodejs.org/) (1.0.0 or later)
2. Run ```npm install```
3. Run ```node plugin/notes-server```
## Multiplexing
-The multiplex plugin allows your audience to view the slides of the presentation you are controlling on their own phone, tablet or laptop. As the master presentation navigates the slides, all client presentations will update in real time. See a demo at [http://revealjs-51546.onmodulus.net/](http://revealjs-51546.onmodulus.net/).
+The multiplex plugin allows your audience to view the slides of the presentation you are controlling on their own phone, tablet or laptop. As the master presentation navigates the slides, all client presentations will update in real time. See a demo at [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/).
The multiplex plugin needs the following 3 things to operate:
@@ -865,7 +913,7 @@ Reveal.initialize({
// Example values. To generate your own, see the socket.io server instructions.
secret: '13652805320794272084', // Obtained from the socket.io server. Gives this (the master) control of the presentation
id: '1ea875674b17ca76', // Obtained from socket.io server
- url: 'revealjs-51546.onmodulus.net:80' // Location of socket.io server
+ url: 'https://reveal-js-multiplex-ccjbegmaii.now.sh' // Location of socket.io server
},
// Don't forget to add the dependencies
@@ -893,7 +941,7 @@ Reveal.initialize({
// Example values. To generate your own, see the socket.io server instructions.
secret: null, // null so the clients do not have control of the master presentation
id: '1ea875674b17ca76', // id, obtained from socket.io server
- url: 'revealjs-51546.onmodulus.net:80' // Location of socket.io server
+ url: 'https://reveal-js-multiplex-ccjbegmaii.now.sh' // Location of socket.io server
},
// Don't forget to add the dependencies
@@ -912,15 +960,15 @@ 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 [http://revealjs-51546.onmodulus.net/](http://revealjs-51546.onmodulus.net/).
+Or you 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 [http://revealjs-51546.onmodulus.net/](http://revealjs-51546.onmodulus.net/), visit [http://revealjs-51546.onmodulus.net/token](http://revealjs-51546.onmodulus.net/token).
+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 [http://revealjs-51546.onmodulus.net/](http://revealjs-51546.onmodulus.net/), 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. It is simple to deploy to nodejitsu, heroku, your own environment, etc.
##### socket.io server as file static server
-The socket.io server can play the role of static file server for your client presentation, as in the example at [http://revealjs-51546.onmodulus.net/](http://revealjs-51546.onmodulus.net/). (Open [http://revealjs-51546.onmodulus.net/](http://revealjs-51546.onmodulus.net/) in two browsers. Navigate through the slides on one, and the other will update to match.)
+The socket.io server can play the role of static file server for your client presentation, as in the example at [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/). (Open [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/) in two browsers. Navigate through the slides on one, and the other will update to match.)
Example configuration:
```javascript
@@ -943,7 +991,7 @@ Reveal.initialize({
]
```
-It can also play the role of static file server for your master presentation and client presentations at the same time (as long as you don't want to use speaker notes). (Open [http://revealjs-51546.onmodulus.net/](http://revealjs-51546.onmodulus.net/) in two browsers. Navigate through the slides on one, and the other will update to match. Navigate through the slides on the second, and the first will update to match.) This is probably not desirable, because you don't want your audience to mess with your slides while you're presenting. ;)
+It can also play the role of static file server for your master presentation and client presentations at the same time (as long as you don't want to use speaker notes). (Open [https://reveal-js-multiplex-ccjbegmaii.now.sh/](https://reveal-js-multiplex-ccjbegmaii.now.sh/) in two browsers. Navigate through the slides on one, and the other will update to match. Navigate through the slides on the second, and the first will update to match.) This is probably not desirable, because you don't want your audience to mess with your slides while you're presenting. ;)
Example configuration:
```javascript
@@ -1015,33 +1063,31 @@ The core of reveal.js is very easy to install. You'll simply need to download a
Some reveal.js features, like external Markdown and speaker notes, require that presentations run from a local web server. The following instructions will set up such a server as well as all of the development tasks needed to make edits to the reveal.js source code.
-1. Install [Node.js](http://nodejs.org/)
-
-2. Install [Grunt](http://gruntjs.com/getting-started#installing-the-cli)
+1. Install [Node.js](http://nodejs.org/) (1.0.0 or later)
-4. Clone the reveal.js repository
+1. Clone the reveal.js repository
```sh
$ git clone https://github.com/hakimel/reveal.js.git
```
-5. Navigate to the reveal.js folder
+1. Navigate to the reveal.js folder
```sh
$ cd reveal.js
```
-6. Install dependencies
+1. Install dependencies
```sh
$ npm install
```
-7. Serve the presentation and monitor source files for changes
+1. Serve the presentation and monitor source files for changes
```sh
- $ grunt serve
+ $ npm start
```
-8. Open <http://localhost:8000> to view your presentation
+1. Open <http://localhost:8000> to view your presentation
- You can change the port by using `grunt serve --port 8001`.
+ You can change the port by using `npm start -- --port 8001`.
### Folder Structure
diff --git a/bower.json b/bower.json
index 5561820..a42ca8d 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "reveal.js",
- "version": "3.2.0",
+ "version": "3.3.0",
"main": [
"js/reveal.js",
"css/reveal.css"
diff --git a/css/print/pdf.css b/css/print/pdf.css
index 9ed90d6..406f125 100644
--- a/css/print/pdf.css
+++ b/css/print/pdf.css
@@ -82,11 +82,16 @@ ul, ol, div, p {
perspective-origin: 50% 50%;
}
+.reveal .slides .pdf-page {
+ position: relative;
+ overflow: hidden;
+ z-index: 1;
+}
+
.reveal .slides section {
page-break-after: always !important;
visibility: visible !important;
- position: relative !important;
display: block !important;
position: relative !important;
@@ -132,13 +137,7 @@ ul, ol, div, p {
top: 0;
left: 0;
width: 100%;
- z-index: -1;
-}
-
-/* All elements should be above the slide-background */
-.reveal section>* {
- position: relative;
- z-index: 1;
+ height: 100%;
}
/* Display slide speaker notes when 'showNotes' is enabled */
diff --git a/css/reveal.css b/css/reveal.css
index 3a31fa4..b203074 100644
--- a/css/reveal.css
+++ b/css/reveal.css
@@ -20,7 +20,7 @@ html, body, .reveal div, .reveal span, .reveal applet, .reveal object, .reveal i
.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, video {
+.reveal time, .reveal mark, .reveal audio, .reveal video {
margin: 0;
padding: 0;
border: 0;
@@ -989,7 +989,8 @@ html:-moz-full-screen-ancestor {
-webkit-perspective: 700px;
perspective: 700px; }
.reveal.overview .slides section {
- height: 700px;
+ height: 100%;
+ top: 0 !important;
opacity: 1 !important;
overflow: hidden;
visibility: visible !important;
diff --git a/css/reveal.scss b/css/reveal.scss
index 8cf8cda..f8d6904 100644
--- a/css/reveal.scss
+++ b/css/reveal.scss
@@ -1022,7 +1022,8 @@ html:-moz-full-screen-ancestor {
perspective: 700px;
.slides section {
- height: 700px;
+ height: 100%;
+ top: 0 !important;
opacity: 1 !important;
overflow: hidden;
visibility: visible !important;
diff --git a/css/theme/beige.css b/css/theme/beige.css
index 5bbda4b..7f71dd9 100644
--- a/css/theme/beige.css
+++ b/css/theme/beige.css
@@ -29,6 +29,11 @@ body {
background: rgba(79, 64, 28, 0.99);
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: rgba(79, 64, 28, 0.99);
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/black.css b/css/theme/black.css
index 511fa79..9228c46 100644
--- a/css/theme/black.css
+++ b/css/theme/black.css
@@ -25,6 +25,11 @@ body {
background: #bee4fd;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #bee4fd;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/blood.css b/css/theme/blood.css
index 6fe3d67..2da8d68 100644
--- a/css/theme/blood.css
+++ b/css/theme/blood.css
@@ -28,6 +28,11 @@ body {
background: #a23;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #a23;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/league.css b/css/theme/league.css
index 03c44ce..aa5bee5 100644
--- a/css/theme/league.css
+++ b/css/theme/league.css
@@ -31,6 +31,11 @@ body {
background: #FF5E99;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #FF5E99;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/moon.css b/css/theme/moon.css
index 5e5d6e4..5cb1176 100644
--- a/css/theme/moon.css
+++ b/css/theme/moon.css
@@ -29,6 +29,11 @@ body {
background: #d33682;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #d33682;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/night.css b/css/theme/night.css
index a439cdc..cf2c7a7 100644
--- a/css/theme/night.css
+++ b/css/theme/night.css
@@ -23,6 +23,11 @@ body {
background: #e7ad52;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #e7ad52;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/serif.css b/css/theme/serif.css
index 40ccb39..bbb9f7e 100644
--- a/css/theme/serif.css
+++ b/css/theme/serif.css
@@ -25,6 +25,11 @@ body {
background: #26351C;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #26351C;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/simple.css b/css/theme/simple.css
index 8b48be1..cb840d9 100644
--- a/css/theme/simple.css
+++ b/css/theme/simple.css
@@ -28,6 +28,11 @@ body {
background: rgba(0, 0, 0, 0.99);
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: rgba(0, 0, 0, 0.99);
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/sky.css b/css/theme/sky.css
index 99f1cfd..202ade8 100644
--- a/css/theme/sky.css
+++ b/css/theme/sky.css
@@ -32,6 +32,11 @@ body {
background: #134674;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #134674;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/solarized.css b/css/theme/solarized.css
index b4d4d4b..44771dc 100644
--- a/css/theme/solarized.css
+++ b/css/theme/solarized.css
@@ -29,6 +29,11 @@ body {
background: #d33682;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #d33682;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/css/theme/template/theme.scss b/css/theme/template/theme.scss
index 101a567..bcbaf0c 100644
--- a/css/theme/template/theme.scss
+++ b/css/theme/template/theme.scss
@@ -22,6 +22,12 @@ body {
text-shadow: none;
}
+::-moz-selection {
+ color: $selectionColor;
+ background: $selectionBackgroundColor;
+ text-shadow: none;
+}
+
.reveal .slides>section,
.reveal .slides>section>section {
line-height: 1.3;
diff --git a/css/theme/white.css b/css/theme/white.css
index b10dd0e..16a1d23 100644
--- a/css/theme/white.css
+++ b/css/theme/white.css
@@ -25,6 +25,11 @@ body {
background: #98bdef;
text-shadow: none; }
+::-moz-selection {
+ color: #fff;
+ background: #98bdef;
+ text-shadow: none; }
+
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
diff --git a/demo.html b/demo.html
index ed777cf..36ad224 100644
--- a/demo.html
+++ b/demo.html
@@ -48,32 +48,11 @@
</p>
</section>
- <section data-background-color="#888">
+ <section>
<h2>Hello There</h2>
<p>
reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do.
</p>
- <p>
- reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do.
- </p>
- <p>
- reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do.
- </p>
- <p>
- reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do.
- </p>
- <p>
- reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do.
- </p>
- <p>
- reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do.
- </p>
- <p>
- reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do.
- </p>
- <p>
- reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do. ---
- </p>
</section>
<!-- Example of nested vertical slides -->
@@ -346,7 +325,7 @@ function linkify( selector ) {
<section>
<h2>Export to PDF</h2>
<p>Presentations can be <a href="https://github.com/hakimel/reveal.js#pdf-export">exported to PDF</a>, here's an example:</p>
- <iframe src="https://www.slideshare.net/slideshow/embed_code/42840540" width="445" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:3px solid #666; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe>
+ <iframe data-src="https://www.slideshare.net/slideshow/embed_code/42840540" width="445" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:3px solid #666; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe>
</section>
<section>
diff --git a/js/reveal.js b/js/reveal.js
index 575214e..656ed10 100644
--- a/js/reveal.js
+++ b/js/reveal.js
@@ -26,12 +26,13 @@
var Reveal;
// The reveal.js version
- var VERSION = '3.2.0';
+ var VERSION = '3.3.0';
var SLIDES_SELECTOR = '.slides section',
HORIZONTAL_SLIDES_SELECTOR = '.slides>section',
VERTICAL_SLIDES_SELECTOR = '.slides>section.present>section',
HOME_SLIDE_SELECTOR = '.slides>section:first-of-type',
+ UA = navigator.userAgent,
// Configuration defaults, can be overridden at initialization time
config = {
@@ -152,6 +153,10 @@
parallaxBackgroundHorizontal: null,
parallaxBackgroundVertical: null,
+ // The maximum number of pages a single slide can expand onto when printing
+ // to PDF, unlimited by default
+ pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY,
+
// Number of slides away from the current that are visible
viewDistance: 3,
@@ -166,6 +171,10 @@
// Flags if the overview mode is currently active
overview = false,
+ // Holds the dimensions of our overview slides, including margins
+ overviewSlideWidth = null,
+ overviewSlideHeight = null,
+
// The horizontal and vertical index of the currently active slide
indexh,
indexv,
@@ -197,6 +206,9 @@
// Client is a mobile device, see #checkCapabilities()
isMobileDevice,
+ // Client is a desktop Chrome, see #checkCapabilities()
+ isChrome,
+
// Throttles mouse wheel navigation
lastMouseWheelStep = 0,
@@ -301,7 +313,8 @@
*/
function checkCapabilities() {
- isMobileDevice = /(iphone|ipod|ipad|android)/gi.test( navigator.userAgent );
+ isMobileDevice = /(iphone|ipod|ipad|android)/gi.test( UA );
+ isChrome = /chrome/i.test( UA ) && !/edge/i.test( UA );
var testElement = document.createElement( 'div' );
@@ -324,13 +337,13 @@
// Transitions in the overview are disabled in desktop and
// Safari due to lag
- features.overviewTransitions = !/Version\/[\d\.]+.*Safari/.test( navigator.userAgent );
+ features.overviewTransitions = !/Version\/[\d\.]+.*Safari/.test( UA );
// Flags if we should use zoom instead of transform to scale
// up slides. Zoom produces crisper results but has a lot of
// xbrowser quirks so we only use it in whitelsited browsers.
features.zoom = 'zoom' in testElement.style && !isMobileDevice &&
- ( /chrome/i.test( navigator.userAgent ) || /Version\/[\d\.]+.*Safari/.test( navigator.userAgent ) );
+ ( isChrome || /Version\/[\d\.]+.*Safari/.test( UA ) );
}
@@ -410,8 +423,8 @@
// Listen to messages posted to this window
setupPostMessage();
- // Prevent iframes from scrolling the slides out of view
- setupIframeScrollPrevention();
+ // Prevent the slides from being scrolled out of view
+ setupScrollPrevention();
// Resets all vertical slides so that only the first is visible
resetVerticalSlides();
@@ -486,6 +499,7 @@
// Element containing notes that are visible to the audience
dom.speakerNotes = createSingletonNode( dom.wrapper, 'div', 'speaker-notes', null );
dom.speakerNotes.setAttribute( 'data-prevent-swipe', '' );
+ dom.speakerNotes.setAttribute( 'tabindex', '0' );
// Overlay graphic which is displayed during the paused mode
createSingletonNode( dom.wrapper, 'div', 'pause-overlay', null );
@@ -580,27 +594,32 @@
var left = ( pageWidth - slideWidth ) / 2,
top = ( pageHeight - slideHeight ) / 2;
- var contentHeight = getAbsoluteHeight( slide );
+ var contentHeight = slide.scrollHeight;
var numberOfPages = Math.max( Math.ceil( contentHeight / pageHeight ), 1 );
+ // Adhere to configured pages per slide limit
+ numberOfPages = Math.min( numberOfPages, config.pdfMaxPagesPerSlide );
+
// Center slides vertically
if( numberOfPages === 1 && config.center || slide.classList.contains( 'center' ) ) {
top = Math.max( ( pageHeight - contentHeight ) / 2, 0 );
}
+ // Wrap the slide in a page element and hide its overflow
+ // so that no page ever flows onto another
+ var page = document.createElement( 'div' );
+ page.className = 'pdf-page';
+ page.style.height = ( pageHeight * numberOfPages ) + 'px';
+ slide.parentNode.insertBefore( page, slide );
+ page.appendChild( slide );
+
// Position the slide inside of the page
slide.style.left = left + 'px';
slide.style.top = top + 'px';
slide.style.width = slideWidth + 'px';
- // TODO Backgrounds need to be multiplied when the slide
- // stretches over multiple pages
- var background = slide.querySelector( '.slide-background' );
- if( background ) {
- background.style.width = pageWidth + 'px';
- background.style.height = ( pageHeight * numberOfPages ) + 'px';
- background.style.top = -top + 'px';
- background.style.left = -left + 'px';
+ if( slide.slideBackgroundElement ) {
+ page.insertBefore( slide.slideBackgroundElement, slide );
}
// Inject notes if `showNotes` is enabled
@@ -628,7 +647,7 @@
numberElement.classList.add( 'slide-number' );
numberElement.classList.add( 'slide-number-pdf' );
numberElement.innerHTML = formatSlideNumber( slideNumberH, '.', slideNumberV );
- background.appendChild( numberElement );
+ page.appendChild( numberElement );
}
}
@@ -642,22 +661,22 @@
}
/**
- * This is an unfortunate necessity. Iframes can trigger the
- * parent window to scroll, for example by focusing an input.
+ * This is an unfortunate necessity. Some actions – such as
+ * an input field being focused in an iframe or using the
+ * keyboard to expand text selection beyond the bounds of
+ * a slide – can trigger our content to be pushed out of view.
* This scrolling can not be prevented by hiding overflow in
- * CSS so we have to resort to repeatedly checking if the
- * browser has decided to offset our slides :(
+ * CSS (we already do) so we have to resort to repeatedly
+ * checking if the slides have been offset :(
*/
- function setupIframeScrollPrevention() {
+ function setupScrollPrevention() {
- if( dom.slides.querySelector( 'iframe' ) ) {
- setInterval( function() {
- if( dom.wrapper.scrollTop !== 0 || dom.wrapper.scrollLeft !== 0 ) {
- dom.wrapper.scrollTop = 0;
- dom.wrapper.scrollLeft = 0;
- }
- }, 500 );
- }
+ setInterval( function() {
+ if( dom.wrapper.scrollTop !== 0 || dom.wrapper.scrollLeft !== 0 ) {
+ dom.wrapper.scrollTop = 0;
+ dom.wrapper.scrollLeft = 0;
+ }
+ }, 1000 );
}
@@ -708,24 +727,12 @@
// Iterate over all horizontal slides
toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).forEach( function( slideh ) {
- var backgroundStack;
-
- if( printMode ) {
- backgroundStack = createBackground( slideh, slideh );
- }
- else {
- backgroundStack = createBackground( slideh, dom.background );
- }
+ var backgroundStack = createBackground( slideh, dom.background );
// Iterate over all vertical slides
toArray( slideh.querySelectorAll( 'section' ) ).forEach( function( slidev ) {
- if( printMode ) {
- createBackground( slidev, slidev );
- }
- else {
- createBackground( slidev, backgroundStack );
- }
+ createBackground( slidev, backgroundStack );
backgroundStack.classList.add( 'stack' );
@@ -821,6 +828,8 @@
slide.classList.remove( 'has-dark-background' );
slide.classList.remove( 'has-light-background' );
+ slide.slideBackgroundElement = element;
+
// If this slide has a background color, add a class that
// signals if it is light or dark. If the slide has no background
// color, no class will be set
@@ -1048,7 +1057,7 @@
// Only support touch for Android, fixes double navigations in
// stock browser
- if( navigator.userAgent.match( /android/gi ) ) {
+ if( UA.match( /android/gi ) ) {
pointerEvents = [ 'touchstart' ];
}
@@ -1282,41 +1291,6 @@
}
/**
- * Retrieves the height of the given element by looking
- * at the position and height of its immediate children.
- */
- function getAbsoluteHeight( element ) {
-
- var height = 0;
-
- if( element ) {
- var absoluteChildren = 0;
-
- toArray( element.childNodes ).forEach( function( child ) {
-
- if( typeof child.offsetTop === 'number' && child.style ) {
- // Count # of abs children
- if( window.getComputedStyle( child ).position === 'absolute' ) {
- absoluteChildren += 1;
- }
-
- height = Math.max( height, child.offsetTop + child.offsetHeight );
- }
-
- } );
-
- // If there are no absolute children, use offsetHeight
- if( absoluteChildren === 0 ) {
- height = element.offsetHeight;
- }
-
- }
-
- return height;
-
- }
-
- /**
* Returns the remaining height within the parent of the
* target element.
*
@@ -1580,10 +1554,8 @@
var size = getComputedSlideSize();
- var slidePadding = 20; // TODO Dig this out of DOM
-
// Layout the contents of the slides
- layoutSlideContents( config.width, config.height, slidePadding );
+ layoutSlideContents( config.width, config.height );
dom.slides.style.width = size.width + 'px';
dom.slides.style.height = size.height + 'px';
@@ -1645,7 +1617,7 @@
slide.style.top = 0;
}
else {
- slide.style.top = Math.max( ( ( size.height - getAbsoluteHeight( slide ) ) / 2 ) - slidePadding, 0 ) + 'px';
+ slide.style.top = Math.max( ( size.height - slide.scrollHeight ) / 2, 0 ) + 'px';
}
}
else {
@@ -1665,7 +1637,7 @@
* Applies layout logic to the contents of all slides in
* the presentation.
*/
- function layoutSlideContents( width, height, padding ) {
+ function layoutSlideContents( width, height ) {
// Handle sizing of elements with the 'stretch' class
toArray( dom.slides.querySelectorAll( 'section > .stretch' ) ).forEach( function( element ) {
@@ -1798,6 +1770,17 @@
}
} );
+ // Calculate slide sizes
+ var margin = 70;
+ var slideSize = getComputedSlideSize();
+ overviewSlideWidth = slideSize.width + margin;
+ overviewSlideHeight = slideSize.height + margin;
+
+ // Reverse in RTL mode
+ if( config.rtl ) {
+ overviewSlideWidth = -overviewSlideWidth;
+ }
+
updateSlidesVisibility();
layoutOverview();
updateOverview();
@@ -1821,19 +1804,10 @@
*/
function layoutOverview() {
- var margin = 70;
- var slideWidth = config.width + margin,
- slideHeight = config.height + margin;
-
- // Reverse in RTL mode
- if( config.rtl ) {
- slideWidth = -slideWidth;
- }
-
// Layout slides
toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).forEach( function( hslide, h ) {
hslide.setAttribute( 'data-index-h', h );
- transformElement( hslide, 'translate3d(' + ( h * slideWidth ) + 'px, 0, 0)' );
+ transformElement( hslide, 'translate3d(' + ( h * overviewSlideWidth ) + 'px, 0, 0)' );
if( hslide.classList.contains( 'stack' ) ) {
@@ -1841,7 +1815,7 @@
vslide.setAttribute( 'data-index-h', h );
vslide.setAttribute( 'data-index-v', v );
- transformElement( vslide, 'translate3d(0, ' + ( v * slideHeight ) + 'px, 0)' );
+ transformElement( vslide, 'translate3d(0, ' + ( v * overviewSlideHeight ) + 'px, 0)' );
} );
}
@@ -1849,10 +1823,10 @@
// Layout slide backgrounds
toArray( dom.background.childNodes ).forEach( function( hbackground, h ) {
- transformElement( hbackground, 'translate3d(' + ( h * slideWidth ) + 'px, 0, 0)' );
+ transformElement( hbackground, 'translate3d(' + ( h * overviewSlideWidth ) + 'px, 0, 0)' );
toArray( hbackground.querySelectorAll( '.slide-background' ) ).forEach( function( vbackground, v ) {
- transformElement( vbackground, 'translate3d(0, ' + ( v * slideHeight ) + 'px, 0)' );
+ transformElement( vbackground, 'translate3d(0, ' + ( v * overviewSlideHeight ) + 'px, 0)' );
} );
} );
@@ -1864,19 +1838,10 @@
*/
function updateOverview() {
- var margin = 70;
- var slideWidth = config.width + margin,
- slideHeight = config.height + margin;
-
- // Reverse in RTL mode
- if( config.rtl ) {
- slideWidth = -slideWidth;
- }
-
transformSlides( {
overview: [
- 'translateX('+ ( -indexh * slideWidth ) +'px)',
- 'translateY('+ ( -indexv * slideHeight ) +'px)',
+ 'translateX('+ ( -indexh * overviewSlideWidth ) +'px)',
+ 'translateY('+ ( -indexv * overviewSlideHeight ) +'px)',
'translateZ('+ ( window.innerWidth < 400 ? -1000 : -2500 ) +'px)'
].join( ' ' )
} );
@@ -2650,34 +2615,37 @@
.concat( dom.controlsNext ).forEach( function( node ) {
node.classList.remove( 'enabled' );
node.classList.remove( 'fragmented' );
+
+ // Set 'disabled' attribute on all directions
+ node.setAttribute( 'disabled', 'disabled' );
} );
- // Add the 'enabled' class to the available routes
- if( routes.left ) dom.controlsLeft.forEach( function( el ) { el.classList.add( 'enabled' ); } );
- if( routes.right ) dom.controlsRight.forEach( function( el ) { el.classList.add( 'enabled' ); } );
- if( routes.up ) dom.controlsUp.forEach( function( el ) { el.classList.add( 'enabled' ); } );
- if( routes.down ) dom.controlsDown.forEach( function( el ) { el.classList.add( 'enabled' ); } );
+ // Add the 'enabled' class to the available routes; remove 'disabled' attribute to enable buttons
+ if( routes.left ) dom.controlsLeft.forEach( function( el ) { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
+ if( routes.right ) dom.controlsRight.forEach( function( el ) { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
+ if( routes.up ) dom.controlsUp.forEach( function( el ) { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
+ if( routes.down ) dom.controlsDown.forEach( function( el ) { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
// Prev/next buttons
- if( routes.left || routes.up ) dom.controlsPrev.forEach( function( el ) { el.classList.add( 'enabled' ); } );
- if( routes.right || routes.down ) dom.controlsNext.forEach( function( el ) { el.classList.add( 'enabled' ); } );
+ if( routes.left || routes.up ) dom.controlsPrev.forEach( function( el ) { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
+ if( routes.right || routes.down ) dom.controlsNext.forEach( function( el ) { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );
// Highlight fragment directions
if( currentSlide ) {
// Always apply fragment decorator to prev/next buttons
- if( fragments.prev ) dom.controlsPrev.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
- if( fragments.next ) dom.controlsNext.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
+ if( fragments.prev ) dom.controlsPrev.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
+ if( fragments.next ) dom.controlsNext.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
// Apply fragment decorators to directional buttons based on
// what slide axis they are in
if( isVerticalSlide( currentSlide ) ) {
- if( fragments.prev ) dom.controlsUp.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
- if( fragments.next ) dom.controlsDown.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
+ if( fragments.prev ) dom.controlsUp.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
+ if( fragments.next ) dom.controlsDown.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
}
else {
- if( fragments.prev ) dom.controlsLeft.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
- if( fragments.next ) dom.controlsRight.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
+ if( fragments.prev ) dom.controlsLeft.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
+ if( fragments.next ) dom.controlsRight.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );
}
}
@@ -3425,10 +3393,7 @@
if( isPrintingPDF() ) {
var slide = getSlide( x, y );
if( slide ) {
- var background = slide.querySelector( '.slide-background' );
- if( background && background.parentNode === slide ) {
- return background;
- }
+ return slide.slideBackgroundElement;
}
return undefined;
@@ -3961,10 +3926,11 @@
// 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);
// Disregard the event if there's a focused element or a
// keyboard modifier key is present
- if( activeElementIsCE || activeElementIsInput || (event.shiftKey && event.keyCode !== 32) || event.altKey || event.ctrlKey || event.metaKey ) return;
+ if( activeElementIsCE || activeElementIsInput || activeElementIsNotes || (event.shiftKey && event.keyCode !== 32) || event.altKey || event.ctrlKey || event.metaKey ) return;
// While paused only allow resume keyboard events; 'b', '.''
var resumeKeyCodes = [66,190,191];
@@ -4183,7 +4149,7 @@
}
// There's a bug with swiping on some Android devices unless
// the default action is always prevented
- else if( navigator.userAgent.match( /android/gi ) ) {
+ else if( UA.match( /android/gi ) ) {
event.preventDefault();
}
diff --git a/lib/js/head.min.js b/lib/js/head.min.js
index 6242b0f..d9f87ba 100644
--- a/lib/js/head.min.js
+++ b/lib/js/head.min.js
@@ -1,8 +1,9 @@
-/**
- Head JS The only script in your <HEAD>
- Copyright Tero Piirainen (tipiirai)
- License MIT / http://bit.ly/mit-license
- Version 0.96
-
- http://headjs.com
-*/(function(a){function z(){d||(d=!0,s(e,function(a){p(a)}))}function y(c,d){var e=a.createElement("script");e.type="text/"+(c.type||"javascript"),e.src=c.src||c,e.async=!1,e.onreadystatechange=e.onload=function(){var a=e.readyState;!d.done&&(!a||/loaded|complete/.test(a))&&(d.done=!0,d())},(a.body||b).appendChild(e)}function x(a,b){if(a.state==o)return b&&b();if(a.state==n)return k.ready(a.name,b);if(a.state==m)return a.onpreload.push(function(){x(a,b)});a.state=n,y(a.url,function(){a.state=o,b&&b(),s(g[a.name],function(a){p(a)}),u()&&d&&s(g.ALL,function(a){p(a)})})}function w(a,b){a.state===undefined&&(a.state=m,a.onpreload=[],y({src:a.url,type:"cache"},function(){v(a)}))}function v(a){a.state=l,s(a.onpreload,function(a){a.call()})}function u(a){a=a||h;var b;for(var c in a){if(a.hasOwnProperty(c)&&a[c].state!=o)return!1;b=!0}return b}function t(a){return Object.prototype.toString.call(a)=="[object Function]"}function s(a,b){if(!!a){typeof a=="object"&&(a=[].slice.call(a));for(var c=0;c<a.length;c++)b.call(a,a[c],c)}}function r(a){var b;if(typeof a=="object")for(var c in a)a[c]&&(b={name:c,url:a[c]});else b={name:q(a),url:a};var d=h[b.name];if(d&&d.url===b.url)return d;h[b.name]=b;return b}function q(a){var b=a.split("/"),c=b[b.length-1],d=c.indexOf("?");return d!=-1?c.substring(0,d):c}function p(a){a._done||(a(),a._done=1)}var b=a.documentElement,c,d,e=[],f=[],g={},h={},i=a.createElement("script").async===!0||"MozAppearance"in a.documentElement.style||window.opera,j=window.head_conf&&head_conf.head||"head",k=window[j]=window[j]||function(){k.ready.apply(null,arguments)},l=1,m=2,n=3,o=4;i?k.js=function(){var a=arguments,b=a[a.length-1],c={};t(b)||(b=null),s(a,function(d,e){d!=b&&(d=r(d),c[d.name]=d,x(d,b&&e==a.length-2?function(){u(c)&&p(b)}:null))});return k}:k.js=function(){var a=arguments,b=[].slice.call(a,1),d=b[0];if(!c){f.push(function(){k.js.apply(null,a)});return k}d?(s(b,function(a){t(a)||w(r(a))}),x(r(a[0]),t(d)?d:function(){k.js.apply(null,b)})):x(r(a[0]));return k},k.ready=function(b,c){if(b==a){d?p(c):e.push(c);return k}t(b)&&(c=b,b="ALL");if(typeof b!="string"||!t(c))return k;var f=h[b];if(f&&f.state==o||b=="ALL"&&u()&&d){p(c);return k}var i=g[b];i?i.push(c):i=g[b]=[c];return k},k.ready(a,function(){u()&&s(g.ALL,function(a){p(a)}),k.feature&&k.feature("domloaded",!0)});if(window.addEventListener)a.addEventListener("DOMContentLoaded",z,!1),window.addEventListener("load",z,!1);else if(window.attachEvent){a.attachEvent("onreadystatechange",function(){a.readyState==="complete"&&z()});var A=1;try{A=window.frameElement}catch(B){}!A&&b.doScroll&&function(){try{b.doScroll("left"),z()}catch(a){setTimeout(arguments.callee,1);return}}(),window.attachEvent("onload",z)}!a.readyState&&a.addEventListener&&(a.readyState="loading",a.addEventListener("DOMContentLoaded",handler=function(){a.removeEventListener("DOMContentLoaded",handler,!1),a.readyState="complete"},!1)),setTimeout(function(){c=!0,s(f,function(a){a()})},300)})(document) \ No newline at end of file
+/*! 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);
+/*
+//# sourceMappingURL=head.min.js.map
+*/ \ No newline at end of file
diff --git a/package.json b/package.json
index 043eac1..3135f35 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "reveal.js",
- "version": "3.2.0",
+ "version": "3.3.0",
"description": "The HTML Presentation Framework",
"homepage": "http://lab.hakim.se/reveal-js",
"subdomain": "revealjs",
diff --git a/plugin/multiplex/index.js b/plugin/multiplex/index.js
index 40c1661..8195f04 100644
--- a/plugin/multiplex/index.js
+++ b/plugin/multiplex/index.js
@@ -31,7 +31,15 @@ io.on( 'connection', function( socket ) {
app.get("/", function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
- fs.createReadStream(opts.baseDir + '/index.html').pipe(res);
+
+ var stream = fs.createReadStream(opts.baseDir + '/index.html');
+ stream.on('error', function( error ) {
+ res.write('<style>body{font-family: sans-serif;}</style><h2>reveal.js multiplex server.</h2><a href="/token">Generate token</a>');
+ res.end();
+ });
+ stream.on('readable', function() {
+ stream.pipe(res);
+ });
});
app.get("/token", function(req,res) {
diff --git a/plugin/multiplex/package.json b/plugin/multiplex/package.json
new file mode 100644
index 0000000..368bfd6
--- /dev/null
+++ b/plugin/multiplex/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "reveal-js-multiplex",
+ "version": "1.0.0",
+ "description": "reveal.js multiplex server",
+ "homepage": "http://lab.hakim.se/reveal-js",
+ "scripts": {
+ "start": "node index.js"
+ },
+ "engines": {
+ "node": "~4.1.1"
+ },
+ "dependencies": {
+ "express": "~4.13.3",
+ "grunt-cli": "~0.1.13",
+ "mustache": "~2.2.1",
+ "socket.io": "~1.3.7"
+ },
+ "license": "MIT"
+}
diff --git a/plugin/zoom-js/zoom.js b/plugin/zoom-js/zoom.js
index 95093e0..8738083 100644
--- a/plugin/zoom-js/zoom.js
+++ b/plugin/zoom-js/zoom.js
@@ -11,7 +11,17 @@
if( event[ modifier ] && isEnabled ) {
event.preventDefault();
- var bounds = event.target.getBoundingClientRect();
+ var bounds;
+ var originalDisplay = event.target.style.display;
+
+ // Get the bounding rect of the contents, not the containing box
+ if( window.getComputedStyle( event.target ).display === 'block' ) {
+ event.target.style.display = 'inline-block';
+ bounds = event.target.getBoundingClientRect();
+ event.target.style.display = originalDisplay;
+ } else {
+ bounds = event.target.getBoundingClientRect();
+ }
zoom.to({
x: ( bounds.left * revealScale ) - zoomPadding,