Merge branch 'attributes' of https://github.com/VonC/reveal.js into dev

This commit is contained in:
Hakim El Hattab 2013-12-02 12:12:27 +01:00
commit 65bd155c34
6 changed files with 196 additions and 154 deletions

View file

@ -60,25 +60,25 @@ You can write your content as a separate file and have reveal.js load it at runt
#### Element Attributes #### Element Attributes
Special syntax is available for adding attributes to Markdown elements. This is useful for fragments, amongst other things. Special syntax (in html comment) is available for adding attributes to Markdown elements. This is useful for fragments, amongst other things.
```html ```html
<section data-markdown> <section data-markdown>
<script type="text/template"> <script type="text/template">
- Item 1 {.class="fragment" data-fragment-index="2"} - Item 1 <!-- .element: class="fragment" data-fragment-index="2" -->
- Item 2 {.class="fragment" data-fragment-index="1"} - Item 2 <!-- .element: class="fragment" data-fragment-index="1" -->
</script> </script>
</section> </section>
``` ```
#### Slide Attributes #### Slide Attributes
Special syntax is available for adding attributes to the slide `<section>` elements generated by your Markdown. Special syntax (in html comment) is available for adding attributes to the slide `<section>` elements generated by your Markdown.
```html ```html
<section data-markdown> <section data-markdown>
<script type="text/template"> <script type="text/template">
<!-- slide-attributes: data-background="#ff0000" --> <!-- slide: data-background="#ff0000" -->
Mardown content Mardown content
</script> </script>
</section> </section>

View file

