From 4862de26eb75d44b36849ef574db986203d3c879 Mon Sep 17 00:00:00 2001 From: Hakim El Hattab Date: Fri, 1 Mar 2019 21:28:52 +0100 Subject: async loading of external markdown, add Reveal.registerPlugin() --- plugin/markdown/markdown.js | 185 ++++++++++++++++++++++++++------------------ 1 file changed, 110 insertions(+), 75 deletions(-) (limited to 'plugin/markdown/markdown.js') diff --git a/plugin/markdown/markdown.js b/plugin/markdown/markdown.js index 31029ae..181116d 100755 --- a/plugin/markdown/markdown.js +++ b/plugin/markdown/markdown.js @@ -7,13 +7,11 @@ if (typeof define === 'function' && define.amd) { root.marked = require( './marked' ); root.RevealMarkdown = factory( root.marked ); - root.RevealMarkdown.initialize(); } else 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 ) { @@ -24,6 +22,10 @@ var SCRIPT_END_PLACEHOLDER = '__SCRIPT_END__'; + var markdownFilesToLoad = 0; + + var loadCallback; + /** * Retrieves the markdown contents of a slide section @@ -199,73 +201,85 @@ */ function processSlides() { - var sections = document.querySelectorAll( '[data-markdown]'), - section; + [].slice.call( document.querySelectorAll( '[data-markdown]') ).forEach( function( section, i ) { - for( var i = 0, len = sections.length; i < len; i++ ) { + if( section.getAttribute( 'data-markdown' ).length ) { - section = sections[i]; + loadExternalMarkdown( section ); - if( section.getAttribute( 'data-markdown' ).length ) { + } + 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 ) + }); - var xhr = new XMLHttpRequest(), - url = section.getAttribute( 'data-markdown' ); + } + else { + section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) ); + } - 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 ); - } + checkIfLoaded(); - 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 ) - }); + function loadExternalMarkdown( section ) { - } - else { + markdownFilesToLoad += 1; - 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.

' + - '
'; + 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( section, xhr ) { + 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 ) { - xhr.open( 'GET', url, false ); + 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 ) + }); - 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 { + + 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.

' + + '
'; + } - } - else if( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-separator-vertical' ) || section.getAttribute( 'data-separator-notes' ) ) { + convertSlides(); - 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 ) - }); + markdownFilesToLoad -= 1; + checkIfLoaded(); } - else { - section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) ); - } + }.bind( this, section, xhr ); + + xhr.open( 'GET', url, true ); + + 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 ); } } @@ -342,44 +356,56 @@ */ function convertSlides() { - var sections = document.querySelectorAll( '[data-markdown]'); + var sections = document.querySelectorAll( '[data-markdown]:not([data-markdown-parsed])'); - for( var i = 0, len = sections.length; i < len; i++ ) { + [].slice.call( sections ).forEach( function( section ) { - var section = sections[i]; + section.setAttribute( 'data-markdown-parsed', true ) - // Only parse the same slide once - if( !section.getAttribute( 'data-markdown-parsed' ) ) { + var notes = section.querySelector( 'aside.notes' ); + var markdown = getMarkdownFromSlide( section ); - section.setAttribute( 'data-markdown-parsed', true ) + section.innerHTML = marked( markdown ); + 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); - var notes = section.querySelector( 'aside.notes' ); - var markdown = getMarkdownFromSlide( section ); + // If there were notes, we need to re-add them after + // having overwritten the section's HTML + if( notes ) { + section.appendChild( notes ); + } - section.innerHTML = marked( markdown ); - 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 ); - } + } - } + function checkIfLoaded() { + if( markdownFilesToLoad === 0 ) { + if( loadCallback ) { + loadCallback(); + loadCallback = null; + } } } // API - return { + var RevealMarkdown = { + + /** + * Starts processing and converting Markdown within the + * current reveal.js deck. + * + * @param {function} callback function to invoke once + * we've finished loading and parsing Markdown + */ + init: function( callback ) { - initialize: function() { if( typeof marked === 'undefined' ) { throw 'The reveal.js Markdown plugin requires marked to be loaded'; } @@ -392,14 +418,17 @@ }); } + // marked can be configured via reveal.js config options var options = Reveal.getConfig().markdown; - - if ( options ) { + if( options ) { marked.setOptions( options ); } + loadCallback = callback; + processSlides(); convertSlides(); + }, // TODO: Do these belong in the API? @@ -409,4 +438,10 @@ }; + // Register our plugin so that reveal.js will call our + // plugin 'init' method as part of the initialization + Reveal.registerPlugin( 'markdown', RevealMarkdown ); + + return RevealMarkdown; + })); -- cgit v1.2.3