diff --git a/src/plugins/substep/README.md b/src/plugins/substep/README.md new file mode 100644 index 0000000..e4277ff --- /dev/null +++ b/src/plugins/substep/README.md @@ -0,0 +1,37 @@ +Substep Plugin +=============== + +Reveal each substep (such as a bullet point) of the step separately. Just like in PowerPoint! + +If the current step contains html elements with `class="substep"` then this plugin will prevent a +`prev()` / `next()` call to leave the slide, and instead reveal the next substep (for `next()`) or +alternatively hide one (for `prev()`). Only once all substeps are shown, will a call to `next()` +actually move to the next step, and only when all are hidden will a call to `prev()` move to the +previous one. + +Calls to `goto()` will be ignored by this plugin, i.e. `goto()` will transition to whichever step is +the target. + +In practice what happens is that when each substep is stepped through via `next()` calls, a +`class="substep-visible"` class is added to the element. It is up to the presentation author to +use the appropriate CSS to make the substeps hidden and visible. + +Example: + + + +
+

Fruits

+

Orange

+

Apple

+
+ +Author +------ + +Copyright 2017 Henrik Ingo (@henrikingo) +Released under the MIT license. + diff --git a/src/plugins/substep/substep.js b/src/plugins/substep/substep.js new file mode 100644 index 0000000..d5a6465 --- /dev/null +++ b/src/plugins/substep/substep.js @@ -0,0 +1,111 @@ +/** + * Substep Plugin + * + * Copyright 2017 Henrik Ingo (@henrikingo) + * Released under the MIT license. + */ + +/* global document, window */ + +( function( document, window ) { + "use strict"; + + // Copied from core impress.js. Good candidate for moving to src/lib/util.js. + var triggerEvent = function( el, eventName, detail ) { + var event = document.createEvent( "CustomEvent" ); + event.initCustomEvent( eventName, true, true, detail ); + el.dispatchEvent( event ); + }; + + var activeStep = null; + document.addEventListener( "impress:stepenter", function( event ) { + activeStep = event.target; + }, false ); + + var substep = function( event ) { + if ( ( !event ) || ( !event.target ) ) { + return; + } + + var step = event.target; + var el; // Needed by jshint + if ( event.detail.reason === "next" ) { + el = showSubstepIfAny( step ); + if ( el ) { + + // Send a message to others, that we aborted a stepleave event. + // Autoplay will reload itself from this, as there won't be a stepenter event now. + triggerEvent( step, "impress:substep:stepleaveaborted", + { reason: "next", substep: el } ); + + // Returning false aborts the stepleave event + return false; + } + } + if ( event.detail.reason === "prev" ) { + el = hideSubstepIfAny( step ); + if ( el ) { + triggerEvent( step, "impress:substep:stepleaveaborted", + { reason: "prev", substep: el } ); + return false; + } + } + }; + + var showSubstepIfAny = function( step ) { + var substeps = step.querySelectorAll( ".substep" ); + var visible = step.querySelectorAll( ".substep-visible" ); + if ( substeps.length > 0 ) { + return showSubstep( substeps, visible ); + } + }; + + var showSubstep = function( substeps, visible ) { + if ( visible.length < substeps.length ) { + var el = substeps[ visible.length ]; + el.classList.add( "substep-visible" ); + return el; + } + }; + + var hideSubstepIfAny = function( step ) { + var substeps = step.querySelectorAll( ".substep" ); + var visible = step.querySelectorAll( ".substep-visible" ); + if ( substeps.length > 0 ) { + return hideSubstep( visible ); + } + }; + + var hideSubstep = function( visible ) { + if ( visible.length > 0 ) { + var el = visible[ visible.length - 1 ]; + el.classList.remove( "substep-visible" ); + return el; + } + }; + + // Register the plugin to be called in pre-stepleave phase. + // The weight makes this plugin run before other preStepLeave plugins. + window.impress.addPreStepLeavePlugin( substep, 1 ); + + // When entering a step, in particular when re-entering, make sure that all substeps are hidden + // at first + document.addEventListener( "impress:stepenter", function( event ) { + var step = event.target; + var visible = step.querySelectorAll( ".substep-visible" ); + for ( var i = 0; i < visible.length; i++ ) { + visible[ i ].classList.remove( "substep-visible" ); + } + }, false ); + + // API for others to reveal/hide next substep //////////////////////////////////////////////// + document.addEventListener( "impress:substep:show", function() { + showSubstepIfAny( activeStep ); + }, false ); + + document.addEventListener( "impress:substep:hide", function() { + hideSubstepIfAny( activeStep ); + }, false ); + +} )( document, window ); +