@ -28,8 +28,8 @@
var DEFAULT_SLIDE_SEPARATOR = '^\n---\n$', var DEFAULT_SLIDE_SEPARATOR = '^\n---\n$',
DEFAULT_NOTES_SEPARATOR = 'note:', DEFAULT_NOTES_SEPARATOR = 'note:',
DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '{\\\.\s*?([^}]+?)}', DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$',
DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '^.*?<!--\\\sslide-attributes:\\\s(.*?)-->'; DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\\.slide:\\\s*?(\\\S.+?)$';
/** /**
@ -73,7 +73,7 @@
value = attributes[i].value; value = attributes[i].value;
// disregard attributes that are used for markdown loading/parsing // disregard attributes that are used for markdown loading/parsing
if( /data\-(markdown|separator|vertical|notes|attributes)/gi.test( name ) ) continue; if( /data\-(markdown|separator|vertical|notes)/gi.test( name ) ) continue;
if( value ) { if( value ) {
result.push( name + '=' + value ); result.push( name + '=' + value );
@ -97,7 +97,6 @@
options.separator = options.separator || DEFAULT_SLIDE_SEPARATOR; options.separator = options.separator || DEFAULT_SLIDE_SEPARATOR;
options.notesSeparator = options.notesSeparator || DEFAULT_NOTES_SEPARATOR; options.notesSeparator = options.notesSeparator || DEFAULT_NOTES_SEPARATOR;
options.attributes = options.attributes || ''; options.attributes = options.attributes || '';
options.slideAttributesSeparator = options.slideAttributesSeparator || DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR;
return options; return options;
@ -129,17 +128,14 @@
options = getSlidifyOptions( options ); options = getSlidifyOptions( options );
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 );
slideAttributesSeparatorRegex = new RegExp( options.slideAttributesSeparator, 'm' );
var matches, var matches,
lastIndex = 0, lastIndex = 0,
isHorizontal, isHorizontal,
wasHorizontal = true, wasHorizontal = true,
content, content,
sectionStack = [], sectionStack = [];
matchAttributes,
slideAttributes = "";
// iterate until all blocks between separators are stacked up // iterate until all blocks between separators are stacked up
while( matches = separatorRegex.exec( markdown ) ) { while( matches = separatorRegex.exec( markdown ) ) {
@ -178,35 +174,19 @@
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] instanceof Array ) { if( sectionStack[i] instanceof Array ) {
// The 'data-xxx' attributes of the first child must be set on the wrapping parent section to be effective markdownSections += '<section '+ options.attributes +'>';
// Mainly for data-transition (otherwise, it is ignored for the first vertical slide)
firstChild = sectionStack[i][0];
matchAttributes = slideAttributesSeparatorRegex.exec( firstChild );
slideAttributes = matchAttributes ? matchAttributes[1] : "";
dataAttributes = "";
if( slideAttributes != "" ) {
// http://stackoverflow.com/questions/18025762/javascript-regex-replace-all-word-characters-except-word-characters-between-ch
// Keep only data-attributes for the parent slide section.
dataAttributes = slideAttributes.replace( /(data-\S+=\"[^\"]+?\")|\w|[\"=]/g, function(a, b) { return b || ''; });
}
markdownSections += '<section '+ options.attributes + ' ' + dataAttributes + '>';
sectionStack[i].forEach( function( child ) { sectionStack[i].forEach( function( child ) {
matchAttributes = slideAttributesSeparatorRegex.exec( child ); markdownSections += '<section data-markdown>' + createMarkdownSlide( child, options ) + '</section>';
slideAttributes = matchAttributes ? matchAttributes[1] : "";
child = matchAttributes ? child.replace( slideAttributesSeparatorRegex,"" ) : child
markdownSections += '<section ' + slideAttributes + ' data-markdown>' + createMarkdownSlide( child, options ) + '</section>';
} ); } );
markdownSections += '</section>'; markdownSections += '</section>';
} }
else { else {
matchAttributes = slideAttributesSeparatorRegex.exec( sectionStack[i] ); markdownSections += '<section '+ options.attributes +' data-markdown>' + createMarkdownSlide( sectionStack[i], options ) + '</section>';
slideAttributes = matchAttributes ? matchAttributes[1] : "";
content = matchAttributes ? sectionStack[i].replace( slideAttributesSeparatorRegex,"" ) : sectionStack[i]
markdownSections += '<section '+ options.attributes + ' ' + slideAttributes +' data-markdown>' + createMarkdownSlide( content, options ) + '</section>';
} }
} }
return markdownSections; return markdownSections;
} }
@ -240,12 +220,12 @@
xhr.onreadystatechange = function() { xhr.onreadystatechange = function() {
if( xhr.readyState === 4 ) { if( xhr.readyState === 4 ) {
if ( xhr.status >= 200 && xhr.status < 300 ) { if ( xhr.status >= 200 && xhr.status < 300 ) {
section.outerHTML = slidify( 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' ),
attributes: getForwardedAttributes( section ), attributes: getForwardedAttributes( section )
slideAttributesSeparator: section.getAttribute( 'data-attributes' ),
}); });
} }
@ -277,24 +257,12 @@
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' ),
attributes: getForwardedAttributes( section ), attributes: getForwardedAttributes( section )
slideAttributesSeparator: section.getAttribute( 'data-attributes' ),
}); });
} }
else { else {
var content = getMarkdownFromSlide( section ); section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) );
var slideAttributesSeparatorRegex = new RegExp( section.getAttribute( 'data-attributes' ) || DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR, 'm' );
var matchAttributes = slideAttributesSeparatorRegex.exec( content );
if ( matchAttributes ) {
var slideAttributes = matchAttributes[1];
content = content.replace( slideAttributesSeparatorRegex,"" );
var slideAttributesRegex = new RegExp( "([^\"= ]+?)=\"([^\"=]+?)\"", 'mg' );
while( matchesAttributes = slideAttributesRegex.exec( slideAttributes ) ) {
section.setAttribute( matchesAttributes[1], matchesAttributes[2] );
}
}
section.innerHTML = createMarkdownSlide( content );
} }
} }
@ -319,40 +287,51 @@
var classes = matches[1]; var classes = matches[1];
nodeValue = nodeValue.substring( 0, matches.index ) + nodeValue.substring( mardownClassesInElementsRegex.lastIndex ); nodeValue = nodeValue.substring( 0, matches.index ) + nodeValue.substring( mardownClassesInElementsRegex.lastIndex );
node.nodeValue = nodeValue; node.nodeValue = nodeValue;
while( matchesClass = mardownClassRegex.exec( classes ) ) { while( matchesClass = mardownClassRegex.exec( classes ) ) {
elementTarget.setAttribute( matchesClass[1], matchesClass[2] ); elementTarget.setAttribute( matchesClass[1], matchesClass[2] );
} }
return true;
} }
return false;
} }
/** /**
* Add attributes to the parent element of a text node, * Add attributes to the parent element of a text node,
* or the element of an attribute node. * or the element of an attribute node.
*/ */
function addAttributes( element, separator ) { function addAttributes( section, element, previousElement, separatorElementAttributes, separatorSectionAttributes ) {
if( element.childNodes.length > 0 ) { if ( element != null && element.childNodes != undefined && element.childNodes.length > 0 ) {
previousParentElement = element;
for( var i = 0; i < element.childNodes.length; i++ ) { for( var i = 0; i < element.childNodes.length; i++ ) {
addAttributes( element.childNodes[i], separator ); childElement = element.childNodes[i];
if ( i > 0 ) {
j = i - 1;
while ( j >= 0 ) {
aPreviousChildElement = element.childNodes[j];
if ( typeof aPreviousChildElement.setAttribute == 'function' && aPreviousChildElement.tagName != "BR" ) {
previousParentElement = aPreviousChildElement;
break;
}
j = j - 1;
}
}
parentSection = section;
if( childElement.nodeName == "section" ) {
parentSection = childElement ;
previousParentElement = childElement ;
}
if ( typeof childElement.setAttribute == 'function' || childElement.nodeType == Node.COMMENT_NODE ) {
addAttributes( parentSection, childElement, previousParentElement, separatorElementAttributes, separatorSectionAttributes );
}
} }
} }
var nodeValue; if ( element.nodeType == Node.COMMENT_NODE ) {
var elementTarget; if ( addAttributeInElement( element, previousElement, separatorElementAttributes ) == false ) {
addAttributeInElement( element, section, separatorSectionAttributes );
// From http://stackoverflow.com/questions/9178174/find-all-text-nodes
if( element.nodeType == Node.TEXT_NODE && /\S/.test(element.nodeValue) ) {
addAttributeInElement( element, element.parentNode, separator );
}
if( element.nodeType == Node.ELEMENT_NODE && element.attributes.length > 0 ) {
for( var j = 0; j < element.attributes.length; j++ ){
var attr = element.attributes[j];
addAttributeInElement( attr, element, separator );
} }
} }
} }
/** /**
@ -376,9 +355,12 @@
var markdown = getMarkdownFromSlide( section ); var markdown = getMarkdownFromSlide( section );
section.innerHTML = marked( markdown ); section.innerHTML = marked( markdown );
addAttributes( section, section.getAttribute( 'data-element-attributes' ) || addAttributes( section, section, null, section.getAttribute( 'data-element-attributes' ) ||
section.parentNode.getAttribute( 'data-element-attributes' ) || section.parentNode.getAttribute( 'data-element-attributes' ) ||
DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR ); DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR,
section.getAttribute( 'data-attributes' ) ||
section.parentNode.getAttribute( 'data-attributes' ) ||
DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR);
// If there were notes, we need to re-add them after // If there were notes, we need to re-add them after
// having overwritten the section's HTML // having overwritten the section's HTML

View file

@ -25,7 +25,7 @@
<section data-markdown data-separator="^\n\n\n" <section data-markdown data-separator="^\n\n\n"
data-vertical="^\n\n" data-vertical="^\n\n"
data-notes="^Note:" data-notes="^Note:"
data-attributes="^\s*?--\s(.*?)$" data-attributes="--\s(.*?)$"
data-charset="utf-8"> data-charset="utf-8">
<script type="text/template"> <script type="text/template">
# Test attributes in Markdown # Test attributes in Markdown
@ -34,11 +34,11 @@
## Slide 2 ## Slide 2
-- id="slide2" data-transition="zoom" data-background="#A0C66B" <!-- -- id="slide2" data-transition="zoom" data-background="#A0C66B" -->
## Slide 2.1 ## Slide 2.1
-- data-background="#ff0000" data-transition="fade" <!-- -- data-background="#ff0000" data-transition="fade" -->
## Slide 2.2 ## Slide 2.2
@ -47,7 +47,7 @@
## Slide 3 ## Slide 3
-- data-transition="zoom" data-background="#C6916B" <!-- -- data-transition="zoom" data-background="#C6916B" -->
@ -66,11 +66,11 @@
## Slide 2 Def ## Slide 2 Def
<!-- slide-attributes: id="slide2def" data-transition="concave" data-background="#A7C66B" --> <!-- .slide: id="slide2def" data-transition="concave" data-background="#A7C66B" -->
## Slide 2.1 Def ## Slide 2.1 Def
<!-- slide-attributes: data-background="#f70000" data-transition="page" --> <!-- .slide: data-background="#f70000" data-transition="page" -->
## Slide 2.2 Def ## Slide 2.2 Def
@ -79,7 +79,7 @@
## Slide 3 Def ## Slide 3 Def
<!-- slide-attributes: data-transition="concave" data-background="#C7916B" --> <!-- .slide: data-transition="concave" data-background="#C7916B" -->
@ -89,7 +89,7 @@
<section data-markdown> <section data-markdown>
<script type="text/template"> <script type="text/template">
<!-- slide-attributes: data-background="#ff0000" --> <!-- .slide: data-background="#ff0000" -->
## Hello world ## Hello world
</script> </script>
</section> </section>
@ -97,7 +97,7 @@
<section data-markdown> <section data-markdown>
<script type="text/template"> <script type="text/template">
## Hello world ## Hello world
<!-- slide-attributes: data-background="#ff0000" --> <!-- .slide: data-background="#ff0000" -->
</script> </script>
</section> </section>
@ -106,7 +106,7 @@
## Hello world ## Hello world
Test Test
<!-- slide-attributes: data-background="#ff0000" --> <!-- .slide: data-background="#ff0000" -->
More Test More Test
</script> </script>

View file

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>reveal.js - Test Markdown</title> <title>reveal.js - Test Markdown Element Attributes</title>
<link rel="stylesheet" href="../css/reveal.min.css"> <link rel="stylesheet" href="../css/reveal.min.css">
<link rel="stylesheet" href="qunit-1.12.0.css"> <link rel="stylesheet" href="qunit-1.12.0.css">
@ -24,19 +24,23 @@
<!-- Slides are separated by newline + three dashes + newline, vertical slides identical but two dashes --> <!-- 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$" data-element-attributes="{_\s*?([^}]+?)}">> <section data-markdown data-separator="^\n---\n$" data-vertical="^\n--\n$" data-element-attributes="{_\s*?([^}]+?)}">>
<script type="text/template"> <script type="text/template">
## Slide 1.1 {_class="fragment fade-out" data-fragment-index="1"} ## Slide 1.1
<!-- {_class="fragment fade-out" data-fragment-index="1"} -->
-- --
## Slide 1.2 {_class="fragment shrink"} ## Slide 1.2
<!-- {_class="fragment shrink"} -->
Paragraph 1 {_class="fragment grow"} Paragraph 1
<!-- {_class="fragment grow"} -->
Paragraph 2 {_class="fragment grow"} Paragraph 2
<!-- {_class="fragment grow"} -->
- list item 1 {_class="fragment roll-in"} - list item 1 <!-- {_class="fragment roll-in"} -->
- list item 2 {_class="fragment roll-in"} - list item 2 <!-- {_class="fragment roll-in"} -->
- list item 3 {_class="fragment roll-in"} - list item 3 <!-- {_class="fragment roll-in"} -->
--- ---
@ -45,27 +49,75 @@
Paragraph 1.2 Paragraph 1.2
multi-line {_class="fragment highlight-red"} multi-line <!-- {_class="fragment highlight-red"} -->
Paragraph 2.2 {_class="fragment highlight-red"} Paragraph 2.2 <!-- {_class="fragment highlight-red"} -->
Paragraph 2.3 {_class="fragment highlight-red"} Paragraph 2.3 <!-- {_class="fragment highlight-red"} -->
Paragraph 2.4 {_class="fragment highlight-red"} Paragraph 2.4 <!-- {_class="fragment highlight-red"} -->
- list item 1 {_class="fragment highlight-green"} - list item 1 <!-- {_class="fragment highlight-green"} -->
- list item 2 {_class="fragment highlight-green"} - list item 2<!-- {_class="fragment highlight-green"} -->
- list item 3 {_class="fragment highlight-green"} - list item 3<!-- {_class="fragment highlight-green"} -->
- list item 4 {_class="fragment highlight-green"} - list item 4
- list item 5 {_class="fragment highlight-green"} <!-- {_class="fragment highlight-green"} -->
- list item 5<!-- {_class="fragment highlight-green"} -->
Test Test
![Example Picture{_class="reveal stretch"}](assets/image2.png) ![Example Picture](examples/assets/image2.png)
<!-- {_class="reveal stretch"} -->
</script> </script>
</section> </section>
<section data-markdown data-separator="^\n\n\n"
data-vertical="^\n\n"
data-notes="^Note:"
data-charset="utf-8">
<script type="text/template">
# Test attributes in Markdown with default separator
## Slide 1 Def <!-- .element: class="fragment highlight-red" data-fragment-index="1" -->
## Slide 2 Def
<!-- .element: class="fragment highlight-red" -->
</script>
</section>
<section data-markdown>
<script type="text/template">
## Hello world
A paragraph
<!-- .element: class="fragment highlight-blue" -->
</script>
</section>
<section data-markdown>
<script type="text/template">
## Hello world
Multiple
Line
<!-- .element: class="fragment highlight-blue" -->
</script>
</section>
<section data-markdown>
<script type="text/template">
## Hello world
Test<!-- .element: class="fragment highlight-blue" -->
More Test
</script>
</section>
</div> </div>
</div> </div>

View file

@ -5,33 +5,41 @@ Reveal.addEventListener( 'ready', function() {
QUnit.module( 'Markdown' ); QUnit.module( 'Markdown' );
test( 'Vertical separator', function() { test( 'Vertical separator', function() {
strictEqual( document.querySelectorAll( '.reveal .slides>section>section' ).length, 2, 'found two slides' ); strictEqual( document.querySelectorAll( '.reveal .slides>section>section' ).length, 4, 'found four slides' );
}); });
test( 'Attributes on vertical slides header', function() { test( 'Attributes on element header in vertical slides', function() {
strictEqual( document.querySelectorAll( '.reveal .slides section>section h2.fragment.fade-out' ).length, 1, 'found one vertical slide with class fragment.fade-out on header' ); strictEqual( document.querySelectorAll( '.reveal .slides section>section h2.fragment.fade-out' ).length, 1, 'found one vertical slide with class fragment.fade-out on header' );
strictEqual( document.querySelectorAll( '.reveal .slides section>section h2.fragment.shrink' ).length, 1, 'found one vertical slide with class fragment.shrink on header' ); strictEqual( document.querySelectorAll( '.reveal .slides section>section h2.fragment.shrink' ).length, 1, 'found one vertical slide with class fragment.shrink on header' );
}); });
test( 'Attributes on vertical slides paragraphs', function() { test( 'Attributes on element paragraphs in vertical slides', function() {
strictEqual( document.querySelectorAll( '.reveal .slides section>section p.fragment.grow' ).length, 2, 'found a vertical slide with two paragraphs with class fragment.grow' ); strictEqual( document.querySelectorAll( '.reveal .slides section>section p.fragment.grow' ).length, 2, 'found a vertical slide with two paragraphs with class fragment.grow' );
}); });
test( 'Attributes on vertical slides list items', function() { test( 'Attributes on element list items in vertical slides', function() {
strictEqual( document.querySelectorAll( '.reveal .slides section>section li.fragment.roll-in' ).length, 3, 'found a vertical slide with three list items with class fragment.roll-in' ); strictEqual( document.querySelectorAll( '.reveal .slides section>section li.fragment.roll-in' ).length, 3, 'found a vertical slide with three list items with class fragment.roll-in' );
}); });
test( 'Attributes on horizontal slides paragraphs', function() { test( 'Attributes on element paragraphs in horizontal slides', function() {
strictEqual( document.querySelectorAll( '.reveal .slides section p.fragment.highlight-red' ).length, 4, 'found a horizontal slide with four paragraphs with class fragment.grow' ); strictEqual( document.querySelectorAll( '.reveal .slides section p.fragment.highlight-red' ).length, 4, 'found a horizontal slide with four paragraphs with class fragment.grow' );
}); });
test( 'Attributes on horizontal slides list items', function() { test( 'Attributes on element list items in horizontal slides', function() {
strictEqual( document.querySelectorAll( '.reveal .slides section li.fragment.highlight-green' ).length, 5, 'found a horizontal slide with five list items with class fragment.roll-in' ); strictEqual( document.querySelectorAll( '.reveal .slides section li.fragment.highlight-green' ).length, 5, 'found a horizontal slide with five list items with class fragment.roll-in' );
}); });
test( 'Attributes on horizontal slides list items', function() { test( 'Attributes on element list items in horizontal slides', function() {
strictEqual( document.querySelectorAll( '.reveal .slides section img.reveal.stretch' ).length, 1, 'found a horizontal slide with stretched image, class img.reveal.stretch' ); strictEqual( document.querySelectorAll( '.reveal .slides section img.reveal.stretch' ).length, 1, 'found a horizontal slide with stretched image, class img.reveal.stretch' );
}); });
test( 'Attributes on elements in vertical slides with default element attribute separator', function() {
strictEqual( document.querySelectorAll( '.reveal .slides section h2.fragment.highlight-red' ).length, 2, 'found two h2 titles with fragment highlight-red in vertical slides with default element attribute separator' );
});
test( 'Attributes on elements in single slides with default element attribute separator', function() {
strictEqual( document.querySelectorAll( '.reveal .slides section p.fragment.highlight-blue' ).length, 3, 'found three elements with fragment highlight-blue in single slide with default element attribute separator' );
});
} ); } );
Reveal.initialize(); Reveal.initialize();