mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-13 22:54:42 -04:00
Use JavaScript Standard Style (part 2)
Fixed all fail on frontend code.
This commit is contained in:
parent
4889e9732d
commit
5bc642d02e
19 changed files with 6790 additions and 7032 deletions
|
@ -1,396 +1,355 @@
|
|||
/* eslint-env browser, jquery */
|
||||
|
||||
import { preventXSS } from './render'
|
||||
import { md } from './extra'
|
||||
|
||||
/**
|
||||
* The reveal.js markdown plugin. Handles parsing of
|
||||
* markdown inside of presentations as well as loading
|
||||
* of external markdown documents.
|
||||
*/
|
||||
(function( root, factory ) {
|
||||
if( typeof exports === 'object' ) {
|
||||
module.exports = factory();
|
||||
}
|
||||
else {
|
||||
// Browser globals (root is window)
|
||||
root.RevealMarkdown = factory();
|
||||
root.RevealMarkdown.initialize();
|
||||
}
|
||||
}( this, function() {
|
||||
|
||||
var DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$',
|
||||
DEFAULT_NOTES_SEPARATOR = 'note:',
|
||||
DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$',
|
||||
DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\\.slide:\\\s*?(\\\S.+?)$';
|
||||
|
||||
var SCRIPT_END_PLACEHOLDER = '__SCRIPT_END__';
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the markdown contents of a slide section
|
||||
* element. Normalizes leading tabs/whitespace.
|
||||
*/
|
||||
function getMarkdownFromSlide( section ) {
|
||||
|
||||
var template = section.querySelector( 'script' );
|
||||
|
||||
// strip leading whitespace so it isn't evaluated as code
|
||||
var text = ( template || section ).textContent;
|
||||
|
||||
// restore script end tags
|
||||
text = text.replace( new RegExp( SCRIPT_END_PLACEHOLDER, 'g' ), '</script>' );
|
||||
|
||||
var leadingWs = text.match( /^\n?(\s*)/ )[1].length,
|
||||
leadingTabs = text.match( /^\n?(\t*)/ )[1].length;
|
||||
|
||||
if( leadingTabs > 0 ) {
|
||||
text = text.replace( new RegExp('\\n?\\t{' + leadingTabs + '}','g'), '\n' );
|
||||
}
|
||||
else if( leadingWs > 1 ) {
|
||||
text = text.replace( new RegExp('\\n? {' + leadingWs + '}', 'g'), '\n' );
|
||||
}
|
||||
|
||||
return text;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a markdown slide section element, this will
|
||||
* return all arguments that aren't related to markdown
|
||||
* parsing. Used to forward any other user-defined arguments
|
||||
* to the output markdown slide.
|
||||
*/
|
||||
function getForwardedAttributes( section ) {
|
||||
|
||||
var attributes = section.attributes;
|
||||
var result = [];
|
||||
|
||||
for( var i = 0, len = attributes.length; i < len; i++ ) {
|
||||
var name = attributes[i].name,
|
||||
value = attributes[i].value;
|
||||
|
||||
// disregard attributes that are used for markdown loading/parsing
|
||||
if( /data\-(markdown|separator|vertical|notes)/gi.test( name ) ) continue;
|
||||
|
||||
if( value ) {
|
||||
result.push( name + '="' + value + '"' );
|
||||
}
|
||||
else {
|
||||
result.push( name );
|
||||
}
|
||||
}
|
||||
|
||||
return result.join( ' ' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function createMarkdownSlide( content, options ) {
|
||||
|
||||
options = getSlidifyOptions( options );
|
||||
|
||||
var notesMatch = content.split( new RegExp( options.notesSeparator, 'mgi' ) );
|
||||
|
||||
if( notesMatch.length === 2 ) {
|
||||
content = notesMatch[0] + '<aside class="notes" data-markdown>' + notesMatch[1].trim() + '</aside>';
|
||||
}
|
||||
|
||||
// prevent script end tags in the content from interfering
|
||||
// with parsing
|
||||
content = content.replace( /<\/script>/g, SCRIPT_END_PLACEHOLDER );
|
||||
|
||||
return '<script type="text/template">' + content + '</script>';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a data string into multiple slides based
|
||||
* on the passed in separator arguments.
|
||||
*/
|
||||
function slidify( markdown, options ) {
|
||||
|
||||
options = getSlidifyOptions( options );
|
||||
|
||||
var separatorRegex = new RegExp( options.separator + ( options.verticalSeparator ? '|' + options.verticalSeparator : '' ), 'mg' ),
|
||||
horizontalSeparatorRegex = new RegExp( options.separator );
|
||||
|
||||
var matches,
|
||||
lastIndex = 0,
|
||||
isHorizontal,
|
||||
wasHorizontal = true,
|
||||
content,
|
||||
sectionStack = [];
|
||||
|
||||
// iterate until all blocks between separators are stacked up
|
||||
while( matches = separatorRegex.exec( markdown ) ) {
|
||||
notes = null;
|
||||
|
||||
// determine direction (horizontal by default)
|
||||
isHorizontal = horizontalSeparatorRegex.test( matches[0] );
|
||||
|
||||
if( !isHorizontal && wasHorizontal ) {
|
||||
// create vertical stack
|
||||
sectionStack.push( [] );
|
||||
}
|
||||
|
||||
// pluck slide content from markdown input
|
||||
content = markdown.substring( lastIndex, matches.index );
|
||||
|
||||
if( isHorizontal && wasHorizontal ) {
|
||||
// add to horizontal stack
|
||||
sectionStack.push( content );
|
||||
}
|
||||
else {
|
||||
// add to vertical stack
|
||||
sectionStack[sectionStack.length-1].push( content );
|
||||
}
|
||||
|
||||
lastIndex = separatorRegex.lastIndex;
|
||||
wasHorizontal = isHorizontal;
|
||||
}
|
||||
|
||||
// add the remaining slide
|
||||
( wasHorizontal ? sectionStack : sectionStack[sectionStack.length-1] ).push( markdown.substring( lastIndex ) );
|
||||
|
||||
var markdownSections = '';
|
||||
|
||||
// flatten the hierarchical stack, and insert <section data-markdown> tags
|
||||
for( var i = 0, len = sectionStack.length; i < len; i++ ) {
|
||||
// vertical
|
||||
if( sectionStack[i] instanceof Array ) {
|
||||
markdownSections += '<section '+ options.attributes +'>';
|
||||
|
||||
sectionStack[i].forEach( function( child ) {
|
||||
markdownSections += '<section data-markdown>' + createMarkdownSlide( child, options ) + '</section>';
|
||||
} );
|
||||
|
||||
markdownSections += '</section>';
|
||||
}
|
||||
else {
|
||||
markdownSections += '<section '+ options.attributes +' data-markdown>' + createMarkdownSlide( sectionStack[i], options ) + '</section>';
|
||||
}
|
||||
}
|
||||
|
||||
return markdownSections;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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]'),
|
||||
section;
|
||||
|
||||
for( var i = 0, len = sections.length; i < len; i++ ) {
|
||||
|
||||
section = sections[i];
|
||||
|
||||
if( section.getAttribute( 'data-markdown' ).length ) {
|
||||
|
||||
var xhr = new XMLHttpRequest(),
|
||||
url = section.getAttribute( 'data-markdown' );
|
||||
|
||||
datacharset = section.getAttribute( 'data-charset' );
|
||||
|
||||
// see https://developer.mozilla.org/en-US/docs/Web/API/element.getAttribute#Notes
|
||||
if( datacharset != null && datacharset != '' ) {
|
||||
xhr.overrideMimeType( 'text/html; charset=' + datacharset );
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if( xhr.readyState === 4 ) {
|
||||
// file protocol yields status code 0 (useful for local debug, mobile applications etc.)
|
||||
if ( ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status === 0 ) {
|
||||
|
||||
section.outerHTML = slidify( xhr.responseText, {
|
||||
separator: section.getAttribute( 'data-separator' ),
|
||||
verticalSeparator: section.getAttribute( 'data-separator-vertical' ),
|
||||
notesSeparator: section.getAttribute( 'data-separator-notes' ),
|
||||
attributes: getForwardedAttributes( section )
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
section.outerHTML = '<section data-state="alert">' +
|
||||
'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' +
|
||||
'Check your browser\'s JavaScript console for more details.' +
|
||||
'<p>Remember that you need to serve the presentation HTML from a HTTP server.</p>' +
|
||||
'</section>';
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open( 'GET', url, false );
|
||||
|
||||
try {
|
||||
xhr.send();
|
||||
}
|
||||
catch ( e ) {
|
||||
alert( 'Failed to get the Markdown file ' + url + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + e );
|
||||
}
|
||||
|
||||
}
|
||||
else if( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-separator-vertical' ) || section.getAttribute( 'data-separator-notes' ) ) {
|
||||
|
||||
section.outerHTML = slidify( getMarkdownFromSlide( section ), {
|
||||
separator: section.getAttribute( 'data-separator' ),
|
||||
verticalSeparator: section.getAttribute( 'data-separator-vertical' ),
|
||||
notesSeparator: section.getAttribute( 'data-separator-notes' ),
|
||||
attributes: getForwardedAttributes( section )
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a node value has the attributes pattern.
|
||||
* If yes, extract it and add that value as one or several attributes
|
||||
* the the terget element.
|
||||
*
|
||||
* You need Cache Killer on Chrome to see the effect on any FOM transformation
|
||||
* directly on refresh (F5)
|
||||
* http://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development/7000899#answer-11786277
|
||||
*/
|
||||
function addAttributeInElement( node, elementTarget, separator ) {
|
||||
|
||||
var mardownClassesInElementsRegex = new RegExp( separator, 'mg' );
|
||||
var mardownClassRegex = new RegExp( "([^\"= ]+?)=\"([^\"=]+?)\"", 'mg' );
|
||||
var nodeValue = node.nodeValue;
|
||||
if( matches = mardownClassesInElementsRegex.exec( nodeValue ) ) {
|
||||
|
||||
var classes = matches[1];
|
||||
nodeValue = nodeValue.substring( 0, matches.index ) + nodeValue.substring( mardownClassesInElementsRegex.lastIndex );
|
||||
node.nodeValue = nodeValue;
|
||||
while( matchesClass = mardownClassRegex.exec( classes ) ) {
|
||||
var name = matchesClass[1];
|
||||
var value = matchesClass[2];
|
||||
if (name.substr(0, 5) === 'data-' || whiteListAttr.indexOf(name) !== -1)
|
||||
elementTarget.setAttribute( name, filterXSS.escapeAttrValue(value) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add attributes to the parent element of a text node,
|
||||
* or the element of an attribute node.
|
||||
*/
|
||||
function addAttributes( section, element, previousElement, separatorElementAttributes, separatorSectionAttributes ) {
|
||||
|
||||
if ( element != null && element.childNodes != undefined && element.childNodes.length > 0 ) {
|
||||
previousParentElement = element;
|
||||
for( var i = 0; i < element.childNodes.length; i++ ) {
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( element.nodeType == Node.COMMENT_NODE ) {
|
||||
if ( addAttributeInElement( element, previousElement, separatorElementAttributes ) == false ) {
|
||||
addAttributeInElement( element, section, separatorSectionAttributes );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts any current data-markdown slides in the
|
||||
* DOM to HTML.
|
||||
*/
|
||||
function convertSlides() {
|
||||
|
||||
var sections = document.querySelectorAll( '[data-markdown]');
|
||||
|
||||
for( var i = 0, len = sections.length; i < len; i++ ) {
|
||||
|
||||
var section = sections[i];
|
||||
|
||||
// Only parse the same slide once
|
||||
if( !section.getAttribute( 'data-markdown-parsed' ) ) {
|
||||
|
||||
section.setAttribute( 'data-markdown-parsed', true )
|
||||
|
||||
var notes = section.querySelector( 'aside.notes' );
|
||||
var markdown = getMarkdownFromSlide( section );
|
||||
|
||||
var rendered = md.render(markdown);
|
||||
rendered = preventXSS(rendered);
|
||||
var result = postProcess(rendered);
|
||||
section.innerHTML = result[0].outerHTML;
|
||||
addAttributes( section, section, null, section.getAttribute( 'data-element-attributes' ) ||
|
||||
section.parentNode.getAttribute( 'data-element-attributes' ) ||
|
||||
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
|
||||
// having overwritten the section's HTML
|
||||
if( notes ) {
|
||||
section.appendChild( notes );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// API
|
||||
return {
|
||||
|
||||
initialize: function() {
|
||||
processSlides();
|
||||
convertSlides();
|
||||
},
|
||||
|
||||
// TODO: Do these belong in the API?
|
||||
processSlides: processSlides,
|
||||
convertSlides: convertSlides,
|
||||
slidify: slidify
|
||||
|
||||
};
|
||||
|
||||
}));
|
||||
(function (root, factory) {
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = factory()
|
||||
} else {
|
||||
// Browser globals (root is window)
|
||||
root.RevealMarkdown = factory()
|
||||
root.RevealMarkdown.initialize()
|
||||
}
|
||||
}(this, function () {
|
||||
var DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$'
|
||||
var DEFAULT_NOTES_SEPARATOR = 'note:'
|
||||
var DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\.element\\s*?(.+?)$'
|
||||
var DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\.slide:\\s*?(\\S.+?)$'
|
||||
|
||||
var SCRIPT_END_PLACEHOLDER = '__SCRIPT_END__'
|
||||
|
||||
/**
|
||||
* Retrieves the markdown contents of a slide section
|
||||
* element. Normalizes leading tabs/whitespace.
|
||||
*/
|
||||
function getMarkdownFromSlide (section) {
|
||||
var template = section.querySelector('script')
|
||||
|
||||
// strip leading whitespace so it isn't evaluated as code
|
||||
var text = (template || section).textContent
|
||||
|
||||
// restore script end tags
|
||||
text = text.replace(new RegExp(SCRIPT_END_PLACEHOLDER, 'g'), '</script>')
|
||||
|
||||
var leadingWs = text.match(/^\n?(\s*)/)[1].length
|
||||
var leadingTabs = text.match(/^\n?(\t*)/)[1].length
|
||||
|
||||
if (leadingTabs > 0) {
|
||||
text = text.replace(new RegExp('\\n?\\t{' + leadingTabs + '}', 'g'), '\n')
|
||||
} else if (leadingWs > 1) {
|
||||
text = text.replace(new RegExp('\\n? {' + leadingWs + '}', 'g'), '\n')
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a markdown slide section element, this will
|
||||
* return all arguments that aren't related to markdown
|
||||
* parsing. Used to forward any other user-defined arguments
|
||||
* to the output markdown slide.
|
||||
*/
|
||||
function getForwardedAttributes (section) {
|
||||
var attributes = section.attributes
|
||||
var result = []
|
||||
|
||||
for (var i = 0, len = attributes.length; i < len; i++) {
|
||||
var name = attributes[i].name
|
||||
var value = attributes[i].value
|
||||
|
||||
// disregard attributes that are used for markdown loading/parsing
|
||||
if (/data-(markdown|separator|vertical|notes)/gi.test(name)) continue
|
||||
|
||||
if (value) {
|
||||
result.push(name + '="' + value + '"')
|
||||
} else {
|
||||
result.push(name)
|
||||
}
|
||||
}
|
||||
|
||||
return result.join(' ')
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function createMarkdownSlide (content, options) {
|
||||
options = getSlidifyOptions(options)
|
||||
|
||||
var notesMatch = content.split(new RegExp(options.notesSeparator, 'mgi'))
|
||||
|
||||
if (notesMatch.length === 2) {
|
||||
content = notesMatch[0] + '<aside class="notes" data-markdown>' + notesMatch[1].trim() + '</aside>'
|
||||
}
|
||||
|
||||
// prevent script end tags in the content from interfering
|
||||
// with parsing
|
||||
content = content.replace(/<\/script>/g, SCRIPT_END_PLACEHOLDER)
|
||||
|
||||
return '<script type="text/template">' + content + '</script>'
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a data string into multiple slides based
|
||||
* on the passed in separator arguments.
|
||||
*/
|
||||
function slidify (markdown, options) {
|
||||
options = getSlidifyOptions(options)
|
||||
|
||||
var separatorRegex = new RegExp(options.separator + (options.verticalSeparator ? '|' + options.verticalSeparator : ''), 'mg')
|
||||
var horizontalSeparatorRegex = new RegExp(options.separator)
|
||||
|
||||
var matches
|
||||
var lastIndex = 0
|
||||
var isHorizontal
|
||||
var wasHorizontal = true
|
||||
var content
|
||||
var sectionStack = []
|
||||
|
||||
// iterate until all blocks between separators are stacked up
|
||||
while ((matches = separatorRegex.exec(markdown)) !== null) {
|
||||
// determine direction (horizontal by default)
|
||||
isHorizontal = horizontalSeparatorRegex.test(matches[0])
|
||||
|
||||
if (!isHorizontal && wasHorizontal) {
|
||||
// create vertical stack
|
||||
sectionStack.push([])
|
||||
}
|
||||
|
||||
// pluck slide content from markdown input
|
||||
content = markdown.substring(lastIndex, matches.index)
|
||||
|
||||
if (isHorizontal && wasHorizontal) {
|
||||
// add to horizontal stack
|
||||
sectionStack.push(content)
|
||||
} else {
|
||||
// add to vertical stack
|
||||
sectionStack[sectionStack.length - 1].push(content)
|
||||
}
|
||||
|
||||
lastIndex = separatorRegex.lastIndex
|
||||
wasHorizontal = isHorizontal
|
||||
}
|
||||
|
||||
// add the remaining slide
|
||||
(wasHorizontal ? sectionStack : sectionStack[sectionStack.length - 1]).push(markdown.substring(lastIndex))
|
||||
|
||||
var markdownSections = ''
|
||||
|
||||
// flatten the hierarchical stack, and insert <section data-markdown> tags
|
||||
for (var i = 0, len = sectionStack.length; i < len; i++) {
|
||||
// vertical
|
||||
if (sectionStack[i] instanceof Array) {
|
||||
markdownSections += '<section ' + options.attributes + '>'
|
||||
|
||||
sectionStack[i].forEach(function (child) {
|
||||
markdownSections += '<section data-markdown>' + createMarkdownSlide(child, options) + '</section>'
|
||||
})
|
||||
|
||||
markdownSections += '</section>'
|
||||
} else {
|
||||
markdownSections += '<section ' + options.attributes + ' data-markdown>' + createMarkdownSlide(sectionStack[i], options) + '</section>'
|
||||
}
|
||||
}
|
||||
|
||||
return markdownSections
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 section
|
||||
|
||||
for (var i = 0, len = sections.length; i < len; i++) {
|
||||
section = sections[i]
|
||||
|
||||
if (section.getAttribute('data-markdown').length) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
var url = section.getAttribute('data-markdown')
|
||||
|
||||
var datacharset = section.getAttribute('data-charset')
|
||||
|
||||
// see https://developer.mozilla.org/en-US/docs/Web/API/element.getAttribute#Notes
|
||||
if (datacharset !== null && datacharset !== '') {
|
||||
xhr.overrideMimeType('text/html; charset=' + datacharset)
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
// file protocol yields status code 0 (useful for local debug, mobile applications etc.)
|
||||
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) {
|
||||
section.outerHTML = slidify(xhr.responseText, {
|
||||
separator: section.getAttribute('data-separator'),
|
||||
verticalSeparator: section.getAttribute('data-separator-vertical'),
|
||||
notesSeparator: section.getAttribute('data-separator-notes'),
|
||||
attributes: getForwardedAttributes(section)
|
||||
})
|
||||
} else {
|
||||
section.outerHTML = '<section data-state="alert">' +
|
||||
'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' +
|
||||
'Check your browser\'s JavaScript console for more details.' +
|
||||
'<p>Remember that you need to serve the presentation HTML from a HTTP server.</p>' +
|
||||
'</section>'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xhr.open('GET', url, false)
|
||||
|
||||
try {
|
||||
xhr.send()
|
||||
} catch (e) {
|
||||
alert('Failed to get the Markdown file ' + url + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + e)
|
||||
}
|
||||
} else if (section.getAttribute('data-separator') || section.getAttribute('data-separator-vertical') || section.getAttribute('data-separator-notes')) {
|
||||
section.outerHTML = slidify(getMarkdownFromSlide(section), {
|
||||
separator: section.getAttribute('data-separator'),
|
||||
verticalSeparator: section.getAttribute('data-separator-vertical'),
|
||||
notesSeparator: section.getAttribute('data-separator-notes'),
|
||||
attributes: getForwardedAttributes(section)
|
||||
})
|
||||
} else {
|
||||
section.innerHTML = createMarkdownSlide(getMarkdownFromSlide(section))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a node value has the attributes pattern.
|
||||
* If yes, extract it and add that value as one or several attributes
|
||||
* the the terget element.
|
||||
*
|
||||
* You need Cache Killer on Chrome to see the effect on any FOM transformation
|
||||
* directly on refresh (F5)
|
||||
* http://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development/7000899#answer-11786277
|
||||
*/
|
||||
function addAttributeInElement (node, elementTarget, separator) {
|
||||
var mardownClassesInElementsRegex = new RegExp(separator, 'mg')
|
||||
var mardownClassRegex = new RegExp('([^"= ]+?)="([^"=]+?)"', 'mg')
|
||||
var nodeValue = node.nodeValue
|
||||
var matches
|
||||
var matchesClass
|
||||
if ((matches = mardownClassesInElementsRegex.exec(nodeValue))) {
|
||||
var classes = matches[1]
|
||||
nodeValue = nodeValue.substring(0, matches.index) + nodeValue.substring(mardownClassesInElementsRegex.lastIndex)
|
||||
node.nodeValue = nodeValue
|
||||
while ((matchesClass = mardownClassRegex.exec(classes))) {
|
||||
var name = matchesClass[1]
|
||||
var value = matchesClass[2]
|
||||
if (name.substr(0, 5) === 'data-' || window.whiteListAttr.indexOf(name) !== -1) { elementTarget.setAttribute(name, window.filterXSS.escapeAttrValue(value)) }
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Add attributes to the parent element of a text node,
|
||||
* or the element of an attribute node.
|
||||
*/
|
||||
function addAttributes (section, element, previousElement, separatorElementAttributes, separatorSectionAttributes) {
|
||||
if (element != null && element.childNodes !== undefined && element.childNodes.length > 0) {
|
||||
var previousParentElement = element
|
||||
for (var i = 0; i < element.childNodes.length; i++) {
|
||||
var childElement = element.childNodes[i]
|
||||
if (i > 0) {
|
||||
let j = i - 1
|
||||
while (j >= 0) {
|
||||
var aPreviousChildElement = element.childNodes[j]
|
||||
if (typeof aPreviousChildElement.setAttribute === 'function' && aPreviousChildElement.tagName !== 'BR') {
|
||||
previousParentElement = aPreviousChildElement
|
||||
break
|
||||
}
|
||||
j = j - 1
|
||||
}
|
||||
}
|
||||
var 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (element.nodeType === Node.COMMENT_NODE) {
|
||||
if (addAttributeInElement(element, previousElement, separatorElementAttributes) === false) {
|
||||
addAttributeInElement(element, section, separatorSectionAttributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts any current data-markdown slides in the
|
||||
* DOM to HTML.
|
||||
*/
|
||||
function convertSlides () {
|
||||
var sections = document.querySelectorAll('[data-markdown]')
|
||||
|
||||
for (var i = 0, len = sections.length; i < len; i++) {
|
||||
var section = sections[i]
|
||||
|
||||
// Only parse the same slide once
|
||||
if (!section.getAttribute('data-markdown-parsed')) {
|
||||
section.setAttribute('data-markdown-parsed', true)
|
||||
|
||||
var notes = section.querySelector('aside.notes')
|
||||
var markdown = getMarkdownFromSlide(section)
|
||||
|
||||
var rendered = md.render(markdown)
|
||||
rendered = preventXSS(rendered)
|
||||
var result = window.postProcess(rendered)
|
||||
section.innerHTML = result[0].outerHTML
|
||||
addAttributes(section, section, null, section.getAttribute('data-element-attributes') ||
|
||||
section.parentNode.getAttribute('data-element-attributes') ||
|
||||
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
|
||||
// having overwritten the section's HTML
|
||||
if (notes) {
|
||||
section.appendChild(notes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// API
|
||||
return {
|
||||
initialize: function () {
|
||||
processSlides()
|
||||
convertSlides()
|
||||
},
|
||||
// TODO: Do these belong in the API?
|
||||
processSlides: processSlides,
|
||||
convertSlides: convertSlides,
|
||||
slidify: slidify
|
||||
}
|
||||
}))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue