/
substep.js
177 lines (151 loc) · 6.21 KB
/
substep.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/**
* 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" );
if ( currentSubstepOrder === undefined ) {
// Stop after one substep as default order
break;
}
}
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 ].dataset.substepOrder !== undefined &&
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 );