Browse Source

Merge branch 'dev' of github.com:hakimel/reveal.js

Hakim El Hattab 7 years ago
parent
commit
a144134b42

+ 16 - 5
Gruntfile.js

@@ -1,7 +1,9 @@
 /* global module:false */
 /* global module:false */
 module.exports = function(grunt) {
 module.exports = function(grunt) {
 	var port = grunt.option('port') || 8000;
 	var port = grunt.option('port') || 8000;
-	var base = grunt.option('base') || '.';
+	var root = grunt.option('root') || '.';
+
+	if (!Array.isArray(root)) root = [root];
 
 
 	// Project configuration
 	// Project configuration
 	grunt.initConfig({
 	grunt.initConfig({
@@ -69,6 +71,7 @@ module.exports = function(grunt) {
 				curly: false,
 				curly: false,
 				eqeqeq: true,
 				eqeqeq: true,
 				immed: true,
 				immed: true,
+				esnext: true,
 				latedef: true,
 				latedef: true,
 				newcap: true,
 				newcap: true,
 				noarg: true,
 				noarg: true,
@@ -93,11 +96,12 @@ module.exports = function(grunt) {
 			server: {
 			server: {
 				options: {
 				options: {
 					port: port,
 					port: port,
-					base: base,
+					base: root,
 					livereload: true,
 					livereload: true,
 					open: true
 					open: true
 				}
 				}
-			}
+			},
+
 		},
 		},
 
 
 		zip: {
 		zip: {
@@ -126,14 +130,20 @@ module.exports = function(grunt) {
 				tasks: 'css-core'
 				tasks: 'css-core'
 			},
 			},
 			html: {
 			html: {
-				files: [ '*.html']
+				files: root.map(path => path + '/*.html')
 			},
 			},
 			markdown: {
 			markdown: {
-				files: [ '*.md' ]
+				files: root.map(path => path + '/*.md')
 			},
 			},
 			options: {
 			options: {
 				livereload: true
 				livereload: true
 			}
 			}
+		},
+
+		retire: {
+			js: ['js/reveal.js', 'lib/js/*.js', 'plugin/**/*.js'],
+			node: ['.'],
+			options: {}
 		}
 		}
 
 
 	});
 	});
@@ -148,6 +158,7 @@ module.exports = function(grunt) {
 	grunt.loadNpmTasks( 'grunt-contrib-connect' );
 	grunt.loadNpmTasks( 'grunt-contrib-connect' );
 	grunt.loadNpmTasks( 'grunt-autoprefixer' );
 	grunt.loadNpmTasks( 'grunt-autoprefixer' );
 	grunt.loadNpmTasks( 'grunt-zip' );
 	grunt.loadNpmTasks( 'grunt-zip' );
+	grunt.loadNpmTasks( 'grunt-retire' );
 
 
 	// Default task
 	// Default task
 	grunt.registerTask( 'default', [ 'css', 'js' ] );
 	grunt.registerTask( 'default', [ 'css', 'js' ] );

+ 1 - 1
LICENSE

@@ -1,4 +1,4 @@
-Copyright (C) 2016 Hakim El Hattab, http://hakim.se
+Copyright (C) 2016 Hakim El Hattab, http://hakim.se, and reveal.js contributors
 
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 of this software and associated documentation files (the "Software"), to deal

File diff suppressed because it is too large
+ 29 - 8
README.md


+ 3 - 2
css/print/paper.css

@@ -38,7 +38,8 @@
 	.share-reveal,
 	.share-reveal,
 	.state-background,
 	.state-background,
 	.reveal .progress,
 	.reveal .progress,
-	.reveal .backgrounds {
+	.reveal .backgrounds,
+	.reveal .slide-number {
 		display: none !important;
 		display: none !important;
 	}
 	}
 
 
@@ -199,4 +200,4 @@
 		font-size: 0.8em;
 		font-size: 0.8em;
 	}
 	}
 
 
-}
+}

+ 22 - 12
css/print/pdf.css

@@ -60,8 +60,9 @@ ul, ol, div, p {
 }
 }
 .reveal .slides {
 .reveal .slides {
 	position: static;
 	position: static;
-	width: 100%;
-	height: auto;
+	width: 100% !important;
+	height: auto !important;
+	zoom: 1 !important;
 
 
 	left: auto;
 	left: auto;
 	top: auto;
 	top: auto;
@@ -82,11 +83,16 @@ ul, ol, div, p {
 	        perspective-origin: 50% 50%;
 	        perspective-origin: 50% 50%;
 }
 }
 
 
+.reveal .slides .pdf-page {
+	position: relative;
+	overflow: hidden;
+	z-index: 1;
+}
+
 .reveal .slides section {
 .reveal .slides section {
 	page-break-after: always !important;
 	page-break-after: always !important;
 
 
 	visibility: visible !important;
 	visibility: visible !important;
-	position: relative !important;
 	display: block !important;
 	display: block !important;
 	position: relative !important;
 	position: relative !important;
 
 
@@ -132,13 +138,7 @@ ul, ol, div, p {
 	top: 0;
 	top: 0;
 	left: 0;
 	left: 0;
 	width: 100%;
 	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 */
 /* Display slide speaker notes when 'showNotes' is enabled */
@@ -146,15 +146,25 @@ ul, ol, div, p {
 	display: block;
 	display: block;
 	width: 100%;
 	width: 100%;
 	max-height: none;
 	max-height: none;
-	left: auto;
 	top: auto;
 	top: auto;
+	right: auto;
+	bottom: auto;
+	left: auto;
 	z-index: 100;
 	z-index: 100;
 }
 }
 
 
+/* Layout option which makes notes appear on a separate page */
+.reveal .speaker-notes-pdf[data-layout="separate-page"] {
+	position: relative;
+	color: inherit;
+	background-color: transparent;
+	padding: 20px;
+	page-break-after: always;
+}
+
 /* Display slide numbers when 'slideNumber' is enabled */
 /* Display slide numbers when 'slideNumber' is enabled */
 .reveal .slide-number-pdf {
 .reveal .slide-number-pdf {
 	display: block;
 	display: block;
 	position: absolute;
 	position: absolute;
 	font-size: 14px;
 	font-size: 14px;
 }
 }
-

+ 54 - 14
css/reveal.css

@@ -57,18 +57,18 @@ body {
           transition: all .2s ease; }
           transition: all .2s ease; }
   .reveal .slides section .fragment.visible {
   .reveal .slides section .fragment.visible {
     opacity: 1;
     opacity: 1;
-    visibility: visible; }
+    visibility: inherit; }
 
 
 .reveal .slides section .fragment.grow {
 .reveal .slides section .fragment.grow {
   opacity: 1;
   opacity: 1;
-  visibility: visible; }
+  visibility: inherit; }
   .reveal .slides section .fragment.grow.visible {
   .reveal .slides section .fragment.grow.visible {
     -webkit-transform: scale(1.3);
     -webkit-transform: scale(1.3);
             transform: scale(1.3); }
             transform: scale(1.3); }
 
 
 .reveal .slides section .fragment.shrink {
 .reveal .slides section .fragment.shrink {
   opacity: 1;
   opacity: 1;
-  visibility: visible; }
+  visibility: inherit; }
   .reveal .slides section .fragment.shrink.visible {
   .reveal .slides section .fragment.shrink.visible {
     -webkit-transform: scale(0.7);
     -webkit-transform: scale(0.7);
             transform: scale(0.7); }
             transform: scale(0.7); }
@@ -82,21 +82,21 @@ body {
 
 
 .reveal .slides section .fragment.fade-out {
 .reveal .slides section .fragment.fade-out {
   opacity: 1;
   opacity: 1;
-  visibility: visible; }
+  visibility: inherit; }
   .reveal .slides section .fragment.fade-out.visible {
   .reveal .slides section .fragment.fade-out.visible {
     opacity: 0;
     opacity: 0;
     visibility: hidden; }
     visibility: hidden; }
 
 
 .reveal .slides section .fragment.semi-fade-out {
 .reveal .slides section .fragment.semi-fade-out {
   opacity: 1;
   opacity: 1;
-  visibility: visible; }
+  visibility: inherit; }
   .reveal .slides section .fragment.semi-fade-out.visible {
   .reveal .slides section .fragment.semi-fade-out.visible {
     opacity: 0.5;
     opacity: 0.5;
-    visibility: visible; }
+    visibility: inherit; }
 
 
 .reveal .slides section .fragment.strike {
 .reveal .slides section .fragment.strike {
   opacity: 1;
   opacity: 1;
-  visibility: visible; }
+  visibility: inherit; }
   .reveal .slides section .fragment.strike.visible {
   .reveal .slides section .fragment.strike.visible {
     text-decoration: line-through; }
     text-decoration: line-through; }
 
 
@@ -133,7 +133,7 @@ body {
   visibility: hidden; }
   visibility: hidden; }
   .reveal .slides section .fragment.current-visible.current-fragment {
   .reveal .slides section .fragment.current-visible.current-fragment {
     opacity: 1;
     opacity: 1;
-    visibility: visible; }
+    visibility: inherit; }
 
 
 .reveal .slides section .fragment.highlight-red,
 .reveal .slides section .fragment.highlight-red,
 .reveal .slides section .fragment.highlight-current-red,
 .reveal .slides section .fragment.highlight-current-red,
@@ -142,7 +142,7 @@ body {
 .reveal .slides section .fragment.highlight-blue,
 .reveal .slides section .fragment.highlight-blue,
 .reveal .slides section .fragment.highlight-current-blue {
 .reveal .slides section .fragment.highlight-current-blue {
   opacity: 1;
   opacity: 1;
-  visibility: visible; }
+  visibility: inherit; }
 
 
 .reveal .slides section .fragment.highlight-red.visible {
 .reveal .slides section .fragment.highlight-red.visible {
   color: #ff2c2d; }
   color: #ff2c2d; }
@@ -341,8 +341,8 @@ body {
   width: 100%;
   width: 100%;
   padding: 20px 0px;
   padding: 20px 0px;
   z-index: 10;
   z-index: 10;
-  -webkit-transform-style: preserve-3d;
-          transform-style: preserve-3d;
+  -webkit-transform-style: flat;
+          transform-style: flat;
   -webkit-transition: -webkit-transform-origin 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), -webkit-transform 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), visibility 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), opacity 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
   -webkit-transition: -webkit-transform-origin 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), -webkit-transform 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), visibility 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), opacity 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
           transition: transform-origin 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), transform 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), visibility 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), opacity 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }
           transition: transform-origin 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), transform 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), visibility 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), opacity 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }
 
 
