reveal.js-appearance 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,19 +28,62 @@ const Plugin = () => {
28
28
  head.appendChild(style);
29
29
  }
30
30
 
31
+ const isJSON = str => {
32
+ try {
33
+ return (JSON.parse(str) && !!str);
34
+ } catch (e) {
35
+ return false;
36
+ }
37
+ };
38
+
39
+ const isObj = (test) => {
40
+ while ( Object.prototype.toString.call(test) === '[object Object]')
41
+ if ((test = Object.getPrototypeOf(test)) === null)
42
+ return true
43
+ return false
44
+ }
45
+
31
46
  const selectionArray = function (container, selectors) {
32
47
  let selections = container.querySelectorAll(selectors);
33
48
  let selectionarray = Array.prototype.slice.call(selections);
34
49
  return selectionarray;
35
50
  };
36
51
 
52
+ const isStack = function (section) {
53
+ let isStack = false;
54
+ for (let i = 0; i < section.childNodes.length; i++) {
55
+ if (section.childNodes[i].tagName == "SECTION") {
56
+ isStack = true
57
+ break;
58
+ }
59
+ }
60
+ return isStack;
61
+ };
62
+
63
+ function copyDataAttributes(source, target, not) {
64
+ [...source.attributes].filter( attr => attr.nodeName.indexOf('data') > -1).forEach( attr => {
65
+ if ((not && attr.nodeName !== not) || !not) {
66
+ target.setAttribute(attr.nodeName, attr.nodeValue)
67
+ }
68
+ })
69
+ }
70
+
71
+
37
72
  const appear = function (deck, options) {
38
73
 
39
74
  let baseclass = 'animate__animated';
75
+ let viewport = (deck.getRevealElement()).tagName == "BODY" ? document : deck.getRevealElement();
40
76
  let appearanceSelector = options.compatibility ? `.${options.compatibilitybaseclass}` : `.${baseclass}`;
41
- let fragmentSelector = ".fragment"
77
+ let fragmentSelector = ".fragment";
78
+
79
+ let speedClasses = ['slower', 'slow', 'fast', 'faster'];
80
+ speedClasses.push(...speedClasses.map(speed => `animate__${speed}`));
81
+
82
+ const generator = document.querySelector('[name=generator]');
83
+
84
+ const sections = selectionArray(viewport, "section");
85
+ const regularSections = sections.filter( section => !isStack(section) && section.dataset.visibility != "hidden");
42
86
 
43
- const sections = deck.getRevealElement().querySelectorAll(`.slides section`);
44
87
  const fragments = deck.getRevealElement().querySelectorAll(fragmentSelector);
45
88
  let animatecss = '[class^="animate__"],[class*=" animate__"]'
46
89
 
@@ -48,17 +91,157 @@ const Plugin = () => {
48
91
  if (options.debug) console.log(text);
49
92
  }
50
93
 
94
+ const assignAutoClass = (section, str, kind) => {
95
+
96
+ let index = [...section.parentElement.children].filter(s => s.tagName=="SECTION").indexOf(section) + 1;
97
+
98
+ let warning = kind == 'global' ? `JSON Parse error, please try to correct the global "autoelements" option.` : `JSON Parse error, please try to correct the "data-autoappear" attribute on section ${index}`;
99
+
100
+ if (typeof str === "string") str = str.replace(/[“”]/g,'"').replace(/[‘’]/g,"'");
101
+
102
+ let strJSON = isJSON(str) ? str : typeof str === "object" ? JSON.stringify(str, null, 2) : str.trim().replace(/'/g, '"').charAt(0) === "{" ? str.trim().replace(/'/g, '"') : `{${str.trim().replace(/'/g, '"')}}`;
103
+
104
+
105
+ if (!isJSON(strJSON)) {
106
+ console.log(warning);
107
+ } else {
108
+ let elementsToAnimate = JSON.parse(strJSON);
109
+
110
+ for (const [element, assignables] of Object.entries(elementsToAnimate)) {
111
+
112
+ let elementsInSection = section.querySelectorAll(element);
113
+
114
+ elementsInSection.forEach(elementInSection => {
115
+
116
+ if (!elementInSection.classList.contains(baseclass) || elementInSection.dataset["autoappear"]) {
117
+
118
+ elementInSection.dataset["autoappear"] = true;
119
+
120
+ let newClasses = [], newDelay = null, speedClass = false;
121
+
122
+ if (Array.isArray(assignables)) {
123
+ newClasses = assignables[0].split(/[ ,]+/);
124
+ newDelay = assignables[1];
125
+ } else if (typeof assignables == "string"){
126
+ newClasses = assignables.split(/[ ,]+/);
127
+ }
128
+
129
+ speedClasses.forEach(speed => {
130
+ if (elementInSection.classList.contains(speed)) {
131
+ speedClass = speed;
132
+ }
133
+ })
134
+
135
+ let classesToRemove = [];
136
+ elementInSection.classList.forEach(currentClass => {
137
+ if (String(currentClass).includes("animate__")) {
138
+ classesToRemove.push(currentClass);
139
+ }
140
+ })
141
+ classesToRemove.forEach(currentClass => {elementInSection.classList.remove(currentClass)});
142
+
143
+ newClasses.forEach(newClass => {
144
+ if (speedClasses.includes(newClass)) {
145
+ // There is a speed class from JSON to be assigned
146
+ if (speedClass) { speedClass = newClass }
147
+ }
148
+ });
149
+
150
+ newClasses.forEach(newClass => {
151
+ elementInSection.classList.add(newClass);
152
+ });
153
+
154
+ if (speedClass) {
155
+ elementInSection.classList.add(speedClass);
156
+ }
157
+
158
+
159
+
160
+
161
+ if (newDelay) {
162
+ elementInSection.dataset.delay = newDelay;
163
+ }
164
+
165
+ elementInSection.classList.add(baseclass);
166
+
167
+ }
168
+
169
+
170
+ });
171
+ }
172
+ }
173
+ };
174
+
51
175
  const findAppearancesIn = function (container, includeClass, excludeClass) {
52
176
  if (!isStack(container)) {
53
177
  let appearances = selectionArray(container, `:scope ${includeClass}`);
178
+
179
+ appearances.forEach(appearance => {
180
+
181
+ let convertListItem = (appearance) => {
182
+ let from = appearance, to = appearance.parentNode;
183
+ if (!to) return
184
+ for (let sibling of to.children) {
185
+ if (sibling !== appearance) { if (sibling.dataset.appearParent) return }
186
+ }
187
+ to.classList = from.classList;
188
+ copyDataAttributes(from, to, "data-appear-parent");
189
+ to.innerHTML = from.innerHTML;
190
+ }
191
+
192
+ // Conversion of list items with Appearance classes to the parent, needs manual attribute
193
+ // Relates to Quarto wrapping list content in a span.
194
+ if (appearance.hasAttribute("data-appear-parent")) {
195
+ convertListItem(appearance);
196
+ }
197
+
198
+ // Automatic conversion of list items which directly contain spans.
199
+ // Relates to Quarto wrapping list content in a span.
200
+ if (options.appearparents) {
201
+ if (appearance.parentNode && appearance.parentNode.tagName) {
202
+ if (appearance.tagName == "SPAN" && appearance.parentNode.tagName == "LI") {
203
+ let spanLength = String(appearance.outerHTML).length;
204
+ let liContentLength = String(appearance.parentNode.innerHTML).length;
205
+ if (spanLength == liContentLength) {
206
+ convertListItem(appearance);
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+
213
+ });
214
+
215
+ appearances = selectionArray(container, `:scope ${includeClass}`);
54
216
  let excludes = selectionArray(container, `:scope ${excludeClass} ${includeClass}`);
55
217
  let delay = 0;
56
-
218
+
57
219
  appearances.filter(function (appearance, index) {
58
- if ( !(excludes.indexOf(appearance) > -1 ) ) {
220
+ if ( !(excludes.indexOf(appearance) > -1 ) ) {
59
221
  if ((index == 0 && appearance.dataset.delay) || index !=0) {
60
- let elementDelay = appearance.dataset.delay ? (parseInt(appearance.dataset.delay)) : options.delay;
222
+
223
+ let elementDelay = options.delay;
224
+ if (appearance.dataset && appearance.dataset.delay) {
225
+ elementDelay = parseInt(appearance.dataset.delay);
226
+ }
227
+
61
228
  delay = delay + elementDelay;
229
+
230
+ // Allow fragments to be Appearance items
231
+ if (appearance.classList.contains("fragment")) {
232
+ delay = 0;
233
+ if (appearance.querySelectorAll(`.${baseclass}`)) {
234
+ let firstNestedAppearance = appearance.querySelectorAll(`.${baseclass}`)[0];
235
+
236
+ if (firstNestedAppearance) {
237
+ let elementDelay = options.delay;
238
+ if (firstNestedAppearance.dataset && firstNestedAppearance.dataset.delay) {
239
+ elementDelay = parseInt(firstNestedAppearance.dataset.delay);
240
+ }
241
+ firstNestedAppearance.dataset.delay = elementDelay
242
+ }
243
+ }
244
+ }
62
245
  appearance.style.setProperty('animation-delay', delay + "ms");
63
246
  }
64
247
  }
@@ -68,46 +251,46 @@ const Plugin = () => {
68
251
 
69
252
  const autoAdd = function () {
70
253
 
71
- if (options.autoelements) {
254
+ regularSections.forEach(section => {
72
255
 
73
- for (const [autoelement, autoanimation] of Object.entries(options.autoelements)) {
256
+ if (section.hasAttribute("data-autoappear")) {
74
257
 
75
- if (options.autoappear) {
76
- debugLog(`All "${autoelement}"" elements will animate with ${autoanimation}`);
77
- }
78
- let autosection = options.autoappear ? "" : "[data-autoappear] ";
79
- let autoAppearances = deck.getRevealElement().querySelectorAll(`.slides ${autosection}${autoelement}`);
80
-
81
- if (autoAppearances.length > 0) {
82
- autoAppearances.forEach(autoAppearance => {
83
- if (!autoAppearance.classList.contains(baseclass)) {
84
- autoAppearance.classList.add(baseclass);
85
- autoAppearance.classList.add(autoanimation);
258
+ let sectDataAppear = section.dataset.autoappear;
259
+
260
+ if (sectDataAppear == "auto" || sectDataAppear == "" || sectDataAppear.length < 1 || sectDataAppear == "true") {
261
+ // This section should get the global autoappear classes on its objects
262
+ if (options.autoelements) {
263
+ if (!options.autoelements) {
264
+ return console.log(`Please add some elements in the option "autoelements"`);
86
265
  }
87
- });
266
+ assignAutoClass(section, options.autoelements, 'global')
267
+ }
268
+ } else if (sectDataAppear.length > 0) {
269
+ // This section should get the local data-autoappear classes on its objects
270
+ assignAutoClass(section, sectDataAppear, 'local');
271
+ //section.removeAttribute("data-autoappear");
88
272
  }
89
- }
90
- } else if (options.autoappear) {
91
- console.log(`Please set an "autoelements" object.`);
92
- }
93
- }
273
+ } else {
94
274
 
95
- const isStack = function (section) {
96
- let isStack = false;
97
- for (let i = 0; i < section.childNodes.length; i++) {
98
- if (section.childNodes[i].tagName == "SECTION") {
99
- isStack = true
100
- break;
275
+ if (options.autoappear) {
276
+ if (!options.autoelements) {
277
+ return console.log(`Please add some elements in the option "autoelements"`);
278
+ }
279
+ // This section should get the global autoappear classes on its objects
280
+ assignAutoClass(section, options.autoelements, 'global')
281
+ }
101
282
  }
102
- }
103
- return isStack;
104
- };
283
+ });
284
+
285
+ }
105
286
 
