From de6860b8b3351d289bdf30e37f4f4fdafc46690f Mon Sep 17 00:00:00 2001 From: koutbo6 Date: Wed, 20 Jan 2021 02:22:34 +0300 Subject: [PATCH] feat(slides): upgrade reveal.js from v3.8.0 to v4.1.0 (#2018) --- .gitignore | 3 + wowchemy/archetypes/slides/index.md | 23 + wowchemy/assets/css/reveal.css | 31 - wowchemy/assets/js/wowchemy-slides.js | 148 ++++ wowchemy/assets/js/wowchemy-theming.js | 4 +- wowchemy/data/assets.toml | 4 +- wowchemy/layouts/slides/baseof.html | 64 +- .../vendor/reveal.js/plugin/notes/notes.html | 834 ------------------ .../js/vendor/reveal.js/plugin/notes/notes.js | 178 ---- 9 files changed, 204 insertions(+), 1085 deletions(-) delete mode 100644 wowchemy/assets/css/reveal.css create mode 100644 wowchemy/assets/js/wowchemy-slides.js delete mode 100644 wowchemy/static/js/vendor/reveal.js/plugin/notes/notes.html delete mode 100644 wowchemy/static/js/vendor/reveal.js/plugin/notes/notes.js diff --git a/.gitignore b/.gitignore index 9f3f91cd..af98a728 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ node_modules/ # Hugo resources/ + +# Mac +.DS_Store diff --git a/wowchemy/archetypes/slides/index.md b/wowchemy/archetypes/slides/index.md index d93004e8..13d085e1 100644 --- a/wowchemy/archetypes/slides/index.md +++ b/wowchemy/archetypes/slides/index.md @@ -12,7 +12,30 @@ slides: theme: black # Choose a code highlighting style (if highlighting enabled in `params.toml`) # Light style: github. Dark style: dracula (default). + # Available highlight themes listed in: https://highlightjs.org/static/demo/ + # Use lower case names and replace space with hyphen '-' highlight_style: dracula + + diagram: true + diagram_options: + # Mermaid diagram themes include: default,base,dark,neutral,forest + theme: base + + # RevealJS slide options. + # Options are named using the snake case equivalent of those in the RevealJS docs. + reveal_options: + controls: true + progress: true + slide_number: c/t # true | false | h.v | h/v | c | c/t + center: true + rtl: false + mouse_wheel: true + transition: fade # none/fade/slide/convex/concave/zoom + transitionSpeed: default # default/fast/slow + background_transition: slide # none/fade/slide/convex/concave/zoom + touch: true + loop: false + menu_enabled: true --- # Title diff --git a/wowchemy/assets/css/reveal.css b/wowchemy/assets/css/reveal.css deleted file mode 100644 index ca174e39..00000000 --- a/wowchemy/assets/css/reveal.css +++ /dev/null @@ -1,31 +0,0 @@ -/************************************************* - * Reveal JS - **************************************************/ - -/* This is a copy of MathJax's `.mjx-chtml` with font-family added to override `.reveal span`. */ -/* See https://github.com/hakimel/reveal.js/issues/1924 */ -.reveal span.mjx-chtml { - display: inline-block; - line-height: 0; - text-indent: 0; - text-align: left; - text-transform: none; - font-style: normal; - font-weight: normal; - font-size: 100%; - font-size-adjust: none; - letter-spacing: normal; - word-wrap: normal; - word-spacing: normal; - white-space: nowrap; - float: none; - direction: ltr; - max-width: none; - max-height: none; - min-width: 0; - min-height: 0; - border: 0; - margin: 0; - padding: 1px 0; - font-family: MJXc-TeX-math-I,MJXc-TeX-math-Ix,MJXc-TeX-math-Iw; -} diff --git a/wowchemy/assets/js/wowchemy-slides.js b/wowchemy/assets/js/wowchemy-slides.js new file mode 100644 index 00000000..77018beb --- /dev/null +++ b/wowchemy/assets/js/wowchemy-slides.js @@ -0,0 +1,148 @@ +/* + global RevealMarkdown, RevealHighlight, RevealSearch, RevealNotes, RevealMath, RevealZoom, Reveal, mermaid, RevealMenu +*/ + +import * as params from '@params'; + +import {fixMermaid} from './wowchemy-utils'; + +// Enable core slide features. +var enabledPlugins = [RevealMarkdown, RevealHighlight, RevealSearch, RevealNotes, RevealMath, RevealZoom]; + +const isObject = function (o) { + return o === Object(o) && !isArray(o) && typeof o !== 'function'; +}; + +const isArray = function (a) { + return Array.isArray(a); +}; + +const toCamelCase = function (s) { + return s.replace(/([-_][a-z])/gi, function (term) { + return term.toUpperCase().replace('-', '').replace('_', ''); + }); +}; + +const keysToCamelCase = function (o) { + if (isObject(o)) { + const n = {}; + + Object.keys(o).forEach(function (k) { + n[toCamelCase(k)] = keysToCamelCase(o[k]); + }); + + return n; + } else if (isArray(o)) { + return o.map(function (i) { + return keysToCamelCase(i); + }); + } + + return o; +}; + +// reveal configurations can be included in front matter under slides.reveal +var pluginOptions = {}; +if (typeof params.slides.reveal_options !== 'undefined') { + pluginOptions = params.slides.reveal_options; +} + +pluginOptions = keysToCamelCase(pluginOptions); + +//enable menu by default if not set +if (typeof pluginOptions.menu_enabled !== 'undefined') { + pluginOptions.menu_enabled = true; +} + +// configure menu if enabled +if (pluginOptions.menu_enabled) { + enabledPlugins.push(RevealMenu); +} + +pluginOptions['plugins'] = enabledPlugins; + +Reveal.initialize(pluginOptions); + +// The following functions are used to render Mermaid diagrams +// after Reveal slides have been successfully loaded +// since content of slides is lazy loaded, if diagrams are +// rendered at start of presentation their sizes will be off +// get all slides that are: +// 1- data loaded +// 2- display set to block +// 3- has a mermaid element that is not processed (data-processed dne) +function mermaidSlidesReadyToRender(mslide) { + var diag = mslide.querySelector('.mermaid'); + if (diag) { + var background = mslide.slideBackgroundElement; + // render if we are 1 slide away horizontally + // current visible slide index + var currentHorizontalIndex = Reveal.getState()['indexh']; + + // mermaid slide index + var diagramSlideIndex = Reveal.getIndices(mslide)['h']; + if ( + // find slides with non-rendered mermaid tags + // these will not have the attribute data-processed + !diag.hasAttribute('data-processed') && + // check also that reveal slide is already loaded + // reveal slides seem to be lazily loaded + // things could be easier if reveal had a slide-loaded event + background.hasAttribute('data-loaded') && + // loaded slides must also have the display attribute set to block + background.style.display === 'block' && + // render diagrams that are 1 slide away + diagramSlideIndex - currentHorizontalIndex <= 1 + ) + return mslide; + } + return null; +} + +function renderMermaidSlides() { + // find all slides with diagrams that are ready to render + var diagramSlides = Reveal.getSlides().filter(mermaidSlidesReadyToRender); + + // render the diagram for each slide with ready to render diagrams + diagramSlides.forEach(function (item) { + mermaid.init(item.querySelector('.mermaid')); + }); +} + +// render mermaid slides for slides that are ready +Reveal.on('slidechanged', function () { + renderMermaidSlides(); +}); + +// render mermaid slides for slides that are ready on startup +Reveal.on('Ready', function () { + if (Reveal.isReady()) { + renderMermaidSlides(); + } +}); + +// Disable Mermaid by default. +if (typeof params.slides.diagram === 'undefined') { + params.slides.diagram = false; +} + +// Configure Mermaid only if diagrams are enabled. +if (params.slides.diagram) { + //mermaid options + // mermaid: front matter configuration can be used to set mermaid options + // You can also use directives (see mermaid documentation) + var mermaidOptions = {}; + if (typeof params.slides.diagram_options !== 'undefined') { + mermaidOptions = params.slides.diagram_options; + } + + // `startOnLoad` must be false since diagrams are lazily rendered. + mermaidOptions['startOnLoad'] = false; + + mermaid.initialize(mermaidOptions); + + // Fix Mermaid conflict with Hightlight JS. + document.addEventListener('DOMContentLoaded', function () { + fixMermaid(); + }); +} diff --git a/wowchemy/assets/js/wowchemy-theming.js b/wowchemy/assets/js/wowchemy-theming.js index b1be77ab..310ef80d 100644 --- a/wowchemy/assets/js/wowchemy-theming.js +++ b/wowchemy/assets/js/wowchemy-theming.js @@ -187,7 +187,7 @@ function renderThemeVariation(isDarkTheme, themeMode = 2, init = false) { console.debug('Initializing Mermaid with light theme'); if (init) { /** @namespace window.mermaid **/ - window.mermaid.initialize({theme: 'default', securityLevel: 'loose'}); + window.mermaid.initialize({startOnLoad: true, theme: 'default', securityLevel: 'loose'}); } else { // Have to reload to re-initialise Mermaid with the new theme and re-parse the Mermaid code blocks. location.reload(); @@ -213,7 +213,7 @@ function renderThemeVariation(isDarkTheme, themeMode = 2, init = false) { console.debug('Initializing Mermaid with dark theme'); if (init) { /** @namespace window.mermaid **/ - window.mermaid.initialize({theme: 'dark', securityLevel: 'loose'}); + window.mermaid.initialize({startOnLoad: true, theme: 'dark', securityLevel: 'loose'}); } else { // Have to reload to re-initialise Mermaid with the new theme and re-parse the Mermaid code blocks. location.reload(); diff --git a/wowchemy/data/assets.toml b/wowchemy/data/assets.toml index f66a64e5..ed68b44d 100644 --- a/wowchemy/data/assets.toml +++ b/wowchemy/data/assets.toml @@ -57,8 +57,8 @@ sri = "sha512-I7w3ZdSFzw5j3jU3ZkNikBNeIrl3i+hEuEdwNmqUJvwNcaBUNcijnP2gd9DtGlgVYDplfjGoD8vTNsID+lCjqg==" url = "https://cdnjs.cloudflare.com/ajax/libs/anchor-js/%s/anchor.min.js" [js.mermaid] - version = "8.8.0" - sri = "sha512-ja+hSBi4JDtjSqc4LTBsSwuBT3tdZ3oKYKd07lTVYmCnTCor56AnRql00ssqnTOR9Ss4gOP/ROGB3SfcJnZkeg==" + version = "8.8.4" + sri = "sha512-as1BF4+iHZ3BVO6LLDQ7zrbvTXM+c/1iZ1qII/c3c4L8Rn5tHLpFUtpaEtBNS92f+xGsCzsD7b62XP3XYap6oA==" url = "https://cdnjs.cloudflare.com/ajax/libs/mermaid/%s/mermaid.min.js" [js.lazysizes] version = "5.2.2" diff --git a/wowchemy/layouts/slides/baseof.html b/wowchemy/layouts/slides/baseof.html index 239fc4a5..36d02105 100644 --- a/wowchemy/layouts/slides/baseof.html +++ b/wowchemy/layouts/slides/baseof.html @@ -5,12 +5,13 @@ {{ .Scratch.Set "media_dir" $media_dir }} {{ $css := site.Data.assets.css }} - {{ $cdn_url_reveal := "https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.8.0" }} + {{ $cdn_url_reveal := "https://cdnjs.cloudflare.com/ajax/libs/reveal.js/4.1.0" }} + {{ $js := site.Data.assets.js }} - + {{ if site.Home.OutputFormats.Get "WebAppManifest" }} @@ -23,55 +24,42 @@ {{ .Title }} | {{ site.Title }} - + {{- $theme := $.Param "slides.theme" | default "black" -}} - + {{- $highlight_style := $.Param "slides.highlight_style" | default "dracula" -}} - {{ printf "" (printf $css.highlight.url $css.highlight.version $highlight_style) | safeHTML }} + {{ printf "" (printf $css.highlight.url $css.highlight.version $highlight_style) | safeHTML }} - {{ $css := resources.Get "css/reveal.css" }} {{ $css_custom := resources.Get "css/reveal_custom.css" }} - {{ $style := slice $css $css_custom | resources.Concat "css/reveal_custom.css" | resources.Minify }} + {{ $style := slice $css_custom | resources.Concat "css/reveal_custom.css" | resources.Minify }} - - - - {{ block "main" . }}{{ end }} - + + + + + + + - + + + {{ end }} - let revealDefaults = { center: true, controls: true, history: true, progress: true, transition: 'slide', mouseWheel: true }; - let revealOptions = Object.assign({}, revealDefaults, revealPlugins); - Reveal.initialize(revealOptions); - + {{ if $.Param "slides.diagram" | default false}} + {{ printf "" (printf $js.mermaid.url $js.mermaid.version) $js.mermaid.sri | safeHTML }} + {{ end }} + + {{ $slidejs := resources.Get "js/wowchemy-slides.js" | js.Build (dict "params" (dict "slides" $.Params.slides )) }} + diff --git a/wowchemy/static/js/vendor/reveal.js/plugin/notes/notes.html b/wowchemy/static/js/vendor/reveal.js/plugin/notes/notes.html deleted file mode 100644 index 255dade3..00000000 --- a/wowchemy/static/js/vendor/reveal.js/plugin/notes/notes.html +++ /dev/null @@ -1,834 +0,0 @@ - - - - - - Speaker Notes - - - - - - -
Loading speaker view...
- -
-
Upcoming
-
-
-

Time Click to Reset

-
- 0:00 AM -
-
- 00:00:00 -
-
- - - -
- - -
-
- - -
- - - - - diff --git a/wowchemy/static/js/vendor/reveal.js/plugin/notes/notes.js b/wowchemy/static/js/vendor/reveal.js/plugin/notes/notes.js deleted file mode 100644 index ee631151..00000000 --- a/wowchemy/static/js/vendor/reveal.js/plugin/notes/notes.js +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Handles opening of and synchronization with the reveal.js - * notes window. - * - * Handshake process: - * 1. This window posts 'connect' to notes window - * - Includes URL of presentation to show - * 2. Notes window responds with 'connected' when it is available - * 3. This window proceeds to send the current presentation state - * to the notes window - */ -var RevealNotes = (function() { - - var notesPopup = null; - - function openNotes( notesFilePath ) { - - if (notesPopup && !notesPopup.closed) { - notesPopup.focus(); - return; - } - - if( !notesFilePath ) { - var jsFileLocation = document.querySelector('script[src$="notes.js"]').src; // this js file path - jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path - notesFilePath = jsFileLocation + 'notes.html'; - } - - notesPopup = window.open( notesFilePath, 'reveal.js - Notes', 'width=1100,height=700' ); - - if( !notesPopup ) { - alert( 'Speaker view popup failed to open. Please make sure popups are allowed and reopen the speaker view.' ); - return; - } - - /** - * Connect to the notes window through a postmessage handshake. - * Using postmessage enables us to work in situations where the - * origins differ, such as a presentation being opened from the - * file system. - */ - function connect() { - // Keep trying to connect until we get a 'connected' message back - var connectInterval = setInterval( function() { - notesPopup.postMessage( JSON.stringify( { - namespace: 'reveal-notes', - type: 'connect', - url: window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search, - state: Reveal.getState() - } ), '*' ); - }, 500 ); - - window.addEventListener( 'message', function( event ) { - var data = JSON.parse( event.data ); - if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) { - clearInterval( connectInterval ); - onConnected(); - } - if( data && data.namespace === 'reveal-notes' && data.type === 'call' ) { - callRevealApi( data.methodName, data.arguments, data.callId ); - } - } ); - } - - /** - * Calls the specified Reveal.js method with the provided argument - * and then pushes the result to the notes frame. - */ - function callRevealApi( methodName, methodArguments, callId ) { - - var result = Reveal[methodName].apply( Reveal, methodArguments ); - notesPopup.postMessage( JSON.stringify( { - namespace: 'reveal-notes', - type: 'return', - result: result, - callId: callId - } ), '*' ); - - } - - /** - * Posts the current slide data to the notes window - */ - function post( event ) { - - var slideElement = Reveal.getCurrentSlide(), - notesElement = slideElement.querySelector( 'aside.notes' ), - fragmentElement = slideElement.querySelector( '.current-fragment' ); - - var messageData = { - namespace: 'reveal-notes', - type: 'state', - notes: '', - markdown: false, - whitespace: 'normal', - state: Reveal.getState() - }; - - // Look for notes defined in a slide attribute - if( slideElement.hasAttribute( 'data-notes' ) ) { - messageData.notes = slideElement.getAttribute( 'data-notes' ); - messageData.whitespace = 'pre-wrap'; - } - - // Look for notes defined in a fragment - if( fragmentElement ) { - var fragmentNotes = fragmentElement.querySelector( 'aside.notes' ); - if( fragmentNotes ) { - notesElement = fragmentNotes; - } - else if( fragmentElement.hasAttribute( 'data-notes' ) ) { - messageData.notes = fragmentElement.getAttribute( 'data-notes' ); - messageData.whitespace = 'pre-wrap'; - - // In case there are slide notes - notesElement = null; - } - } - - // Look for notes defined in an aside element - if( notesElement ) { - messageData.notes = notesElement.innerHTML; - messageData.markdown = typeof notesElement.getAttribute( 'data-markdown' ) === 'string'; - } - - notesPopup.postMessage( JSON.stringify( messageData ), '*' ); - - } - - /** - * Called once we have established a connection to the notes - * window. - */ - function onConnected() { - - // Monitor events that trigger a change in state - Reveal.addEventListener( 'slidechanged', post ); - Reveal.addEventListener( 'fragmentshown', post ); - Reveal.addEventListener( 'fragmenthidden', post ); - Reveal.addEventListener( 'overviewhidden', post ); - Reveal.addEventListener( 'overviewshown', post ); - Reveal.addEventListener( 'paused', post ); - Reveal.addEventListener( 'resumed', post ); - - // Post the initial state - post(); - - } - - connect(); - - } - - return { - init: function() { - - if( !/receiver/i.test( window.location.search ) ) { - - // If the there's a 'notes' query set, open directly - if( window.location.search.match( /(\?|\&)notes/gi ) !== null ) { - openNotes(); - } - - // Open the notes when the 's' key is hit - Reveal.addKeyBinding({keyCode: 83, key: 'S', description: 'Speaker notes view'}, function() { - openNotes(); - } ); - - } - - }, - - open: openNotes - }; - -})(); - -Reveal.registerPlugin( 'notes', RevealNotes );