From 5bc642d02e8955b200bb21cf30e863fdf0c53765 Mon Sep 17 00:00:00 2001 From: BoHong Li Date: Thu, 9 Mar 2017 02:41:05 +0800 Subject: Use JavaScript Standard Style (part 2) Fixed all fail on frontend code. --- public/js/reveal-markdown.js | 741 ++++++++++++++++++++----------------------- 1 file changed, 350 insertions(+), 391 deletions(-) (limited to 'public/js/reveal-markdown.js') diff --git a/public/js/reveal-markdown.js b/public/js/reveal-markdown.js index 3c3e1f5b..eca148d8 100755 --- a/public/js/reveal-markdown.js +++ b/public/js/reveal-markdown.js @@ -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' ), '' ); - - 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] + ''; - } - - // prevent script end tags in the content from interfering - // with parsing - content = content.replace( /<\/script>/g, SCRIPT_END_PLACEHOLDER ); - - return ''; - - } - - /** - * 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
tags - for( var i = 0, len = sectionStack.length; i < len; i++ ) { - // vertical - if( sectionStack[i] instanceof Array ) { - markdownSections += '
'; - - sectionStack[i].forEach( function( child ) { - markdownSections += '
' + createMarkdownSlide( child, options ) + '
'; - } ); - - markdownSections += '
'; - } - else { - markdownSections += '
' + createMarkdownSlide( sectionStack[i], options ) + '
'; - } - } - - 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 = '
' + - 'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' + - 'Check your browser\'s JavaScript console for more details.' + - '

Remember that you need to serve the presentation HTML from a HTTP server.

' + - '
'; - - } - } - }; - - 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'), '') + + 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] + '' + } + + // prevent script end tags in the content from interfering + // with parsing + content = content.replace(/<\/script>/g, SCRIPT_END_PLACEHOLDER) + + return '' + } + + /** + * 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
tags + for (var i = 0, len = sectionStack.length; i < len; i++) { + // vertical + if (sectionStack[i] instanceof Array) { + markdownSections += '
' + + sectionStack[i].forEach(function (child) { + markdownSections += '
' + createMarkdownSlide(child, options) + '
' + }) + + markdownSections += '
' + } else { + markdownSections += '
' + createMarkdownSlide(sectionStack[i], options) + '
' + } + } + + 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 = '
' + + 'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' + + 'Check your browser\'s JavaScript console for more details.' + + '

Remember that you need to serve the presentation HTML from a HTTP server.

' + + '
' + } + } + } + + 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 + } +})) -- cgit v1.2.3