106
287
  if (options.compatibility) {
107
288
  animatecss = '.backInDown, .backInLeft, .backInRight, .backInUp, .bounceIn, .bounceInDown, .bounceInLeft, .bounceInRight, .bounceInUp, .fadeIn, .fadeInDown, .fadeInDownBig, .fadeInLeft, .fadeInLeftBig, .fadeInRight, .fadeInRightBig, .fadeInUp, .fadeInUpBig, .fadeInTopLeft, .fadeInTopRight, .fadeInBottomLeft, .fadeInBottomRight, .flipInX, .flipInY, .lightSpeedInRight, .lightSpeedInLeft, .rotateIn, .rotateInDownLeft, .rotateInDownRight, .rotateInUpLeft, .rotateInUpRight, .jackInTheBox, .rollIn, .zoomIn, .zoomInDown, .zoomInLeft, .zoomInRight, .zoomInUp, .slideInDown, .slideInLeft, .slideInRight, .slideInUp, .skidLeft, .skidLeftBig, .skidRight, .skidRightBig, .shrinkIn, .shrinkInBlur';
108
289
  baseclass = options.compatibilitybaseclass
109
290
  }
110
291
 
292
+
293
+
111
294
  let allappearances = deck.getRevealElement().querySelectorAll(animatecss);
