Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Chris Lawrence 2013-09-15 20:19:47 -04:00
commit 55f220109c
15 changed files with 308 additions and 178 deletions

View File

@ -1,6 +1,6 @@
/* global module:false */ /* global module:false */
module.exports = function(grunt) { module.exports = function(grunt) {
var port = grunt.option('port') || 8000;
// Project configuration // Project configuration
grunt.initConfig({ grunt.initConfig({
pkg: grunt.file.readJSON('package.json'), pkg: grunt.file.readJSON('package.json'),
@ -78,7 +78,7 @@ module.exports = function(grunt) {
connect: { connect: {
server: { server: {
options: { options: {
port: 8000, port: port,
base: '.' base: '.'
} }
} }

View File

@ -778,6 +778,8 @@ $ grunt serve
8. Open <http://localhost:8000> to view your presentation 8. Open <http://localhost:8000> to view your presentation
You can change the port by using `grunt serve --port 8001`.
### Folder Structure ### Folder Structure
- **css/** Core styles without which the project does not function - **css/** Core styles without which the project does not function
@ -786,6 +788,23 @@ $ grunt serve
- **lib/** All other third party assets (JavaScript, CSS, fonts) - **lib/** All other third party assets (JavaScript, CSS, fonts)
### Contributing
Please keep the [issue tracker](github.com/hakimel/reveal.js/issues) limited to **bug reports**, **feature requests** and **pull requests**. If you are reporting a bug make sure to include information about which browser and operating system you are using as well as the necessary steps to reproduce the issue.
If you have personal support questions use [StackOverflow](http://stackoverflow.com/questions/tagged/reveal.js).
#### Pull requests
- Should follow the coding style
- Tabs to indent
- Single-quoted strings
- No space between function name and opening argument parenthesis
- One space after opening and before closing parenthesis
- Should be made towards the **dev branch**
- Should be submitted from a feature/topic branch (not your master)
## License ## License

View File

@ -517,6 +517,10 @@ body {
perspective-origin: 0px -100px; perspective-origin: 0px -100px;
} }
.reveal .slides>section {
-ms-perspective: 600px;
}
.reveal .slides>section, .reveal .slides>section,
.reveal .slides>section>section { .reveal .slides>section>section {
display: none; display: none;
@ -1050,8 +1054,8 @@ body {
.reveal.fade.overview .slides section, .reveal.fade.overview .slides section,
.reveal.fade.overview .slides>section>section, .reveal.fade.overview .slides>section>section,
.reveal.fade.exit-overview .slides section, .reveal.fade.overview-deactivating .slides section,
.reveal.fade.exit-overview .slides>section>section { .reveal.fade.overview-deactivating .slides>section>section {
-webkit-transition: none; -webkit-transition: none;
-moz-transition: none; -moz-transition: none;
-ms-transition: none; -ms-transition: none;

2
css/reveal.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -167,12 +167,15 @@
<h2>Themes</h2> <h2>Themes</h2>
<p> <p>
Reveal.js comes with a few themes built in: <br> Reveal.js comes with a few themes built in: <br>
<a href="?#/themes">Default</a> -
<a href="?theme=sky#/themes">Sky</a> - <a href="?theme=sky#/themes">Sky</a> -
<a href="?theme=beige#/themes">Beige</a> - <a href="?theme=beige#/themes">Beige</a> -
<a href="?theme=simple#/themes">Simple</a> - <a href="?theme=simple#/themes">Simple</a> -
<a href="?theme=serif#/themes">Serif</a> - <a href="?theme=serif#/themes">Serif</a> -
<a href="?theme=night#/themes">Night</a> - <a href="?theme=night#/themes">Night</a> <br>
<a href="?#/themes">Default</a> <a href="?theme=moon.css#/themes">Moon</a> -
<a href="?theme=simple.css#/themes">Simple</a> -
<a href="?theme=solarized.css#/themes">Solarized</a>
</p> </p>
<p> <p>
<small> <small>
@ -259,10 +262,10 @@ function linkify( selector ) {
for( var i = 0, len = nodes.length; i &lt; len; i++ ) { for( var i = 0, len = nodes.length; i &lt; len; i++ ) {
var node = nodes[i]; var node = nodes[i];
if( !node.className ) ) { if( !node.className ) {
node.className += ' roll'; node.className += ' roll';
} }
}; }
} }
} }
</code></pre> </code></pre>

View File

@ -74,6 +74,9 @@ var Reveal = (function(){
// Apply a 3D roll to links on hover // Apply a 3D roll to links on hover
rollingLinks: false, rollingLinks: false,
// Hides the address bar on mobile devices
hideAddressBar: true,
// Opens links in an iframe preview overlay // Opens links in an iframe preview overlay
previewLinks: false, previewLinks: false,
@ -353,17 +356,15 @@ var Reveal = (function(){
createSingletonNode( dom.wrapper, 'div', 'pause-overlay', null ); createSingletonNode( dom.wrapper, 'div', 'pause-overlay', null );
// Cache references to elements // Cache references to elements
if ( config.controls ) { dom.controls = document.querySelector( '.reveal .controls' );
dom.controls = document.querySelector( '.reveal .controls' );
// There can be multiple instances of controls throughout the page // There can be multiple instances of controls throughout the page
dom.controlsLeft = toArray( document.querySelectorAll( '.navigate-left' ) ); dom.controlsLeft = toArray( document.querySelectorAll( '.navigate-left' ) );
dom.controlsRight = toArray( document.querySelectorAll( '.navigate-right' ) ); dom.controlsRight = toArray( document.querySelectorAll( '.navigate-right' ) );
dom.controlsUp = toArray( document.querySelectorAll( '.navigate-up' ) ); dom.controlsUp = toArray( document.querySelectorAll( '.navigate-up' ) );
dom.controlsDown = toArray( document.querySelectorAll( '.navigate-down' ) ); dom.controlsDown = toArray( document.querySelectorAll( '.navigate-down' ) );
dom.controlsPrev = toArray( document.querySelectorAll( '.navigate-prev' ) ); dom.controlsPrev = toArray( document.querySelectorAll( '.navigate-prev' ) );
dom.controlsNext = toArray( document.querySelectorAll( '.navigate-next' ) ); dom.controlsNext = toArray( document.querySelectorAll( '.navigate-next' ) );
}
} }
@ -491,13 +492,8 @@ var Reveal = (function(){
dom.wrapper.setAttribute( 'data-transition-speed', config.transitionSpeed ); dom.wrapper.setAttribute( 'data-transition-speed', config.transitionSpeed );
dom.wrapper.setAttribute( 'data-background-transition', config.backgroundTransition ); dom.wrapper.setAttribute( 'data-background-transition', config.backgroundTransition );
if( dom.controls ) { dom.controls.style.display = config.controls ? 'block' : 'none';
dom.controls.style.display = ( config.controls && dom.controls ) ? 'block' : 'none'; dom.progress.style.display = config.progress ? 'block' : 'none';
}
if( dom.progress ) {
dom.progress.style.display = ( config.progress && dom.progress ) ? 'block' : 'none';
}
if( config.rtl ) { if( config.rtl ) {
dom.wrapper.classList.add( 'rtl' ); dom.wrapper.classList.add( 'rtl' );
@ -586,16 +582,14 @@ var Reveal = (function(){
dom.progress.addEventListener( 'click', onProgressClicked, false ); dom.progress.addEventListener( 'click', onProgressClicked, false );
} }
if ( config.controls && dom.controls ) { [ 'touchstart', 'click' ].forEach( function( eventName ) {
[ 'touchstart', 'click' ].forEach( function( eventName ) { dom.controlsLeft.forEach( function( el ) { el.addEventListener( eventName, onNavigateLeftClicked, false ); } );
dom.controlsLeft.forEach( function( el ) { el.addEventListener( eventName, onNavigateLeftClicked, false ); } ); dom.controlsRight.forEach( function( el ) { el.addEventListener( eventName, onNavigateRightClicked, false ); } );
dom.controlsRight.forEach( function( el ) { el.addEventListener( eventName, onNavigateRightClicked, false ); } ); dom.controlsUp.forEach( function( el ) { el.addEventListener( eventName, onNavigateUpClicked, false ); } );
dom.controlsUp.forEach( function( el ) { el.addEventListener( eventName, onNavigateUpClicked, false ); } ); dom.controlsDown.forEach( function( el ) { el.addEventListener( eventName, onNavigateDownClicked, false ); } );
dom.controlsDown.forEach( function( el ) { el.addEventListener( eventName, onNavigateDownClicked, false ); } ); dom.controlsPrev.forEach( function( el ) { el.addEventListener( eventName, onNavigatePrevClicked, false ); } );
dom.controlsPrev.forEach( function( el ) { el.addEventListener( eventName, onNavigatePrevClicked, false ); } ); dom.controlsNext.forEach( function( el ) { el.addEventListener( eventName, onNavigateNextClicked, false ); } );
dom.controlsNext.forEach( function( el ) { el.addEventListener( eventName, onNavigateNextClicked, false ); } ); } );
} );
}
} }
@ -624,16 +618,14 @@ var Reveal = (function(){
dom.progress.removeEventListener( 'click', onProgressClicked, false ); dom.progress.removeEventListener( 'click', onProgressClicked, false );
} }
if ( config.controls && dom.controls ) { [ 'touchstart', 'click' ].forEach( function( eventName ) {
[ 'touchstart', 'click' ].forEach( function( eventName ) { dom.controlsLeft.forEach( function( el ) { el.removeEventListener( eventName, onNavigateLeftClicked, false ); } );
dom.controlsLeft.forEach( function( el ) { el.removeEventListener( eventName, onNavigateLeftClicked, false ); } ); dom.controlsRight.forEach( function( el ) { el.removeEventListener( eventName, onNavigateRightClicked, false ); } );
dom.controlsRight.forEach( function( el ) { el.removeEventListener( eventName, onNavigateRightClicked, false ); } ); dom.controlsUp.forEach( function( el ) { el.removeEventListener( eventName, onNavigateUpClicked, false ); } );
dom.controlsUp.forEach( function( el ) { el.removeEventListener( eventName, onNavigateUpClicked, false ); } ); dom.controlsDown.forEach( function( el ) { el.removeEventListener( eventName, onNavigateDownClicked, false ); } );
dom.controlsDown.forEach( function( el ) { el.removeEventListener( eventName, onNavigateDownClicked, false ); } ); dom.controlsPrev.forEach( function( el ) { el.removeEventListener( eventName, onNavigatePrevClicked, false ); } );
dom.controlsPrev.forEach( function( el ) { el.removeEventListener( eventName, onNavigatePrevClicked, false ); } ); dom.controlsNext.forEach( function( el ) { el.removeEventListener( eventName, onNavigateNextClicked, false ); } );
dom.controlsNext.forEach( function( el ) { el.removeEventListener( eventName, onNavigateNextClicked, false ); } ); } );
} );
}
} }
@ -778,7 +770,7 @@ var Reveal = (function(){
*/ */
function hideAddressBar() { function hideAddressBar() {
if( /iphone|ipod|android/gi.test( navigator.userAgent ) && !/crios/gi.test( navigator.userAgent ) ) { if( config.hideAddressBar && isMobileDevice ) {
// Events that should trigger the address bar to hide // Events that should trigger the address bar to hide
window.addEventListener( 'load', removeAddressBar, false ); window.addEventListener( 'load', removeAddressBar, false );
window.addEventListener( 'orientationchange', removeAddressBar, false ); window.addEventListener( 'orientationchange', removeAddressBar, false );
@ -792,7 +784,8 @@ var Reveal = (function(){
*/ */
function removeAddressBar() { function removeAddressBar() {
if( window.orientation === 0 ) { // Portrait and not Chrome for iOS
if( window.orientation === 0 && !/crios/gi.test( navigator.userAgent ) ) {
document.documentElement.style.overflow = 'scroll'; document.documentElement.style.overflow = 'scroll';
document.body.style.height = '120%'; document.body.style.height = '120%';
} }
@ -1156,7 +1149,7 @@ var Reveal = (function(){
var depth = window.innerWidth < 400 ? 1000 : 2500; var depth = window.innerWidth < 400 ? 1000 : 2500;
dom.wrapper.classList.add( 'overview' ); dom.wrapper.classList.add( 'overview' );
dom.wrapper.classList.remove( 'exit-overview' ); dom.wrapper.classList.remove( 'overview-deactivating' );
clearTimeout( activateOverviewTimeout ); clearTimeout( activateOverviewTimeout );
clearTimeout( deactivateOverviewTimeout ); clearTimeout( deactivateOverviewTimeout );
@ -1164,7 +1157,7 @@ var Reveal = (function(){
// Not the pretties solution, but need to let the overview // Not the pretties solution, but need to let the overview
// class apply first so that slides are measured accurately // class apply first so that slides are measured accurately
// before we can position them // before we can position them
activateOverviewTimeout = setTimeout( function(){ activateOverviewTimeout = setTimeout( function() {
var horizontalSlides = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ); var horizontalSlides = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
@ -1241,25 +1234,19 @@ var Reveal = (function(){
// Temporarily add a class so that transitions can do different things // Temporarily add a class so that transitions can do different things
// depending on whether they are exiting/entering overview, or just // depending on whether they are exiting/entering overview, or just
// moving from slide to slide // moving from slide to slide
dom.wrapper.classList.add( 'exit-overview' ); dom.wrapper.classList.add( 'overview-deactivating' );
deactivateOverviewTimeout = setTimeout( function () { deactivateOverviewTimeout = setTimeout( function () {
dom.wrapper.classList.remove( 'exit-overview' ); dom.wrapper.classList.remove( 'overview-deactivating' );
}, 10); }, 1 );
// Select all slides // Select all slides
var slides = toArray( document.querySelectorAll( SLIDES_SELECTOR ) ); toArray( document.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) {
for( var i = 0, len = slides.length; i < len; i++ ) {
var element = slides[i];
element.style.display = '';
// Resets all transforms to use the external styles // Resets all transforms to use the external styles
transformElement( element, '' ); transformElement( slide, '' );
element.removeEventListener( 'click', onOverviewSlideClicked, true ); slide.removeEventListener( 'click', onOverviewSlideClicked, true );
} } );
slide( indexh, indexv ); slide( indexh, indexv );
@ -1792,48 +1779,45 @@ var Reveal = (function(){
*/ */
function updateControls() { function updateControls() {
if ( config.controls && dom.controls ) { var routes = availableRoutes();
var fragments = availableFragments();
var routes = availableRoutes(); // Remove the 'enabled' class from all directions
var fragments = availableFragments(); dom.controlsLeft.concat( dom.controlsRight )
.concat( dom.controlsUp )
.concat( dom.controlsDown )
.concat( dom.controlsPrev )
.concat( dom.controlsNext ).forEach( function( node ) {
node.classList.remove( 'enabled' );
node.classList.remove( 'fragmented' );
} );
// Remove the 'enabled' class from all directions // Add the 'enabled' class to the available routes
dom.controlsLeft.concat( dom.controlsRight ) if( routes.left ) dom.controlsLeft.forEach( function( el ) { el.classList.add( 'enabled' ); } );
.concat( dom.controlsUp ) if( routes.right ) dom.controlsRight.forEach( function( el ) { el.classList.add( 'enabled' ); } );
.concat( dom.controlsDown ) if( routes.up ) dom.controlsUp.forEach( function( el ) { el.classList.add( 'enabled' ); } );
.concat( dom.controlsPrev ) if( routes.down ) dom.controlsDown.forEach( function( el ) { el.classList.add( 'enabled' ); } );
.concat( dom.controlsNext ).forEach( function( node ) {
node.classList.remove( 'enabled' );
node.classList.remove( 'fragmented' );
} );
// Add the 'enabled' class to the available routes // Prev/next buttons
if( routes.left ) dom.controlsLeft.forEach( function( el ) { el.classList.add( 'enabled' ); } ); if( routes.left || routes.up ) dom.controlsPrev.forEach( function( el ) { el.classList.add( 'enabled' ); } );
if( routes.right ) dom.controlsRight.forEach( function( el ) { el.classList.add( 'enabled' ); } ); if( routes.right || routes.down ) dom.controlsNext.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' ); } );
// Prev/next buttons // Highlight fragment directions
if( routes.left || routes.up ) dom.controlsPrev.forEach( function( el ) { el.classList.add( 'enabled' ); } ); if( currentSlide ) {
if( routes.right || routes.down ) dom.controlsNext.forEach( function( el ) { el.classList.add( 'enabled' ); } );
// Highlight fragment directions // Always apply fragment decorator to prev/next buttons
if( currentSlide ) { 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' ); } );
// Always apply fragment decorator to prev/next buttons // Apply fragment decorators to directional buttons based on
if( fragments.prev ) dom.controlsPrev.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } ); // what slide axis they are in
if( fragments.next ) dom.controlsNext.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } ); if( isVerticalSlide( currentSlide ) ) {
if( fragments.prev ) dom.controlsUp.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
// Apply fragment decorators to directional buttons based on if( fragments.next ) dom.controlsDown.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
// what slide axis they are in }
if( isVerticalSlide( currentSlide ) ) { else {
if( fragments.prev ) dom.controlsUp.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } ); if( fragments.prev ) dom.controlsLeft.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
if( fragments.next ) dom.controlsDown.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } ); if( fragments.next ) dom.controlsRight.forEach( function( el ) { el.classList.add( 'fragmented', 'enabled' ); } );
}
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' ); } );
}
} }
} }

4
js/reveal.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -13,11 +13,13 @@ pre code {
pre .keyword, pre .keyword,
pre .tag, pre .tag,
pre .django .tag,
pre .django .keyword,
pre .css .class, pre .css .class,
pre .css .id, pre .css .id,
pre .lisp .title { pre .lisp .title,
pre .nginx .title,
pre .request,
pre .status,
pre .clojure .attribute {
color: #E3CEAB; color: #E3CEAB;
} }
@ -49,32 +51,27 @@ pre .tex .special {
} }
pre .diff .chunk, pre .diff .chunk,
pre .ruby .subst { pre .subst {
color: #8F8F8F; color: #8F8F8F;
} }
pre .dos .keyword, pre .dos .keyword,
pre .python .decorator, pre .python .decorator,
pre .class .title, pre .title,
pre .haskell .label, pre .haskell .type,
pre .function .title,
pre .ini .title,
pre .diff .header, pre .diff .header,
pre .ruby .class .parent, pre .ruby .class .parent,
pre .apache .tag, pre .apache .tag,
pre .nginx .built_in, pre .nginx .built_in,
pre .tex .command, pre .tex .command,
pre .input_number { pre .prompt {
color: #efef8f; color: #efef8f;
} }
pre .dos .winutils, pre .dos .winutils,
pre .ruby .symbol, pre .ruby .symbol,
pre .ruby .symbol .string, pre .ruby .symbol .string,
pre .ruby .symbol .keyword, pre .ruby .string {
pre .ruby .symbol .keymethods,
pre .ruby .string,
pre .ruby .instancevar {
color: #DCA3A3; color: #DCA3A3;
} }
@ -106,10 +103,12 @@ pre .doctype {
color: #7F9F7F; color: #7F9F7F;
} }
pre .xml .css, pre .coffeescript .javascript,
pre .javascript .xml,
pre .tex .formula,
pre .xml .javascript, pre .xml .javascript,
pre .xml .vbscript, pre .xml .vbscript,
pre .tex .formula { pre .xml .css,
pre .xml .cdata {
opacity: 0.5; opacity: 0.5;
} }

View File

@ -21,19 +21,19 @@
"node": "~0.8.0" "node": "~0.8.0"
}, },
"dependencies": { "dependencies": {
"underscore": "~1.3.3", "underscore": "~1.5.1",
"express": "~2.5.9", "express": "~2.5.9",
"mustache": "~0.4.0", "mustache": "~0.7.2",
"socket.io": "~0.9.13" "socket.io": "~0.9.13"
}, },
"devDependencies": { "devDependencies": {
"grunt-contrib-qunit": "~0.2.2", "grunt-contrib-qunit": "~0.2.2",
"grunt-contrib-jshint": "~0.2.0", "grunt-contrib-jshint": "~0.6.4",
"grunt-contrib-cssmin": "~0.4.1", "grunt-contrib-cssmin": "~0.4.1",
"grunt-contrib-uglify": "~0.1.1", "grunt-contrib-uglify": "~0.2.4",
"grunt-contrib-watch": "~0.2.0", "grunt-contrib-watch": "~0.5.3",
"grunt-contrib-sass": "~0.2.2", "grunt-contrib-sass": "~0.5.0",
"grunt-contrib-connect": "~0.2.0", "grunt-contrib-connect": "~0.4.1",
"grunt-zip": "~0.7.0", "grunt-zip": "~0.7.0",
"grunt": "~0.4.0" "grunt": "~0.4.0"
}, },

View File

@ -3,7 +3,16 @@
* markdown inside of presentations as well as loading * markdown inside of presentations as well as loading
* of external markdown documents. * of external markdown documents.
*/ */
(function(){ (function( root, factory ) {
if( typeof exports === 'object' ) {
module.exports = factory( require( './marked' ) );
}
else {
// Browser globals (root is window)
root.RevealMarkdown = factory( root.marked );
root.RevealMarkdown.initialize();
}
}( this, function( marked ) {
if( typeof marked === 'undefined' ) { if( typeof marked === 'undefined' ) {
throw 'The reveal.js Markdown plugin requires marked to be loaded'; throw 'The reveal.js Markdown plugin requires marked to be loaded';
@ -17,6 +26,10 @@
}); });
} }
var DEFAULT_SLIDE_SEPARATOR = '^\n---\n$',
DEFAULT_NOTES_SEPARATOR = 'note:';
/** /**
* Retrieves the markdown contents of a slide section * Retrieves the markdown contents of a slide section
* element. Normalizes leading tabs/whitespace. * element. Normalizes leading tabs/whitespace.
@ -72,15 +85,32 @@
} }
/**
* Inspects the given options and fills out default
* values for what's not defined.
*/
function getSlidifyOptions( options ) {
options = options || {};
options.separator = options.separator || DEFAULT_SLIDE_SEPARATOR;
options.notesSeparator = options.notesSeparator || DEFAULT_NOTES_SEPARATOR;
options.attributes = options.attributes || '';
return options;
}
/** /**
* Helper function for constructing a markdown slide. * Helper function for constructing a markdown slide.
*/ */
function createMarkdownSlide( data ) { function createMarkdownSlide( content, options ) {
var content = data.content || data; options = getSlidifyOptions( options );
if( data.notes ) { var notesMatch = content.split( new RegExp( options.notesSeparator, 'mgi' ) );
content += '<aside class="notes" data-markdown>' + data.notes + '</aside>';
if( notesMatch.length === 2 ) {
content = notesMatch[0] + '<aside class="notes" data-markdown>' + notesMatch[1].trim() + '</aside>';
} }
return '<script type="text/template">' + content + '</script>'; return '<script type="text/template">' + content + '</script>';
@ -91,25 +121,18 @@
* Parses a data string into multiple slides based * Parses a data string into multiple slides based
* on the passed in separator arguments. * on the passed in separator arguments.
*/ */
function slidifyMarkdown( markdown, options ) { function slidify( markdown, options ) {
options = options || {}; options = getSlidifyOptions( options );
options.separator = options.separator || '^\n---\n$';
options.notesSeparator = options.notesSeparator || 'note:';
options.attributes = options.attributes || '';
var separatorRegex = new RegExp( options.separator + ( options.verticalSeparator ? '|' + options.verticalSeparator : '' ), 'mg' ), var separatorRegex = new RegExp( options.separator + ( options.verticalSeparator ? '|' + options.verticalSeparator : '' ), 'mg' ),
horizontalSeparatorRegex = new RegExp( options.separator ), horizontalSeparatorRegex = new RegExp( options.separator );
notesSeparatorRegex = new RegExp( options.notesSeparator, 'mgi' );
var matches, var matches,
noteMatch,
lastIndex = 0, lastIndex = 0,
isHorizontal, isHorizontal,
wasHorizontal = true, wasHorizontal = true,
content, content,
notes,
slide,
sectionStack = []; sectionStack = [];
// iterate until all blocks between separators are stacked up // iterate until all blocks between separators are stacked up
@ -126,25 +149,14 @@
// pluck slide content from markdown input // pluck slide content from markdown input
content = markdown.substring( lastIndex, matches.index ); content = markdown.substring( lastIndex, matches.index );
noteMatch = content.split( notesSeparatorRegex );
if( noteMatch.length === 2 ) {
content = noteMatch[0];
notes = noteMatch[1].trim();
}
slide = {
content: content,
notes: notes || ''
};
if( isHorizontal && wasHorizontal ) { if( isHorizontal && wasHorizontal ) {
// add to horizontal stack // add to horizontal stack
sectionStack.push( slide ); sectionStack.push( content );
} }
else { else {
// add to vertical stack // add to vertical stack
sectionStack[sectionStack.length-1].push( slide ); sectionStack[sectionStack.length-1].push( content );
} }
lastIndex = separatorRegex.lastIndex; lastIndex = separatorRegex.lastIndex;
@ -160,12 +172,16 @@
for( var i = 0, len = sectionStack.length; i < len; i++ ) { for( var i = 0, len = sectionStack.length; i < len; i++ ) {
// vertical // vertical
if( sectionStack[i].propertyIsEnumerable( length ) && typeof sectionStack[i].splice === 'function' ) { if( sectionStack[i].propertyIsEnumerable( length ) && typeof sectionStack[i].splice === 'function' ) {
markdownSections += '<section '+ options.attributes +'>' + markdownSections += '<section '+ options.attributes +'>';
'<section data-markdown>' + sectionStack[i].map( createMarkdownSlide ).join( '</section><section data-markdown>' ) + '</section>' +
'</section>'; sectionStack[i].forEach( function( child ) {
markdownSections += '<section data-markdown>' + createMarkdownSlide( child, options ) + '</section>';
} );
markdownSections += '</section>';
} }
else { else {
markdownSections += '<section '+ options.attributes +' data-markdown>' + createMarkdownSlide( sectionStack[i] ) + '</section>'; markdownSections += '<section '+ options.attributes +' data-markdown>' + createMarkdownSlide( sectionStack[i], options ) + '</section>';
} }
} }
@ -173,7 +189,12 @@
} }
function loadExternalMarkdown() { /**
* Parses any current data-markdown slides, splits
* multi-slide markdown into separate sections and
* handles loading of external markdown.
*/
function processSlides() {
var sections = document.querySelectorAll( '[data-markdown]'), var sections = document.querySelectorAll( '[data-markdown]'),
section; section;
@ -198,7 +219,7 @@
if( xhr.readyState === 4 ) { if( xhr.readyState === 4 ) {
if ( xhr.status >= 200 && xhr.status < 300 ) { if ( xhr.status >= 200 && xhr.status < 300 ) {
section.outerHTML = slidifyMarkdown( xhr.responseText, { section.outerHTML = slidify( xhr.responseText, {
separator: section.getAttribute( 'data-separator' ), separator: section.getAttribute( 'data-separator' ),
verticalSeparator: section.getAttribute( 'data-vertical' ), verticalSeparator: section.getAttribute( 'data-vertical' ),
notesSeparator: section.getAttribute( 'data-notes' ), notesSeparator: section.getAttribute( 'data-notes' ),
@ -228,9 +249,9 @@
} }
} }
else if( section.getAttribute( 'data-separator' ) ) { else if( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-vertical' ) || section.getAttribute( 'data-notes' ) ) {
section.outerHTML = slidifyMarkdown( getMarkdownFromSlide( section ), { section.outerHTML = slidify( getMarkdownFromSlide( section ), {
separator: section.getAttribute( 'data-separator' ), separator: section.getAttribute( 'data-separator' ),
verticalSeparator: section.getAttribute( 'data-vertical' ), verticalSeparator: section.getAttribute( 'data-vertical' ),
notesSeparator: section.getAttribute( 'data-notes' ), notesSeparator: section.getAttribute( 'data-notes' ),
@ -238,11 +259,20 @@
}); });
} }
else {
section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) );
}
} }
} }
function convertMarkdownToHTML() { /**
* Converts any current data-markdown slides in the
* DOM to HTML.
*/
function convertSlides() {
var sections = document.querySelectorAll( '[data-markdown]'); var sections = document.querySelectorAll( '[data-markdown]');
@ -250,22 +280,41 @@
var section = sections[i]; var section = sections[i];
var notes = section.querySelector( 'aside.notes' ); // Only parse the same slide once
var markdown = getMarkdownFromSlide( section ); if( !section.getAttribute( 'data-markdown-parsed' ) ) {
section.innerHTML = marked( markdown ); section.setAttribute( 'data-markdown-parsed', true )
var notes = section.querySelector( 'aside.notes' );
var markdown = getMarkdownFromSlide( section );
section.innerHTML = marked( markdown );
// If there were notes, we need to re-add them after
// having overwritten the section's HTML
if( notes ) {
section.appendChild( notes );
}
// If there were notes, we need to re-add them after
// having overwritten the section's HTML
if( notes ) {
section.appendChild( notes );
} }
} }
} }
loadExternalMarkdown(); // API
convertMarkdownToHTML(); return {
})(); initialize: function() {
processSlides();
convertSlides();
},
// TODO: Do these belong in the API?
processSlides: processSlides,
convertSlides: convertSlides,
slidify: slidify
};
}));

View File

@ -1,6 +1,7 @@
(function() { (function() {
// don't emit events from inside the previews themselves // Don't emit events from inside of notes windows
if ( window.location.search.match( /receiver/gi ) ) { return; } if ( window.location.search.match( /receiver/gi ) ) { return; }
var multiplex = Reveal.getConfig().multiplex; var multiplex = Reveal.getConfig().multiplex;
var socket = io.connect(multiplex.url); var socket = io.connect(multiplex.url);

View File

@ -139,11 +139,11 @@
<body> <body>
<div id="wrap-current-slide" class="slides"> <div id="wrap-current-slide" class="slides">
<script>document.write( '<iframe width="1280" height="1024" id="current-slide" src="'+ window.opener.location.href +'"></iframe>' );</script> <script>document.write( '<iframe width="1280" height="1024" id="current-slide" src="'+ window.opener.location.href +'?receiver"></iframe>' );</script>
</div> </div>
<div id="wrap-next-slide" class="slides"> <div id="wrap-next-slide" class="slides">
<script>document.write( '<iframe width="640" height="512" id="next-slide" src="'+ window.opener.location.href +'"></iframe>' );</script> <script>document.write( '<iframe width="640" height="512" id="next-slide" src="'+ window.opener.location.href +'?receiver"></iframe>' );</script>
<span>UPCOMING:</span> <span>UPCOMING:</span>
</div> </div>
@ -239,6 +239,10 @@
currentSlide.contentWindow.Reveal.addEventListener( 'fragmentshown', synchronizeMainWindow ); currentSlide.contentWindow.Reveal.addEventListener( 'fragmentshown', synchronizeMainWindow );
currentSlide.contentWindow.Reveal.addEventListener( 'fragmenthidden', synchronizeMainWindow ); currentSlide.contentWindow.Reveal.addEventListener( 'fragmenthidden', synchronizeMainWindow );
// Reconfigure the notes window to remove needless UI
currentSlide.contentWindow.Reveal.configure({ controls: false, progress: false, overview: false });
nextSlide.contentWindow.Reveal.configure({ controls: false, progress: false, overview: false });
} }
else { else {

View File

@ -17,11 +17,11 @@
* Detects if notes are enable and the current page is opened inside an /iframe * Detects if notes are enable and the current page is opened inside an /iframe
* this prevents loading Remotes.io several times * this prevents loading Remotes.io several times
*/ */
var remotesAndIsNotes = (function(){ var isNotesAndIframe = (function(){
return !(window.RevealNotes && self == top); return window.RevealNotes && !(self == top);
})(); })();
if(!hasTouch && !remotesAndIsNotes){ if(!hasTouch && !isNotesAndIframe){
head.ready( 'remotes.ne.min.js', function() { head.ready( 'remotes.ne.min.js', function() {
new Remotes("preview") new Remotes("preview")
.on("swipe-left", function(e){ Reveal.right(); }) .on("swipe-left", function(e){ Reveal.right(); })

52
test/test-markdown.html Normal file
View File

@ -0,0 +1,52 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Test Markdown</title>
<link rel="stylesheet" href="../css/reveal.min.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="example.md" data-separator="^\n\n\n" data-vertical="^\n\n"></section> -->
<!-- Slides are separated by newline + three dashes + newline, vertical slides identical but two dashes -->
<section data-markdown data-separator="^\n---\n$" data-vertical="^\n--\n$">
<script type="text/template">
## Slide 1.1
--
## Slide 1.2
---
## Slide 2
</script>
</section>
</div>
</div>
<script src="../lib/js/head.min.js"></script>
<script src="../js/reveal.min.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.js"></script>
</body>
</html>

15
test/test-markdown.js Normal file
View File

@ -0,0 +1,15 @@
Reveal.addEventListener( 'ready', function() {
QUnit.module( 'Markdown' );
test( 'Vertical separator', function() {
strictEqual( document.querySelectorAll( '.reveal .slides>section>section' ).length, 2, 'found two slides' );
});
} );
Reveal.initialize();