Files
impress.js/src/plugins/substep/substep.js

172 lines
6.0 KiB
JavaScript

/**
* 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.
triggerEvent( step, "impress:substep:stepleaveaborted",
{ reason: "next", substep: el } );
// Autoplay uses this for reloading itself
triggerEvent( step, "impress:substep:enter",
{ 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 } );
triggerEvent( step, "impress:substep:leave",
{ reason: "prev", substep: el } );
return false;
}
}
};
var showSubstepIfAny = function( step ) {
var substeps = step.querySelectorAll( ".substep" );
if ( substeps.length > 0 ) {
var sorted = sortSubsteps( substeps );
var visible = step.querySelectorAll( ".substep-visible" );
return showSubstep( sorted, visible );
}
};
var sortSubsteps = function( substepNodeList ) {
var substeps = Array.from( substepNodeList );
var sorted = substeps
.filter( el => el.dataset.substepOrder )
.sort( ( a, b ) => {
var orderA = a.dataset.substepOrder;
var orderB = b.dataset.substepOrder;
return parseInt( orderA ) - parseInt( orderB );
} )
.concat( substeps.filter( el => {
return el.dataset.substepOrder === undefined;
} ) );
return sorted;
};
var showSubstep = function( substeps, visible ) {
if ( visible.length < substeps.length ) {
for ( var i = 0; i < substeps.length; i++ ) {
substeps[ i ].classList.remove( "substep-active" );
}
// Loop over all substeps that are not yet visible and set
// those of currentSubstepOrder to visible and active
var el;
var currentSubstepOrder;
for ( var j = visible.length; j < substeps.length; j++ ) {
if ( currentSubstepOrder &&
currentSubstepOrder !== substeps[ j ].dataset.substepOrder ) {
// Stop if the substepOrder is greater
break;
}
el = substeps[ j ];
currentSubstepOrder = el.dataset.substepOrder;
el.classList.add( "substep-visible" );
el.classList.add( "substep-active" );
}
return el;
}
};
var hideSubstepIfAny = function( step ) {
var substeps = step.querySelectorAll( ".substep" );
var visible = step.querySelectorAll( ".substep-visible" );
var sorted = sortSubsteps( visible );
if ( substeps.length > 0 ) {
return hideSubstep( sorted );
}
};
var hideSubstep = function( visible ) {
if ( visible.length > 0 ) {
var current = -1;
for ( var i = 0; i < visible.length; i++ ) {
if ( visible[ i ].classList.contains( "substep-active" ) ) {
current = i;
}
visible[ i ].classList.remove( "substep-active" );
}
if ( current > 0 ) {
visible[ current - 1 ].classList.add( "substep-active" );
}
var el = visible[ visible.length - 1 ];
el.classList.remove( "substep-visible" );
// Continue if there is another substep with the same substepOrder
if ( current > 0 &&
visible[ current - 1 ].dataset.substepOrder ===
visible[ current ].dataset.substepOrder ) {
visible.pop();
return hideSubstep( 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 );