112
295
 
113
296
  allappearances.forEach(appearance => {
@@ -156,11 +339,17 @@ const Plugin = () => {
156
339
 
157
340
  if (etype == "slidetransitionend") {
158
341
  if (options.hideagain) {
159
- delete slides.from?.dataset.appearanceCanStart;
160
- let fromFragments = slides.from.querySelectorAll(`.fragment.visible`);
161
- fromFragments.forEach(fragment => {
162
- fragment.classList.remove('visible');
163
- })
342
+ if (slides.from) {
343
+ if (slides.from.dataset.appearanceCanStart) {
344
+ delete slides.from.dataset.appearanceCanStart;
345
+ }
346
+ let fromFragments = slides.from.querySelectorAll(`.fragment.visible`);
347
+ if (fromFragments) {
348
+ fromFragments.forEach(fragment => {
349
+ fragment.classList.remove('visible');
350
+ })
351
+ }
352
+ }
164
353
  }
165
354
  }
166
355
 
@@ -204,10 +393,11 @@ const Plugin = () => {
204
393
  appearevent: 'slidetransitionend',
205
394
  autoappear: false,
206
395
  autoelements: false,
396
+ appearparents: false,
207
397
  csspath: '',
208
398
  animatecsspath: {
209
399
  link : 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css',
210
- compat : 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.compat.css',
400
+ compat : 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.compat.css',
211
401
  },
212
402
  compatibility: false,
213
403
  compatibilitybaseclass: 'animated'
package/screenshot.png CHANGED
Binary file