@@ -463,6 +463,11 @@ body {
  * CONVEX TRANSITION
  * CONVEX TRANSITION
  * Aliased 'default' for backwards compatibility
  * Aliased 'default' for backwards compatibility
  *********************************************/
  *********************************************/
+.reveal .slides section[data-transition=default].stack,
+.reveal.default .slides section.stack {
+  -webkit-transform-style: preserve-3d;
+          transform-style: preserve-3d; }
+
 .reveal .slides > section[data-transition=default].past,
 .reveal .slides > section[data-transition=default].past,
 .reveal .slides > section[data-transition~=default-out].past,
 .reveal .slides > section[data-transition~=default-out].past,
 .reveal.default .slides > section:not([data-transition]).past {
 .reveal.default .slides > section:not([data-transition]).past {
@@ -487,6 +492,11 @@ body {
   -webkit-transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0);
   -webkit-transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0);
           transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); }
           transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); }
 
 
+.reveal .slides section[data-transition=convex].stack,
+.reveal.convex .slides section.stack {
+  -webkit-transform-style: preserve-3d;
+          transform-style: preserve-3d; }
+
 .reveal .slides > section[data-transition=convex].past,
 .reveal .slides > section[data-transition=convex].past,
 .reveal .slides > section[data-transition~=convex-out].past,
 .reveal .slides > section[data-transition~=convex-out].past,
 .reveal.convex .slides > section:not([data-transition]).past {
 .reveal.convex .slides > section:not([data-transition]).past {
@@ -514,6 +524,11 @@ body {
 /*********************************************
 /*********************************************
  * CONCAVE TRANSITION
  * CONCAVE TRANSITION
  *********************************************/
  *********************************************/
+.reveal .slides section[data-transition=concave].stack,
+.reveal.concave .slides section.stack {
+  -webkit-transform-style: preserve-3d;
+          transform-style: preserve-3d; }
+
 .reveal .slides > section[data-transition=concave].past,
 .reveal .slides > section[data-transition=concave].past,
 .reveal .slides > section[data-transition~=concave-out].past,
 .reveal .slides > section[data-transition~=concave-out].past,
 .reveal.concave .slides > section:not([data-transition]).past {
 .reveal.concave .slides > section:not([data-transition]).past {
@@ -584,7 +599,9 @@ body {
   min-height: 700px;
   min-height: 700px;
   -webkit-backface-visibility: hidden;
   -webkit-backface-visibility: hidden;
           backface-visibility: hidden;
           backface-visibility: hidden;
-  box-sizing: border-box; }
+  box-sizing: border-box;
+  -webkit-transform-style: preserve-3d;
+          transform-style: preserve-3d; }
 
 
 .reveal.center.cube .slides section {
 .reveal.center.cube .slides section {
   min-height: 0; }
   min-height: 0; }
@@ -657,7 +674,9 @@ body {
 .reveal.page .slides section {
 .reveal.page .slides section {
   padding: 30px;
   padding: 30px;
   min-height: 700px;
   min-height: 700px;
-  box-sizing: border-box; }
+  box-sizing: border-box;
+  -webkit-transform-style: preserve-3d;
+          transform-style: preserve-3d; }
 
 
 .reveal.page .slides section.past {
 .reveal.page .slides section.past {
   z-index: 12; }
   z-index: 12; }
@@ -982,6 +1001,8 @@ body {
           perspective-origin: 50% 50%;
           perspective-origin: 50% 50%;
   -webkit-perspective: 700px;
   -webkit-perspective: 700px;
           perspective: 700px; }
           perspective: 700px; }
+  .reveal.overview .slides {
+    -moz-transform-style: preserve-3d; }
   .reveal.overview .slides section {
   .reveal.overview .slides section {
     height: 100%;
     height: 100%;
     top: 0 !important;
     top: 0 !important;
@@ -1009,7 +1030,8 @@ body {
     overflow: visible; }
     overflow: visible; }
   .reveal.overview .backgrounds {
   .reveal.overview .backgrounds {
     -webkit-perspective: inherit;
     -webkit-perspective: inherit;
-            perspective: inherit; }
+            perspective: inherit;
+    -moz-transform-style: preserve-3d; }
   .reveal.overview .backgrounds .slide-background {
   .reveal.overview .backgrounds .slide-background {
     opacity: 1;
     opacity: 1;
     visibility: visible;
     visibility: visible;
@@ -1118,6 +1140,7 @@ body {
   display: inline-block;
   display: inline-block;
   width: 40px;
   width: 40px;
   height: 40px;
   height: 40px;
+  line-height: 36px;
   padding: 0 10px;
   padding: 0 10px;
   float: right;
   float: right;
   opacity: 0.6;
   opacity: 0.6;
@@ -1166,6 +1189,23 @@ body {
   opacity: 1;
   opacity: 1;
   visibility: visible; }
   visibility: visible; }
 
 
+.reveal .overlay.overlay-preview.loaded .viewport-inner {
+  position: absolute;
+  z-index: -1;
+  left: 0;
+  top: 45%;
+  width: 100%;
+  text-align: center;
+  letter-spacing: normal; }
+
+.reveal .overlay.overlay-preview .x-frame-error {
+  opacity: 0;
+  -webkit-transition: opacity 0.3s ease 0.3s;
+          transition: opacity 0.3s ease 0.3s; }
+
+.reveal .overlay.overlay-preview.loaded .x-frame-error {
+  opacity: 1; }
+
 .reveal .overlay.overlay-preview.loaded .spinner {
 .reveal .overlay.overlay-preview.loaded .spinner {
   opacity: 0;
   opacity: 0;
   visibility: hidden;
   visibility: hidden;

+ 54 - 10
css/reveal.scss

@@ -69,13 +69,13 @@ body {
 
 
 	&.visible {
 	&.visible {
 		opacity: 1;
 		opacity: 1;
-		visibility: visible;
+		visibility: inherit;
 	}
 	}
 }
 }
 
 
 .reveal .slides section .fragment.grow {
 .reveal .slides section .fragment.grow {
 	opacity: 1;
 	opacity: 1;
-	visibility: visible;
+	visibility: inherit;
 
 
 	&.visible {
 	&.visible {
 		transform: scale( 1.3 );
 		transform: scale( 1.3 );
@@ -84,7 +84,7 @@ body {
 
 
 .reveal .slides section .fragment.shrink {
 .reveal .slides section .fragment.shrink {
 	opacity: 1;
 	opacity: 1;
-	visibility: visible;
+	visibility: inherit;
 
 
 	&.visible {
 	&.visible {
 		transform: scale( 0.7 );
 		transform: scale( 0.7 );
@@ -101,7 +101,7 @@ body {
 
 
 .reveal .slides section .fragment.fade-out {
 .reveal .slides section .fragment.fade-out {
 	opacity: 1;
 	opacity: 1;
-	visibility: visible;
+	visibility: inherit;
 
 
 	&.visible {
 	&.visible {
 		opacity: 0;
 		opacity: 0;
@@ -111,17 +111,17 @@ body {
 
 
 .reveal .slides section .fragment.semi-fade-out {
 .reveal .slides section .fragment.semi-fade-out {
 	opacity: 1;
 	opacity: 1;
-	visibility: visible;
+	visibility: inherit;
 
 
 	&.visible {
 	&.visible {
 		opacity: 0.5;
 		opacity: 0.5;
-		visibility: visible;
+		visibility: inherit;
 	}
 	}
 }
 }
 
 
 .reveal .slides section .fragment.strike {
 .reveal .slides section .fragment.strike {
 	opacity: 1;
 	opacity: 1;
-	visibility: visible;
+	visibility: inherit;
 
 
 	&.visible {
 	&.visible {
 		text-decoration: line-through;
 		text-decoration: line-through;
@@ -166,7 +166,7 @@ body {
 
 
 	&.current-fragment {
 	&.current-fragment {
 		opacity: 1;
 		opacity: 1;
-		visibility: visible;
+		visibility: inherit;
 	}
 	}
 }
 }
 
 
@@ -177,7 +177,7 @@ body {
 .reveal .slides section .fragment.highlight-blue,
 .reveal .slides section .fragment.highlight-blue,
 .reveal .slides section .fragment.highlight-current-blue {
 .reveal .slides section .fragment.highlight-current-blue {
 	opacity: 1;
 	opacity: 1;
-	visibility: visible;
+	visibility: inherit;
 }
 }
 	.reveal .slides section .fragment.highlight-red.visible {
 	.reveal .slides section .fragment.highlight-red.visible {
 		color: #ff2c2d
 		color: #ff2c2d
@@ -408,7 +408,7 @@ body {
 	padding: 20px 0px;
 	padding: 20px 0px;
 
 
 	z-index: 10;
 	z-index: 10;
-	transform-style: preserve-3d;
+	transform-style: flat;
 	transition: transform-origin 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985),
 	transition: transform-origin 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985),
 				transform 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985),
 				transform 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985),
 				visibility 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985),
 				visibility 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985),
@@ -480,6 +480,12 @@ body {
 		@content;
 		@content;
 	}
 	}
 }
 }
+@mixin transition-stack($style) {
+	.reveal .slides section[data-transition=#{$style}].stack,
+	.reveal.#{$style} .slides section.stack {
+		@content;
+	}
+}
 @mixin transition-horizontal-past($style) {
 @mixin transition-horizontal-past($style) {
 	.reveal .slides>section[data-transition=#{$style}].past,
 	.reveal .slides>section[data-transition=#{$style}].past,
 	.reveal .slides>section[data-transition~=#{$style}-out].past,
 	.reveal .slides>section[data-transition~=#{$style}-out].past,
@@ -539,6 +545,10 @@ body {
  *********************************************/
  *********************************************/
 
 
 @each $stylename in default, convex {
 @each $stylename in default, convex {
+	@include transition-stack(#{$stylename}) {
+		transform-style: preserve-3d;
+	}
+
 	@include transition-horizontal-past(#{$stylename}) {
 	@include transition-horizontal-past(#{$stylename}) {
 		transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0);
 		transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0);
 	}
 	}
@@ -557,6 +567,10 @@ body {
  * CONCAVE TRANSITION
  * CONCAVE TRANSITION
  *********************************************/
  *********************************************/
 
 
+@include transition-stack(concave) {
+	transform-style: preserve-3d;
+}
+
 @include transition-horizontal-past(concave) {
 @include transition-horizontal-past(concave) {
 	transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0);
 	transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0);
 }
 }
@@ -607,6 +621,7 @@ body {
 	min-height: 700px;
 	min-height: 700px;
 	backface-visibility: hidden;
 	backface-visibility: hidden;
 	box-sizing: border-box;
 	box-sizing: border-box;
+	transform-style: preserve-3d;
 }
 }
 	.reveal.center.cube .slides section {
 	.reveal.center.cube .slides section {
 		min-height: 0;
 		min-height: 0;
@@ -678,6 +693,7 @@ body {
 	padding: 30px;
 	padding: 30px;
 	min-height: 700px;
 	min-height: 700px;
 	box-sizing: border-box;
 	box-sizing: border-box;
+	transform-style: preserve-3d;
 }
 }
 	.reveal.page .slides section.past {
 	.reveal.page .slides section.past {
 		z-index: 12;
 		z-index: 12;
@@ -1012,6 +1028,12 @@ body {
 	perspective-origin: 50% 50%;
 	perspective-origin: 50% 50%;
 	perspective: 700px;
 	perspective: 700px;
 
 
+	.slides {
+		// Fixes overview rendering errors in FF48+, not applied to
+		// other browsers since it degrades performance
+		-moz-transform-style: preserve-3d;
+	}
+
 	.slides section {
 	.slides section {
 		height: 100%;
 		height: 100%;
 		top: 0 !important;
 		top: 0 !important;
@@ -1044,6 +1066,10 @@ body {
 
 
 	.backgrounds {
 	.backgrounds {
 		perspective: inherit;
 		perspective: inherit;
+
+		// Fixes overview rendering errors in FF48+, not applied to
+		// other browsers since it degrades performance
+		-moz-transform-style: preserve-3d;
 	}
 	}
 
 
 	.backgrounds .slide-background {
 	.backgrounds .slide-background {
@@ -1169,6 +1195,7 @@ body {
 			display: inline-block;
 			display: inline-block;
 			width: 40px;
 			width: 40px;
 			height: 40px;
 			height: 40px;
+			line-height: 36px;
 			padding: 0 10px;
 			padding: 0 10px;
 			float: right;
 			float: right;
 			opacity: 0.6;
 			opacity: 0.6;
@@ -1220,6 +1247,23 @@ body {
 		visibility: visible;
 		visibility: visible;
 	}
 	}
 
 
+	.reveal .overlay.overlay-preview.loaded .viewport-inner  {
+		position: absolute;
+		z-index: -1;
+		left: 0;
+		top: 45%;
+		width: 100%;
+		text-align: center;
+		letter-spacing: normal;
+	}
+	.reveal .overlay.overlay-preview .x-frame-error  {
+		opacity: 0;
+		transition: opacity 0.3s ease 0.3s;
+	}
+	.reveal .overlay.overlay-preview.loaded .x-frame-error  {
+		opacity: 1;
+	}
+
 	.reveal .overlay.overlay-preview.loaded .spinner {
 	.reveal .overlay.overlay-preview.loaded .spinner {
 		opacity: 0;
 		opacity: 0;
 		visibility: hidden;
 		visibility: hidden;

+ 6 - 1
css/theme/beige.css

@@ -20,7 +20,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Lato", sans-serif;
   font-family: "Lato", sans-serif;
-  font-size: 36px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #333; }
   color: #333; }
 
 
@@ -29,6 +29,11 @@ body {
   background: rgba(79, 64, 28, 0.99);
   background: rgba(79, 64, 28, 0.99);
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: rgba(79, 64, 28, 0.99);
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 6 - 1
css/theme/black.css

@@ -16,7 +16,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Source Sans Pro", Helvetica, sans-serif;
   font-family: "Source Sans Pro", Helvetica, sans-serif;
-  font-size: 38px;
+  font-size: 42px;
   font-weight: normal;
   font-weight: normal;
   color: #fff; }
   color: #fff; }
 
 
@@ -25,6 +25,11 @@ body {
   background: #bee4fd;
   background: #bee4fd;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #bee4fd;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 6 - 1
css/theme/blood.css

@@ -19,7 +19,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: Ubuntu, "sans-serif";
   font-family: Ubuntu, "sans-serif";
-  font-size: 36px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #eee; }
   color: #eee; }
 
 
@@ -28,6 +28,11 @@ body {
   background: #a23;
   background: #a23;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #a23;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 6 - 1
css/theme/league.css

@@ -22,7 +22,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Lato", sans-serif;
   font-family: "Lato", sans-serif;
-  font-size: 36px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #eee; }
   color: #eee; }
 
 
@@ -31,6 +31,11 @@ body {
   background: #FF5E99;
   background: #FF5E99;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #FF5E99;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 6 - 1
css/theme/moon.css

@@ -20,7 +20,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Lato", sans-serif;
   font-family: "Lato", sans-serif;
-  font-size: 36px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #93a1a1; }
   color: #93a1a1; }
 
 
@@ -29,6 +29,11 @@ body {
   background: #d33682;
   background: #d33682;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #d33682;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 6 - 1
css/theme/night.css

@@ -14,7 +14,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Open Sans", sans-serif;
   font-family: "Open Sans", sans-serif;
-  font-size: 30px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #eee; }
   color: #eee; }
 
 
@@ -23,6 +23,11 @@ body {
   background: #e7ad52;
   background: #e7ad52;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #e7ad52;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 6 - 1
css/theme/serif.css

@@ -16,7 +16,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Palatino Linotype", "Book Antiqua", Palatino, FreeSerif, serif;
   font-family: "Palatino Linotype", "Book Antiqua", Palatino, FreeSerif, serif;
-  font-size: 36px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #000; }
   color: #000; }
 
 
@@ -25,6 +25,11 @@ body {
   background: #26351C;
   background: #26351C;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #26351C;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 9 - 1
css/theme/simple.css

@@ -7,6 +7,9 @@
  */
  */
 @import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700);
 @import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700);
 @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
 @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
+section.has-dark-background, section.has-dark-background h1, section.has-dark-background h2, section.has-dark-background h3, section.has-dark-background h4, section.has-dark-background h5, section.has-dark-background h6 {
+  color: #fff; }
+
 /*********************************************
 /*********************************************
  * GLOBAL STYLES
  * GLOBAL STYLES
  *********************************************/
  *********************************************/
@@ -16,7 +19,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Lato", sans-serif;
   font-family: "Lato", sans-serif;
-  font-size: 36px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #000; }
   color: #000; }
 
 
@@ -25,6 +28,11 @@ body {
   background: rgba(0, 0, 0, 0.99);
   background: rgba(0, 0, 0, 0.99);
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: rgba(0, 0, 0, 0.99);
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 6 - 1
css/theme/sky.css

@@ -23,7 +23,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Open Sans", sans-serif;
   font-family: "Open Sans", sans-serif;
-  font-size: 36px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #333; }
   color: #333; }
 
 
@@ -32,6 +32,11 @@ body {
   background: #134674;
   background: #134674;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #134674;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 6 - 1
css/theme/solarized.css

@@ -20,7 +20,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Lato", sans-serif;
   font-family: "Lato", sans-serif;
-  font-size: 36px;
+  font-size: 40px;
   font-weight: normal;
   font-weight: normal;
   color: #657b83; }
   color: #657b83; }
 
 
@@ -29,6 +29,11 @@ body {
   background: #d33682;
   background: #d33682;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #d33682;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

+ 1 - 1
css/theme/source/black.scss

@@ -21,7 +21,7 @@ $backgroundColor: #222;
 $mainColor: #fff;
 $mainColor: #fff;
 $headingColor: #fff;
 $headingColor: #fff;
 
 
-$mainFontSize: 38px;
+$mainFontSize: 42px;
 $mainFont: 'Source Sans Pro', Helvetica, sans-serif;
 $mainFont: 'Source Sans Pro', Helvetica, sans-serif;
 $headingFont: 'Source Sans Pro', Helvetica, sans-serif;
 $headingFont: 'Source Sans Pro', Helvetica, sans-serif;
 $headingTextShadow: none;
 $headingTextShadow: none;

+ 0 - 1
css/theme/source/blood.scss

@@ -28,7 +28,6 @@ $backgroundColor: $coal;
 
 
 // Main text
 // Main text
 $mainFont: Ubuntu, 'sans-serif';
 $mainFont: Ubuntu, 'sans-serif';
-$mainFontSize: 36px;
 $mainColor: #eee;
 $mainColor: #eee;
 
 
 // Headings
 // Headings

+ 0 - 1
css/theme/source/night.scss

@@ -27,7 +27,6 @@ $headingTextShadow: none;
 $headingLetterSpacing: -0.03em;
 $headingLetterSpacing: -0.03em;
 $headingTextTransform: none;
 $headingTextTransform: none;
 $selectionBackgroundColor: #e7ad52;
 $selectionBackgroundColor: #e7ad52;
-$mainFontSize: 30px;
 
 
 
 
 // Theme template ------------------------------
 // Theme template ------------------------------

+ 5 - 0
css/theme/source/simple.scss

@@ -31,6 +31,11 @@ $linkColor: #00008B;
 $linkColorHover: lighten( $linkColor, 20% );
 $linkColorHover: lighten( $linkColor, 20% );
 $selectionBackgroundColor: rgba(0, 0, 0, 0.99);
 $selectionBackgroundColor: rgba(0, 0, 0, 0.99);
 
 
+section.has-dark-background {
+	&, h1, h2, h3, h4, h5, h6 {
+		color: #fff;
+	}
+}
 
 
 
 
 // Theme template ------------------------------
 // Theme template ------------------------------

+ 1 - 1
css/theme/source/white.scss

@@ -21,7 +21,7 @@ $backgroundColor: #fff;
 $mainColor: #222;
 $mainColor: #222;
 $headingColor: #222;
 $headingColor: #222;
 
 
-$mainFontSize: 38px;
+$mainFontSize: 42px;
 $mainFont: 'Source Sans Pro', Helvetica, sans-serif;
 $mainFont: 'Source Sans Pro', Helvetica, sans-serif;
 $headingFont: 'Source Sans Pro', Helvetica, sans-serif;
 $headingFont: 'Source Sans Pro', Helvetica, sans-serif;
 $headingTextShadow: none;
 $headingTextShadow: none;

+ 1 - 1
css/theme/template/settings.scss

@@ -6,7 +6,7 @@ $backgroundColor: #2b2b2b;
 
 
 // Primary/body text
 // Primary/body text
 $mainFont: 'Lato', sans-serif;
 $mainFont: 'Lato', sans-serif;
-$mainFontSize: 36px;
+$mainFontSize: 40px;
 $mainColor: #eee;
 $mainColor: #eee;
 
 
 // Vertical spacing between blocks of text
 // Vertical spacing between blocks of text

+ 6 - 0
css/theme/template/theme.scss

@@ -22,6 +22,12 @@ body {
 	text-shadow: none;
 	text-shadow: none;
 }
 }
 
 
+::-moz-selection {
+	color: $selectionColor;
+	background: $selectionBackgroundColor;
+	text-shadow: none;
+}
+
 .reveal .slides>section,
 .reveal .slides>section,
 .reveal .slides>section>section {
 .reveal .slides>section>section {
 	line-height: 1.3;
 	line-height: 1.3;

+ 6 - 1
css/theme/white.css

@@ -16,7 +16,7 @@ body {
 
 
 .reveal {
 .reveal {
   font-family: "Source Sans Pro", Helvetica, sans-serif;
   font-family: "Source Sans Pro", Helvetica, sans-serif;
-  font-size: 38px;
+  font-size: 42px;
   font-weight: normal;
   font-weight: normal;
   color: #222; }
   color: #222; }
 
 
@@ -25,6 +25,11 @@ body {
   background: #98bdef;
   background: #98bdef;
   text-shadow: none; }
   text-shadow: none; }
 
 
+::-moz-selection {
+  color: #fff;
+  background: #98bdef;
+  text-shadow: none; }
+
 .reveal .slides > section,
 .reveal .slides > section,
 .reveal .slides > section > section {
 .reveal .slides > section > section {
   line-height: 1.3;
   line-height: 1.3;

File diff suppressed because it is too large
+ 388 - 171
js/reveal.js


+ 7 - 6
package.json

@@ -22,21 +22,22 @@
     "node": ">=4.0.0"
     "node": ">=4.0.0"
   },
   },
   "dependencies": {
   "dependencies": {
-    "express": "~4.13.3",
-    "grunt-cli": "~0.1.13",
+    "express": "~4.14.0",
+    "grunt-cli": "~1.2.0",
     "mustache": "~2.2.1",
     "mustache": "~2.2.1",
-    "socket.io": "~1.3.7"
+    "socket.io": "^1.4.8"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "grunt": "~0.4.5",
+    "grunt": "~1.0.1",
     "grunt-autoprefixer": "~3.0.3",
     "grunt-autoprefixer": "~3.0.3",
     "grunt-contrib-connect": "~0.11.2",
     "grunt-contrib-connect": "~0.11.2",
     "grunt-contrib-cssmin": "~0.14.0",
     "grunt-contrib-cssmin": "~0.14.0",
     "grunt-contrib-jshint": "~0.11.3",
     "grunt-contrib-jshint": "~0.11.3",
     "grunt-contrib-qunit": "~1.2.0",
     "grunt-contrib-qunit": "~1.2.0",
     "grunt-contrib-uglify": "~0.9.2",
     "grunt-contrib-uglify": "~0.9.2",
-    "grunt-contrib-watch": "~0.6.1",
-    "grunt-sass": "~1.1.0-beta",
+    "grunt-contrib-watch": "~1.0.0",
+    "grunt-sass": "~1.2.0",
+    "grunt-retire": "~0.3.10",
     "grunt-zip": "~0.17.1",
     "grunt-zip": "~0.17.1",
     "node-sass": "~3.13.0"
     "node-sass": "~3.13.0"
   },
   },

+ 48 - 1
plugin/highlight/highlight.js

@@ -1,5 +1,52 @@
 // START CUSTOM REVEAL.JS INTEGRATION
 // START CUSTOM REVEAL.JS INTEGRATION
 (function() {
 (function() {
+	// Function to perform a better "data-trim" on code snippets
+	// Will slice an indentation amount on each line of the snippet (amount based on the line having the lowest indentation length)
+	function betterTrim(snippetEl) {
+		// Helper functions
+		function trimLeft(val) {
+			// Adapted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
+			return val.replace(/^[\s\uFEFF\xA0]+/g, '');
+		}
+		function trimLineBreaks(input) {
+			var lines = input.split('\n');
+
+			// Trim line-breaks from the beginning
+			for (var i = 0; i < lines.length; i++) {
+				if (lines[i].trim() === '') {
+					lines.splice(i--, 1);
+				} else break;
+			}
+
+			// Trim line-breaks from the end
+			for (var i = lines.length-1; i >= 0; i--) {
+				if (lines[i].trim() === '') {
+					lines.splice(i, 1);
+				} else break;
+			}
+
+			return lines.join('\n');
+		}
+
+		// Main function for betterTrim()
+		return (function(snippetEl) {
+			var content = trimLineBreaks(snippetEl.innerHTML);
+			var lines = content.split('\n');
+			// Calculate the minimum amount to remove on each line start of the snippet (can be 0)
+			var pad = lines.reduce(function(acc, line) {
+				if (line.length > 0 && trimLeft(line).length > 0 && acc > line.length - trimLeft(line).length) {
+					return line.length - trimLeft(line).length;
+				}
+				return acc;
+			}, Number.POSITIVE_INFINITY);
+			// Slice each line with this amount
+			return lines.map(function(line, index) {
+				return line.slice(pad);
+			})
+			.join('\n');
+		})(snippetEl);
+	}
+
 	if( typeof window.addEventListener === 'function' ) {
 	if( typeof window.addEventListener === 'function' ) {
 		var hljs_nodes = document.querySelectorAll( 'pre code' );
 		var hljs_nodes = document.querySelectorAll( 'pre code' );
 
 
@@ -8,7 +55,7 @@
 
 
 			// trim whitespace if data-trim attribute is present
 			// trim whitespace if data-trim attribute is present
 			if( element.hasAttribute( 'data-trim' ) && typeof element.innerHTML.trim === 'function' ) {
 			if( element.hasAttribute( 'data-trim' ) && typeof element.innerHTML.trim === 'function' ) {
-				element.innerHTML = element.innerHTML.trim();
+				element.innerHTML = betterTrim(element);
 			}
 			}
 
 
 			// Now escape html unless prevented by author
 			// Now escape html unless prevented by author

+ 19 - 13
plugin/markdown/markdown.js

@@ -17,18 +17,6 @@
 	}
 	}
 }( this, function( marked ) {
 }( this, function( marked ) {
 
 
-	if( typeof marked === 'undefined' ) {
-		throw 'The reveal.js Markdown plugin requires marked to be loaded';
-	}
-
-	if( typeof hljs !== 'undefined' ) {
-		marked.setOptions({
-			highlight: function( lang, code ) {
-				return hljs.highlightAuto( lang, code ).value;
-			}
-		});
-	}
-
 	var DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$',
 	var DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$',
 		DEFAULT_NOTES_SEPARATOR = 'note:',
 		DEFAULT_NOTES_SEPARATOR = 'note:',
 		DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$',
 		DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$',
@@ -189,7 +177,7 @@
 				markdownSections += '<section '+ options.attributes +'>';
 				markdownSections += '<section '+ options.attributes +'>';
 
 
 				sectionStack[i].forEach( function( child ) {
 				sectionStack[i].forEach( function( child ) {
-					markdownSections += '<section data-markdown>' +  createMarkdownSlide( child, options ) + '</section>';
+					markdownSections += '<section data-markdown>' + createMarkdownSlide( child, options ) + '</section>';
 				} );
 				} );
 
 
 				markdownSections += '</section>';
 				markdownSections += '</section>';
@@ -391,6 +379,24 @@
 	return {
 	return {
 
 
 		initialize: function() {
 		initialize: function() {
+			if( typeof marked === 'undefined' ) {
+				throw 'The reveal.js Markdown plugin requires marked to be loaded';
+			}
+
+			if( typeof hljs !== 'undefined' ) {
+				marked.setOptions({
+					highlight: function( code, lang ) {
+						return hljs.highlightAuto( code, [lang] ).value;
+					}
+				});
+			}
+
+			var options = Reveal.getConfig().markdown;
+
+			if ( options ) {
+				marked.setOptions( options );
+			}
+
 			processSlides();
 			processSlides();
 			convertSlides();
 			convertSlides();
 		},
 		},

File diff suppressed because it is too large
+ 1 - 1
plugin/markdown/marked.js


+ 198 - 20
plugin/notes-server/notes.html

@@ -8,6 +8,7 @@
 		<style>
 		<style>
 			body {
 			body {
 				font-family: Helvetica;
 				font-family: Helvetica;
+				font-size: 18px;
 			}
 			}
 
 
 			#current-slide,
 			#current-slide,
@@ -30,15 +31,26 @@
 				position: absolute;
 				position: absolute;
 				top: 10px;
 				top: 10px;
 				left: 10px;
 				left: 10px;
-				font-weight: bold;
-				font-size: 14px;
 				z-index: 2;
 				z-index: 2;
-				color: rgba( 255, 255, 255, 0.9 );
+			}
+
+			.overlay-element {
+				height: 34px;
+				line-height: 34px;
+				padding: 0 10px;
+				text-shadow: none;
+				background: rgba( 220, 220, 220, 0.8 );
+				color: #222;
+				font-size: 14px;
+			}
+
+			.overlay-element.interactive:hover {
+				background: rgba( 220, 220, 220, 1 );
 			}
 			}
 
 
 			#current-slide {
 			#current-slide {
 				position: absolute;
 				position: absolute;
-				width: 65%;
+				width: 60%;
 				height: 100%;
 				height: 100%;
 				top: 0;
 				top: 0;
 				left: 0;
 				left: 0;
@@ -47,19 +59,20 @@
 
 
 			#upcoming-slide {
 			#upcoming-slide {
 				position: absolute;
 				position: absolute;
-				width: 35%;
+				width: 40%;
 				height: 40%;
 				height: 40%;
 				right: 0;
 				right: 0;
 				top: 0;
 				top: 0;
 			}
 			}
 
 
+			/* Speaker controls */
 			#speaker-controls {
 			#speaker-controls {
 				position: absolute;
 				position: absolute;
 				top: 40%;
 				top: 40%;
 				right: 0;
 				right: 0;
-				width: 35%;
+				width: 40%;
 				height: 60%;
 				height: 60%;
-
+				overflow: auto;
 				font-size: 18px;
 				font-size: 18px;
 			}
 			}
 
 
@@ -124,26 +137,108 @@
 					font-size: 1.2em;
 					font-size: 1.2em;
 				}
 				}
 
 
+			/* Layout selector */
+			#speaker-layout {
+				position: absolute;
+				top: 10px;
+				right: 10px;
+				color: #222;
+				z-index: 10;
+			}
+				#speaker-layout select {
+					position: absolute;
+					width: 100%;
+					height: 100%;
+					top: 0;
+					left: 0;
+					border: 0;
+					box-shadow: 0;
+					cursor: pointer;
+					opacity: 0;
+
+					font-size: 1em;
+					background-color: transparent;
+
+					-moz-appearance: none;
+					-webkit-appearance: none;
+					-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+				}
+
+				#speaker-layout select:focus {
+					outline: none;
+					box-shadow: none;
+				}
+
 			.clear {
 			.clear {
 				clear: both;
 				clear: both;
 			}
 			}
 
 
-			@media screen and (max-width: 1080px) {
-				#speaker-controls {
-					font-size: 16px;
-				}
+			/* Speaker layout: Wide */
+			body[data-speaker-layout="wide"] #current-slide,
+			body[data-speaker-layout="wide"] #upcoming-slide {
+				width: 50%;
+				height: 45%;
+				padding: 6px;
 			}
 			}
 
 
-			@media screen and (max-width: 900px) {
-				#speaker-controls {
-					font-size: 14px;
-				}
+			body[data-speaker-layout="wide"] #current-slide {
+				top: 0;
+				left: 0;
 			}
 			}
 
 
-			@media screen and (max-width: 800px) {
-				#speaker-controls {
-					font-size: 12px;
-				}
+			body[data-speaker-layout="wide"] #upcoming-slide {
+				top: 0;
+				left: 50%;
+			}
+
+			body[data-speaker-layout="wide"] #speaker-controls {
+				top: 45%;
+				left: 0;
+				width: 100%;
+				height: 50%;
+				font-size: 1.25em;
+			}
+
+			/* Speaker layout: Tall */
+			body[data-speaker-layout="tall"] #current-slide,
+			body[data-speaker-layout="tall"] #upcoming-slide {
+				width: 45%;
+				height: 50%;
+				padding: 6px;
+			}
+
+			body[data-speaker-layout="tall"] #current-slide {
+				top: 0;
+				left: 0;
+			}
+
+			body[data-speaker-layout="tall"] #upcoming-slide {
+				top: 50%;
+				left: 0;
+			}
+
+			body[data-speaker-layout="tall"] #speaker-controls {
+				padding-top: 40px;
+				top: 0;
+				left: 45%;
+				width: 55%;
+				height: 100%;
+				font-size: 1.25em;
+			}
+
+			/* Speaker layout: Notes only */
+			body[data-speaker-layout="notes-only"] #current-slide,
+			body[data-speaker-layout="notes-only"] #upcoming-slide {
+				display: none;
+			}
+
+			body[data-speaker-layout="notes-only"] #speaker-controls {
+				padding-top: 40px;
+				top: 0;
+				left: 0;
+				width: 100%;
+				height: 100%;
+				font-size: 1.25em;
 			}
 			}
 
 
 		</style>
 		</style>
@@ -152,7 +247,7 @@
 	<body>
 	<body>
 
 
 		<div id="current-slide"></div>
 		<div id="current-slide"></div>
-		<div id="upcoming-slide"><span class="label">UPCOMING:</span></div>
+		<div id="upcoming-slide"><span class="overlay-element label">Upcoming</span></div>
 		<div id="speaker-controls">
 		<div id="speaker-controls">
 			<div class="speaker-controls-time">
 			<div class="speaker-controls-time">
 				<h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
 				<h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
@@ -170,6 +265,10 @@
 				<div class="value"></div>
 				<div class="value"></div>
 			</div>
 			</div>
 		</div>
 		</div>
+		<div id="speaker-layout" class="overlay-element interactive">
+			<span class="speaker-layout-label"></span>
+			<select class="speaker-layout-dropdown"></select>
+		</div>
 
 
 		<script src="/socket.io/socket.io.js"></script>
 		<script src="/socket.io/socket.io.js"></script>
 		<script src="/plugin/markdown/marked.js"></script>
 		<script src="/plugin/markdown/marked.js"></script>
@@ -182,11 +281,20 @@
 				currentState,
 				currentState,
 				currentSlide,
 				currentSlide,
 				upcomingSlide,
 				upcomingSlide,
+				layoutLabel,
+				layoutDropdown,
 				connected = false;
 				connected = false;
 
 
 			var socket = io.connect( window.location.origin ),
 			var socket = io.connect( window.location.origin ),
 				socketId = '{{socketId}}';
 				socketId = '{{socketId}}';
 
 
+			var SPEAKER_LAYOUTS = {
+				'default': 'Default',
+				'wide': 'Wide',
+				'tall': 'Tall',
+				'notes-only': 'Notes only'
+			};
+
 			socket.on( 'statechanged', function( data ) {
 			socket.on( 'statechanged', function( data ) {
 
 
 				// ignore data from sockets that aren't ours
 				// ignore data from sockets that aren't ours
@@ -205,6 +313,8 @@
 
 
 			} );
 			} );
 
 
+			setupLayout();
+
 			// Load our presentation iframes
 			// Load our presentation iframes
 			setupIframes();
 			setupIframes();
 
 
@@ -362,6 +472,74 @@
 
 
 			}
 			}
 
 
+			/**
+				 * Sets up the speaker view layout and layout selector.
+				 */
+				function setupLayout() {
+
+					layoutDropdown = document.querySelector( '.speaker-layout-dropdown' );
+					layoutLabel = document.querySelector( '.speaker-layout-label' );
+
+					// Render the list of available layouts
+					for( var id in SPEAKER_LAYOUTS ) {
+						var option = document.createElement( 'option' );
+						option.setAttribute( 'value', id );
+						option.textContent = SPEAKER_LAYOUTS[ id ];
+						layoutDropdown.appendChild( option );
+					}
+
+					// Monitor the dropdown for changes
+					layoutDropdown.addEventListener( 'change', function( event ) {
+
+						setLayout( layoutDropdown.value );
+
+					}, false );
+
+					// Restore any currently persisted layout
+					setLayout( getLayout() );
+
+				}
+
+				/**
+				 * Sets a new speaker view layout. The layout is persisted
+				 * in local storage.
+				 */
+				function setLayout( value ) {
+
+					var title = SPEAKER_LAYOUTS[ value ];
+
+					layoutLabel.innerHTML = 'Layout' + ( title ? ( ': ' + title ) : '' );
+					layoutDropdown.value = value;
+
+					document.body.setAttribute( 'data-speaker-layout', value );
+
+					// Persist locally
+					if( window.localStorage ) {
+						window.localStorage.setItem( 'reveal-speaker-layout', value );
+					}
+
+				}
+
+				/**
+				 * Returns the ID of the most recently set speaker layout
+				 * or our default layout if none has been set.
+				 */
+				function getLayout() {
+
+					if( window.localStorage ) {
+						var layout = window.localStorage.getItem( 'reveal-speaker-layout' );
+						if( layout ) {
+							return layout;
+						}
+					}
+
+					// Default to the first record in the layouts hash
+					for( var id in SPEAKER_LAYOUTS ) {
+						return id;
+					}
+
+				}
+
 			function zeroPadInteger( num ) {
 			function zeroPadInteger( num ) {
 
 
 				var str = '00' + parseInt( num );
 				var str = '00' + parseInt( num );

+ 206 - 11
plugin/notes/notes.html

@@ -8,6 +8,7 @@
 		<style>
 		<style>
 			body {
 			body {
 				font-family: Helvetica;
 				font-family: Helvetica;
+				font-size: 18px;
 			}
 			}
 
 
 			#current-slide,
 			#current-slide,
@@ -30,15 +31,26 @@
 				position: absolute;
 				position: absolute;
 				top: 10px;
 				top: 10px;
 				left: 10px;
 				left: 10px;
-				font-weight: bold;
-				font-size: 14px;
 				z-index: 2;
 				z-index: 2;
-				color: rgba( 255, 255, 255, 0.9 );
+			}
+
+			.overlay-element {
+				height: 34px;
+				line-height: 34px;
+				padding: 0 10px;
+				text-shadow: none;
+				background: rgba( 220, 220, 220, 0.8 );
+				color: #222;
+				font-size: 14px;
+			}
+
+			.overlay-element.interactive:hover {
+				background: rgba( 220, 220, 220, 1 );
 			}
 			}
 
 
 			#current-slide {
 			#current-slide {
 				position: absolute;
 				position: absolute;
-				width: 65%;
+				width: 60%;
 				height: 100%;
 				height: 100%;
 				top: 0;
 				top: 0;
 				left: 0;
 				left: 0;
@@ -47,20 +59,20 @@
 
 
 			#upcoming-slide {
 			#upcoming-slide {
 				position: absolute;
 				position: absolute;
-				width: 35%;
+				width: 40%;
 				height: 40%;
 				height: 40%;
 				right: 0;
 				right: 0;
 				top: 0;
 				top: 0;
 			}
 			}
 
 
+			/* Speaker controls */
 			#speaker-controls {
 			#speaker-controls {
 				position: absolute;
 				position: absolute;
 				top: 40%;
 				top: 40%;
 				right: 0;
 				right: 0;
-				width: 35%;
+				width: 40%;
 				height: 60%;
 				height: 60%;
 				overflow: auto;
 				overflow: auto;
-
 				font-size: 18px;
 				font-size: 18px;
 			}
 			}
 
 
@@ -125,24 +137,124 @@
 					font-size: 1.2em;
 					font-size: 1.2em;
 				}
 				}
 
 
+			/* Layout selector */
+			#speaker-layout {
+				position: absolute;
+				top: 10px;
+				right: 10px;
+				color: #222;
+				z-index: 10;
+			}
+				#speaker-layout select {
+					position: absolute;
+					width: 100%;
+					height: 100%;
+					top: 0;
+					left: 0;
+					border: 0;
+					box-shadow: 0;
+					cursor: pointer;
+					opacity: 0;
+
+					font-size: 1em;
+					background-color: transparent;
+
+					-moz-appearance: none;
+					-webkit-appearance: none;
+					-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+				}
+
+				#speaker-layout select:focus {
+					outline: none;
+					box-shadow: none;
+				}
+
 			.clear {
 			.clear {
 				clear: both;
 				clear: both;
 			}
 			}
 
 
+			/* Speaker layout: Wide */
+			body[data-speaker-layout="wide"] #current-slide,
+			body[data-speaker-layout="wide"] #upcoming-slide {
+				width: 50%;
+				height: 45%;
+				padding: 6px;
+			}
+
+			body[data-speaker-layout="wide"] #current-slide {
+				top: 0;
+				left: 0;
+			}
+
+			body[data-speaker-layout="wide"] #upcoming-slide {
+				top: 0;
+				left: 50%;
+			}
+
+			body[data-speaker-layout="wide"] #speaker-controls {
+				top: 45%;
+				left: 0;
+				width: 100%;
+				height: 50%;
+				font-size: 1.25em;
+			}
+
+			/* Speaker layout: Tall */
+			body[data-speaker-layout="tall"] #current-slide,
+			body[data-speaker-layout="tall"] #upcoming-slide {
+				width: 45%;
+				height: 50%;
+				padding: 6px;
+			}
+
+			body[data-speaker-layout="tall"] #current-slide {
+				top: 0;
+				left: 0;
+			}
+
+			body[data-speaker-layout="tall"] #upcoming-slide {
+				top: 50%;
+				left: 0;
+			}
+
+			body[data-speaker-layout="tall"] #speaker-controls {
+				padding-top: 40px;
+				top: 0;
+				left: 45%;
+				width: 55%;
+				height: 100%;
+				font-size: 1.25em;
+			}
+
+			/* Speaker layout: Notes only */
+			body[data-speaker-layout="notes-only"] #current-slide,
+			body[data-speaker-layout="notes-only"] #upcoming-slide {
+				display: none;
+			}
+
+			body[data-speaker-layout="notes-only"] #speaker-controls {
+				padding-top: 40px;
+				top: 0;
+				left: 0;
+				width: 100%;
+				height: 100%;
+				font-size: 1.25em;
+			}
+
 			@media screen and (max-width: 1080px) {
 			@media screen and (max-width: 1080px) {
-				#speaker-controls {
+				body[data-speaker-layout="default"] #speaker-controls {
 					font-size: 16px;
 					font-size: 16px;
 				}
 				}
 			}
 			}
 
 
 			@media screen and (max-width: 900px) {
 			@media screen and (max-width: 900px) {
-				#speaker-controls {
+				body[data-speaker-layout="default"] #speaker-controls {
 					font-size: 14px;
 					font-size: 14px;
 				}
 				}
 			}
 			}
 
 
 			@media screen and (max-width: 800px) {
 			@media screen and (max-width: 800px) {
-				#speaker-controls {
+				body[data-speaker-layout="default"] #speaker-controls {
 					font-size: 12px;
 					font-size: 12px;
 				}
 				}
 			}
 			}
@@ -153,7 +265,7 @@
 	<body>
 	<body>
 
 
 		<div id="current-slide"></div>
 		<div id="current-slide"></div>
-		<div id="upcoming-slide"><span class="label">UPCOMING:</span></div>
+		<div id="upcoming-slide"><span class="overlay-element label">Upcoming</span></div>
 		<div id="speaker-controls">
 		<div id="speaker-controls">
 			<div class="speaker-controls-time">
 			<div class="speaker-controls-time">
 				<h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
 				<h4 class="label">Time <span class="reset-button">Click to Reset</span></h4>
@@ -171,6 +283,10 @@
 				<div class="value"></div>
 				<div class="value"></div>
 			</div>
 			</div>
 		</div>
 		</div>
+		<div id="speaker-layout" class="overlay-element interactive">
+			<span class="speaker-layout-label"></span>
+			<select class="speaker-layout-dropdown"></select>
+		</div>
 
 
 		<script src="../../plugin/markdown/marked.js"></script>
 		<script src="../../plugin/markdown/marked.js"></script>
 		<script>
 		<script>
@@ -182,8 +298,19 @@
 					currentState,
 					currentState,
 					currentSlide,
 					currentSlide,
 					upcomingSlide,
 					upcomingSlide,
+					layoutLabel,
+					layoutDropdown,
 					connected = false;
 					connected = false;
 
 
+				var SPEAKER_LAYOUTS = {
+					'default': 'Default',
+					'wide': 'Wide',
+					'tall': 'Tall',
+					'notes-only': 'Notes only'
+				};
+
+				setupLayout();
+
 				window.addEventListener( 'message', function( event ) {
 				window.addEventListener( 'message', function( event ) {
 
 
 					var data = JSON.parse( event.data );
 					var data = JSON.parse( event.data );
@@ -369,6 +496,74 @@
 
 
 				}
 				}
 
 
+				/**
+				 * Sets up the speaker view layout and layout selector.
+				 */
+				function setupLayout() {
+
+					layoutDropdown = document.querySelector( '.speaker-layout-dropdown' );
+					layoutLabel = document.querySelector( '.speaker-layout-label' );
+
+					// Render the list of available layouts
+					for( var id in SPEAKER_LAYOUTS ) {
+						var option = document.createElement( 'option' );
+						option.setAttribute( 'value', id );
+						option.textContent = SPEAKER_LAYOUTS[ id ];
+						layoutDropdown.appendChild( option );
+					}
+
+					// Monitor the dropdown for changes
+					layoutDropdown.addEventListener( 'change', function( event ) {
+
+						setLayout( layoutDropdown.value );
+
+					}, false );
+
+					// Restore any currently persisted layout
+					setLayout( getLayout() );
+
+				}
+
+				/**
+				 * Sets a new speaker view layout. The layout is persisted
+				 * in local storage.
+				 */
+				function setLayout( value ) {
+
+					var title = SPEAKER_LAYOUTS[ value ];
+
+					layoutLabel.innerHTML = 'Layout' + ( title ? ( ': ' + title ) : '' );
+					layoutDropdown.value = value;
+
+					document.body.setAttribute( 'data-speaker-layout', value );
+
+					// Persist locally
+					if( window.localStorage ) {
+						window.localStorage.setItem( 'reveal-speaker-layout', value );
+					}
+
+				}
+
+				/**
+				 * Returns the ID of the most recently set speaker layout
+				 * or our default layout if none has been set.
+				 */
+				function getLayout() {
+
+					if( window.localStorage ) {
+						var layout = window.localStorage.getItem( 'reveal-speaker-layout' );
+						if( layout ) {
+							return layout;
+						}
+					}
+
+					// Default to the first record in the layouts hash
+					for( var id in SPEAKER_LAYOUTS ) {
+						return id;
+					}
+
+				}
+
 				function zeroPadInteger( num ) {
 				function zeroPadInteger( num ) {
 
 
 					var str = '00' + parseInt( num );
 					var str = '00' + parseInt( num );

+ 11 - 1
plugin/zoom-js/zoom.js

@@ -11,7 +11,17 @@
 		if( event[ modifier ] && isEnabled ) {
 		if( event[ modifier ] && isEnabled ) {
 			event.preventDefault();
 			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({
 			zoom.to({
 				x: ( bounds.left * revealScale ) - zoomPadding,
 				x: ( bounds.left * revealScale ) - zoomPadding,

+ 12 - 0
test/simple.md

@@ -0,0 +1,12 @@
+## Slide 1.1
+
+```js
+var a = 1;
+```
+
+
+## Slide 1.2
+
+
+
+## Slide 2

+ 36 - 0
test/test-markdown-external.html

@@ -0,0 +1,36 @@
+<!doctype html>
+<html lang="en">
+
+	<head>
+		<meta charset="utf-8">
+
+		<title>reveal.js - Test Markdown</title>
+
+		<link rel="stylesheet" href="../css/reveal.css">
+		<link rel="stylesheet" href="qunit-1.12.0.css">
+	</head>
+
+	<body style="overflow: auto;">
+
+		<div id="qunit"></div>
+  		<div id="qunit-fixture"></div>
+
+		<div class="reveal" style="display: none;">
+
+			<div class="slides">
+				<section data-markdown="simple.md" data-separator="^\n\n\n" data-separator-vertical="^\n\n"></section>
+			</div>
+
+		</div>
+
+		<script src="../lib/js/head.min.js"></script>
+		<script src="../js/reveal.js"></script>
+		<script src="../plugin/highlight/highlight.js"></script>
+		<script src="../plugin/markdown/marked.js"></script>
+		<script src="../plugin/markdown/markdown.js"></script>
+		<script src="qunit-1.12.0.js"></script>
+
+		<script src="test-markdown-external.js"></script>
+
+	</body>
+</html>

+ 24 - 0
test/test-markdown-external.js

@@ -0,0 +1,24 @@
+
+
+Reveal.addEventListener( 'ready', function() {
+
+	QUnit.module( 'Markdown' );
+
+	test( 'Vertical separator', function() {
+		strictEqual( document.querySelectorAll( '.reveal .slides>section>section' ).length, 2, 'found two slides' );
+	});
+
+	test( 'Horizontal separator', function() {
+		strictEqual( document.querySelectorAll( '.reveal .slides>section' ).length, 2, 'found two slides' );
+	});
+
+	test( 'Language highlighter', function() {
+		strictEqual( document.querySelectorAll( '.hljs-keyword' ).length, 1, 'got rendered highlight tag.' );
+		strictEqual( document.querySelector( '.hljs-keyword' ).innerHTML, 'var', 'the same keyword: var.' );
+	});
+
+
+} );
+
+Reveal.initialize();
+

+ 41 - 0
test/test-markdown-options.html

@@ -0,0 +1,41 @@
+<!doctype html>
+<html lang="en">
+
+	<head>
+		<meta charset="utf-8">
+
+		<title>reveal.js - Test Markdown Options</title>
+
+		<link rel="stylesheet" href="../css/reveal.css">
+		<link rel="stylesheet" href="qunit-1.12.0.css">
+	</head>
+
+	<body style="overflow: auto;">
+
+		<div id="qunit"></div>
+		<div id="qunit-fixture"></div>
+
+		<div class="reveal" style="display: none;">
+
+			<div class="slides">
+
+				<section data-markdown>
+					<script type="text/template">
+						## Testing Markdown Options
+
+						This "slide" should contain 'smart' quotes.
+					</script>
+				</section>
+
+			</div>
+
+		</div>
+
+		<script src="../lib/js/head.min.js"></script>
+		<script src="../js/reveal.js"></script>
+		<script src="qunit-1.12.0.js"></script>
+
+		<script src="test-markdown-options.js"></script>
+
+	</body>
+</html>

+ 26 - 0
test/test-markdown-options.js

@@ -0,0 +1,26 @@
+Reveal.addEventListener( 'ready', function() {
+
+	QUnit.module( 'Markdown' );
+
+	test( 'Options are set', function() {
+		strictEqual( marked.defaults.smartypants, true );
+	});
+
+	test( 'Smart quotes are activated', function() {
+		var text = document.querySelector( '.reveal .slides>section>p' ).textContent;
+
+		strictEqual( /['"]/.test( text ), false );
+		strictEqual( /[“”‘’]/.test( text ), true );
+	});
+
+} );
+
+Reveal.initialize({
+	dependencies: [
+		{ src: '../plugin/markdown/marked.js' },
+		{ src: '../plugin/markdown/markdown.js' },
+	],
+	markdown: {
+		smartypants: true
+	}
+});

+ 1 - 1
test/test-markdown.html

@@ -13,7 +13,7 @@
 	<body style="overflow: auto;">
 	<body style="overflow: auto;">
 
 
 		<div id="qunit"></div>
 		<div id="qunit"></div>
-  		<div id="qunit-fixture"></div>
+		<div id="qunit-fixture"></div>
 
 
 		<div class="reveal" style="display: none;">
 		<div class="reveal" style="display: none;">