minimal-mistakes-jekyll 4.15.2 → 4.16.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,632 @@
1
+ /*!
2
+ * smooth-scroll v15.2.1
3
+ * Animate scrolling to anchor links
4
+ * (c) 2019 Chris Ferdinandi
5
+ * MIT License
6
+ * http://github.com/cferdinandi/smooth-scroll
7
+ */
8
+
9
+ (function (root, factory) {
10
+ if (typeof define === 'function' && define.amd) {
11
+ define([], (function () {
12
+ return factory(root);
13
+ }));
14
+ } else if (typeof exports === 'object') {
15
+ module.exports = factory(root);
16
+ } else {
17
+ root.SmoothScroll = factory(root);
18
+ }
19
+ })(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this, (function (window) {
20
+
21
+ 'use strict';
22
+
23
+ //
24
+ // Default settings
25
+ //
26
+
27
+ var defaults = {
28
+
29
+ // Selectors
30
+ ignore: '[data-scroll-ignore]',
31
+ header: null,
32
+ topOnEmptyHash: true,
33
+
34
+ // Speed & Duration
35
+ speed: 500,
36
+ speedAsDuration: false,
37
+ durationMax: null,
38
+ durationMin: null,
39
+ clip: true,
40
+ offset: 0,
41
+
42
+ // Easing
43
+ easing: 'easeInOutCubic',
44
+ customEasing: null,
45
+
46
+ // History
47
+ updateURL: true,
48
+ popstate: true,
49
+
50
+ // Custom Events
51
+ emitEvents: true
52
+
53
+ };
54
+
55
+
56
+ //
57
+ // Utility Methods
58
+ //
59
+
60
+ /**
61
+ * Check if browser supports required methods
62
+ * @return {Boolean} Returns true if all required methods are supported
63
+ */
64
+ var supports = function () {
65
+ return (
66
+ 'querySelector' in document &&
67
+ 'addEventListener' in window &&
68
+ 'requestAnimationFrame' in window &&
69
+ 'closest' in window.Element.prototype
70
+ );
71
+ };
72
+
73
+ /**
74
+ * Merge two or more objects together.
75
+ * @param {Object} objects The objects to merge together
76
+ * @returns {Object} Merged values of defaults and options
77
+ */
78
+ var extend = function () {
79
+ var merged = {};
80
+ Array.prototype.forEach.call(arguments, (function (obj) {
81
+ for (var key in obj) {
82
+ if (!obj.hasOwnProperty(key)) return;
83
+ merged[key] = obj[key];
84
+ }
85
+ }));
86
+ return merged;
87
+ };
88
+
89
+ /**
90
+ * Check to see if user prefers reduced motion
91
+ * @param {Object} settings Script settings
92
+ */
93
+ var reduceMotion = function (settings) {
94
+ if ('matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches) {
95
+ return true;
96
+ }
97
+ return false;
98
+ };
99
+
100
+ /**
101
+ * Get the height of an element.
102
+ * @param {Node} elem The element to get the height of
103
+ * @return {Number} The element's height in pixels
104
+ */
105
+ var getHeight = function (elem) {
106
+ return parseInt(window.getComputedStyle(elem).height, 10);
107
+ };
108
+
109
+ /**
110
+ * Escape special characters for use with querySelector
111
+ * @author Mathias Bynens
112
+ * @link https://github.com/mathiasbynens/CSS.escape
113
+ * @param {String} id The anchor ID to escape
114
+ */
115
+ var escapeCharacters = function (id) {
116
+
117
+ // Remove leading hash
118
+ if (id.charAt(0) === '#') {
119
+ id = id.substr(1);
120
+ }
121
+
122
+ var string = String(id);
123
+ var length = string.length;
124
+ var index = -1;
125
+ var codeUnit;
126
+ var result = '';
127
+ var firstCodeUnit = string.charCodeAt(0);
128
+ while (++index < length) {
129
+ codeUnit = string.charCodeAt(index);
130
+ // Note: there’s no need to special-case astral symbols, surrogate
131
+ // pairs, or lone surrogates.
132
+
133
+ // If the character is NULL (U+0000), then throw an
134
+ // `InvalidCharacterError` exception and terminate these steps.
135
+ if (codeUnit === 0x0000) {
136
+ throw new InvalidCharacterError(
137
+ 'Invalid character: the input contains U+0000.'
138
+ );
139
+ }
140
+
141
+ if (
142
+ // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
143
+ // U+007F, […]
144
+ (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
145
+ // If the character is the first character and is in the range [0-9]
146
+ // (U+0030 to U+0039), […]
147
+ (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
148
+ // If the character is the second character and is in the range [0-9]
149
+ // (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
150
+ (
151
+ index === 1 &&
152
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
153
+ firstCodeUnit === 0x002D
154
+ )
155
+ ) {
156
+ // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
157
+ result += '\\' + codeUnit.toString(16) + ' ';
158
+ continue;
159
+ }
160
+
161
+ // If the character is not handled by one of the above rules and is
162
+ // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
163
+ // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
164
+ // U+005A), or [a-z] (U+0061 to U+007A), […]
165
+ if (
166
+ codeUnit >= 0x0080 ||
167
+ codeUnit === 0x002D ||
168
+ codeUnit === 0x005F ||
169
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
170
+ codeUnit >= 0x0041 && codeUnit <= 0x005A ||
171
+ codeUnit >= 0x0061 && codeUnit <= 0x007A
172
+ ) {
173
+ // the character itself
174
+ result += string.charAt(index);
175
+ continue;
176
+ }
177
+
178
+ // Otherwise, the escaped character.
179
+ // http://dev.w3.org/csswg/cssom/#escape-a-character
180
+ result += '\\' + string.charAt(index);
181
+
182
+ }
183
+
184
+ // Return sanitized hash
185
+ return '#' + result;
186
+
187
+ };
188
+
189
+ /**
190
+ * Calculate the easing pattern
191
+ * @link https://gist.github.com/gre/1650294
192
+ * @param {String} type Easing pattern
193
+ * @param {Number} time Time animation should take to complete
194
+ * @returns {Number}
195
+ */
196
+ var easingPattern = function (settings, time) {
197
+ var pattern;
198
+
199
+ // Default Easing Patterns
200
+ if (settings.easing === 'easeInQuad') pattern = time * time; // accelerating from zero velocity
201
+ if (settings.easing === 'easeOutQuad') pattern = time * (2 - time); // decelerating to zero velocity
202
+ if (settings.easing === 'easeInOutQuad') pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
203
+ if (settings.easing === 'easeInCubic') pattern = time * time * time; // accelerating from zero velocity
204
+ if (settings.easing === 'easeOutCubic') pattern = (--time) * time * time + 1; // decelerating to zero velocity
205
+ if (settings.easing === 'easeInOutCubic') pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
206
+ if (settings.easing === 'easeInQuart') pattern = time * time * time * time; // accelerating from zero velocity
207
+ if (settings.easing === 'easeOutQuart') pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity
208
+ if (settings.easing === 'easeInOutQuart') pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
209
+ if (settings.easing === 'easeInQuint') pattern = time * time * time * time * time; // accelerating from zero velocity
210
+ if (settings.easing === 'easeOutQuint') pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity
211
+ if (settings.easing === 'easeInOutQuint') pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
212
+
213
+ // Custom Easing Patterns
214
+ if (!!settings.customEasing) pattern = settings.customEasing(time);
215
+
216
+ return pattern || time; // no easing, no acceleration
217
+ };
218
+
219
+ /**
220
+ * Determine the document's height
221
+ * @returns {Number}
222
+ */
223
+ var getDocumentHeight = function () {
224
+ return Math.max(
225
+ document.body.scrollHeight, document.documentElement.scrollHeight,
226
+ document.body.offsetHeight, document.documentElement.offsetHeight,
227
+ document.body.clientHeight, document.documentElement.clientHeight
228
+ );
229
+ };
230
+
231
+ /**
232
+ * Calculate how far to scroll
233
+ * Clip support added by robjtede - https://github.com/cferdinandi/smooth-scroll/issues/405
234
+ * @param {Element} anchor The anchor element to scroll to
235
+ * @param {Number} headerHeight Height of a fixed header, if any
236
+ * @param {Number} offset Number of pixels by which to offset scroll
237
+ * @param {Boolean} clip If true, adjust scroll distance to prevent abrupt stops near the bottom of the page
238
+ * @returns {Number}
239
+ */
240
+ var getEndLocation = function (anchor, headerHeight, offset, clip) {
241
+ var location = 0;
242
+ if (anchor.offsetParent) {
243
+ do {
244
+ location += anchor.offsetTop;
245
+ anchor = anchor.offsetParent;
246
+ } while (anchor);
247
+ }
248
+ location = Math.max(location - headerHeight - offset, 0);
249
+ if (clip) {
250
+ location = Math.min(location, getDocumentHeight() - window.innerHeight);
251
+ }
252
+ return location;
253
+ };
254
+
255
+ /**
256
+ * Get the height of the fixed header
257
+ * @param {Node} header The header
258
+ * @return {Number} The height of the header
259
+ */
260
+ var getHeaderHeight = function (header) {
261
+ return !header ? 0 : (getHeight(header) + header.offsetTop);
262
+ };
263
+
264
+ /**
265
+ * Calculate the speed to use for the animation
266
+ * @param {Number} distance The distance to travel
267
+ * @param {Object} settings The plugin settings
268
+ * @return {Number} How fast to animate
269
+ */
270
+ var getSpeed = function (distance, settings) {
271
+ var speed = settings.speedAsDuration ? settings.speed : Math.abs(distance / 1000 * settings.speed);
272
+ if (settings.durationMax && speed > settings.durationMax) return settings.durationMax;
273
+ if (settings.durationMin && speed < settings.durationMin) return settings.durationMin;
274
+ return parseInt(speed, 10);
275
+ };
276
+
277
+ var setHistory = function (options) {
278
+
279
+ // Make sure this should run
280
+ if (!history.replaceState || !options.updateURL || history.state) return;
281
+
282
+ // Get the hash to use
283
+ var hash = window.location.hash;
284
+ hash = hash ? hash : '';
285
+
286
+ // Set a default history
287
+ history.replaceState(
288
+ {
289
+ smoothScroll: JSON.stringify(options),
290
+ anchor: hash ? hash : window.pageYOffset
291
+ },
292
+ document.title,
293
+ hash ? hash : window.location.href
294
+ );
295
+
296
+ };
297
+
298
+ /**
299
+ * Update the URL
300
+ * @param {Node} anchor The anchor that was scrolled to
301
+ * @param {Boolean} isNum If true, anchor is a number
302
+ * @param {Object} options Settings for Smooth Scroll
303
+ */
304
+ var updateURL = function (anchor, isNum, options) {
305
+
306
+ // Bail if the anchor is a number
307
+ if (isNum) return;
308
+
309
+ // Verify that pushState is supported and the updateURL option is enabled
310
+ if (!history.pushState || !options.updateURL) return;
311
+
312
+ // Update URL
313
+ history.pushState(
314
+ {
315
+ smoothScroll: JSON.stringify(options),
316
+ anchor: anchor.id
317
+ },
318
+ document.title,
319
+ anchor === document.documentElement ? '#top' : '#' + anchor.id
320
+ );
321
+
322
+ };
323
+
324
+ /**
325
+ * Bring the anchored element into focus
326
+ * @param {Node} anchor The anchor element
327
+ * @param {Number} endLocation The end location to scroll to
328
+ * @param {Boolean} isNum If true, scroll is to a position rather than an element
329
+ */
330
+ var adjustFocus = function (anchor, endLocation, isNum) {
331
+
332
+ // Is scrolling to top of page, blur
333
+ if (anchor === 0) {
334
+ document.body.focus();
335
+ }
336
+
337
+ // Don't run if scrolling to a number on the page
338
+ if (isNum) return;
339
+
340
+ // Otherwise, bring anchor element into focus
341
+ anchor.focus();
342
+ if (document.activeElement !== anchor) {
343
+ anchor.setAttribute('tabindex', '-1');
344
+ anchor.focus();
345
+ anchor.style.outline = 'none';
346
+ }
347
+ window.scrollTo(0 , endLocation);
348
+
349
+ };
350
+
351
+ /**
352
+ * Emit a custom event
353
+ * @param {String} type The event type
354
+ * @param {Object} options The settings object
355
+ * @param {Node} anchor The anchor element
356
+ * @param {Node} toggle The toggle element
357
+ */
358
+ var emitEvent = function (type, options, anchor, toggle) {
359
+ if (!options.emitEvents || typeof window.CustomEvent !== 'function') return;
360
+ var event = new CustomEvent(type, {
361
+ bubbles: true,
362
+ detail: {
363
+ anchor: anchor,
364
+ toggle: toggle
365
+ }
366
+ });
367
+ document.dispatchEvent(event);
368
+ };
369
+
370
+
371
+ //
372
+ // SmoothScroll Constructor
373
+ //
374
+
375
+ var SmoothScroll = function (selector, options) {
376
+
377
+ //
378
+ // Variables
379
+ //
380
+
381
+ var smoothScroll = {}; // Object for public APIs
382
+ var settings, anchor, toggle, fixedHeader, eventTimeout, animationInterval;
383
+
384
+
385
+ //
386
+ // Methods
387
+ //
388
+
389
+ /**
390
+ * Cancel a scroll-in-progress
391
+ */
392
+ smoothScroll.cancelScroll = function (noEvent) {
393
+ cancelAnimationFrame(animationInterval);
394
+ animationInterval = null;
395
+ if (noEvent) return;
396
+ emitEvent('scrollCancel', settings);
397
+ };
398
+
399
+ /**
400
+ * Start/stop the scrolling animation
401
+ * @param {Node|Number} anchor The element or position to scroll to
402
+ * @param {Element} toggle The element that toggled the scroll event
403
+ * @param {Object} options
404
+ */
405
+ smoothScroll.animateScroll = function (anchor, toggle, options) {
406
+
407
+ // Cancel any in progress scrolls
408
+ smoothScroll.cancelScroll();
409
+
410
+ // Local settings
411
+ var _settings = extend(settings || defaults, options || {}); // Merge user options with defaults
412
+
413
+ // Selectors and variables
414
+ var isNum = Object.prototype.toString.call(anchor) === '[object Number]' ? true : false;
415
+ var anchorElem = isNum || !anchor.tagName ? null : anchor;
416
+ if (!isNum && !anchorElem) return;
417
+ var startLocation = window.pageYOffset; // Current location on the page
418
+ if (_settings.header && !fixedHeader) {
419
+ // Get the fixed header if not already set
420
+ fixedHeader = document.querySelector(_settings.header);
421
+ }
422
+ var headerHeight = getHeaderHeight(fixedHeader);
423
+ var endLocation = isNum ? anchor : getEndLocation(anchorElem, headerHeight, parseInt((typeof _settings.offset === 'function' ? _settings.offset(anchor, toggle) : _settings.offset), 10), _settings.clip); // Location to scroll to
424
+ var distance = endLocation - startLocation; // distance to travel
425
+ var documentHeight = getDocumentHeight();
426
+ var timeLapsed = 0;
427
+ var speed = getSpeed(distance, _settings);
428
+ var start, percentage, position;
429
+
430
+ /**
431
+ * Stop the scroll animation when it reaches its target (or the bottom/top of page)
432
+ * @param {Number} position Current position on the page
433
+ * @param {Number} endLocation Scroll to location
434
+ * @param {Number} animationInterval How much to scroll on this loop
435
+ */
436
+ var stopAnimateScroll = function (position, endLocation) {
437
+
438
+ // Get the current location
439
+ var currentLocation = window.pageYOffset;
440
+
441
+ // Check if the end location has been reached yet (or we've hit the end of the document)
442
+ if (position == endLocation || currentLocation == endLocation || ((startLocation < endLocation && window.innerHeight + currentLocation) >= documentHeight)) {
443
+
444
+ // Clear the animation timer
445
+ smoothScroll.cancelScroll(true);
446
+
447
+ // Bring the anchored element into focus
448
+ adjustFocus(anchor, endLocation, isNum);
449
+
450
+ // Emit a custom event
451
+ emitEvent('scrollStop', _settings, anchor, toggle);
452
+
453
+ // Reset start
454
+ start = null;
455
+ animationInterval = null;
456
+
457
+ return true;
458
+
459
+ }
460
+ };
461
+
462
+ /**
463
+ * Loop scrolling animation
464
+ */
465
+ var loopAnimateScroll = function (timestamp) {
466
+ if (!start) { start = timestamp; }
467
+ timeLapsed += timestamp - start;
468
+ percentage = speed === 0 ? 0 : (timeLapsed / speed);
469
+ percentage = (percentage > 1) ? 1 : percentage;
470
+ position = startLocation + (distance * easingPattern(_settings, percentage));
471
+ window.scrollTo(0, Math.floor(position));
472
+ if (!stopAnimateScroll(position, endLocation)) {
473
+ animationInterval = window.requestAnimationFrame(loopAnimateScroll);
474
+ start = timestamp;
475
+ }
476
+ };
477
+
478
+ /**
479
+ * Reset position to fix weird iOS bug
480
+ * @link https://github.com/cferdinandi/smooth-scroll/issues/45
481
+ */
482
+ if (window.pageYOffset === 0) {
483
+ window.scrollTo(0, 0);
484
+ }
485
+
486
+ // Update the URL
487
+ updateURL(anchor, isNum, _settings);
488
+
489
+ // Emit a custom event
490
+ emitEvent('scrollStart', _settings, anchor, toggle);
491
+
492
+ // Start scrolling animation
493
+ smoothScroll.cancelScroll(true);
494
+ window.requestAnimationFrame(loopAnimateScroll);
495
+
496
+ };
497
+
498
+ /**
499
+ * If smooth scroll element clicked, animate scroll
500
+ */
501
+ var clickHandler = function (event) {
502
+
503
+ // Don't run if the user prefers reduced motion
504
+ if (reduceMotion(settings)) return;
505
+
506
+ // Don't run if right-click or command/control + click
507
+ if (event.button !== 0 || event.metaKey || event.ctrlKey) return;
508
+
509
+ // Check if event.target has closest() method
510
+ // By @totegi - https://github.com/cferdinandi/smooth-scroll/pull/401/
511
+ if(!('closest' in event.target))return;
512
+
513
+ // Check if a smooth scroll link was clicked
514
+ toggle = event.target.closest(selector);
515
+ if (!toggle || toggle.tagName.toLowerCase() !== 'a' || event.target.closest(settings.ignore)) return;
516
+
517
+ // Only run if link is an anchor and points to the current page
518
+ if (toggle.hostname !== window.location.hostname || toggle.pathname !== window.location.pathname || !/#/.test(toggle.href)) return;
519
+
520
+ // Get an escaped version of the hash
521
+ var hash = escapeCharacters(toggle.hash);
522
+
523
+ // Get the anchored element
524
+ var anchor = settings.topOnEmptyHash && hash === '#' ? document.documentElement : document.querySelector(hash);
525
+ anchor = !anchor && hash === '#top' ? document.documentElement : anchor;
526
+
527
+ // If anchored element exists, scroll to it
528
+ if (!anchor) return;
529
+ event.preventDefault();
530
+ setHistory(settings);
531
+ smoothScroll.animateScroll(anchor, toggle);
532
+
533
+ };
534
+
535
+ /**
536
+ * Animate scroll on popstate events
537
+ */
538
+ var popstateHandler = function (event) {
539
+
540
+ // Stop if history.state doesn't exist (ex. if clicking on a broken anchor link).
541
+ // fixes `Cannot read property 'smoothScroll' of null` error getting thrown.
542
+ if (history.state === null) return;
543
+
544
+ // Only run if state is a popstate record for this instantiation
545
+ if (!history.state.smoothScroll || history.state.smoothScroll !== JSON.stringify(settings)) return;
546
+
547
+ // Only run if state includes an anchor
548
+
549
+ // if (!history.state.anchor && history.state.anchor !== 0) return;
550
+
551
+ // Get the anchor
552
+ var anchor = history.state.anchor;
553
+ if (typeof anchor === 'string' && anchor) {
554
+ anchor = document.querySelector(escapeCharacters(history.state.anchor));
555
+ if (!anchor) return;
556
+ }
557
+
558
+ // Animate scroll to anchor link
559
+ smoothScroll.animateScroll(anchor, null, {updateURL: false});
560
+
561
+ };
562
+
563
+ /**
564
+ * Destroy the current initialization.
565
+ */
566
+ smoothScroll.destroy = function () {
567
+
568
+ // If plugin isn't already initialized, stop
569
+ if (!settings) return;
570
+
571
+ // Remove event listeners
572
+ document.removeEventListener('click', clickHandler, false);
573
+ window.removeEventListener('popstate', popstateHandler, false);
574
+
575
+ // Cancel any scrolls-in-progress
576
+ smoothScroll.cancelScroll();
577
+
578
+ // Reset variables
579
+ settings = null;
580
+ anchor = null;
581
+ toggle = null;
582
+ fixedHeader = null;
583
+ eventTimeout = null;
584
+ animationInterval = null;
585
+
586
+ };
587
+
588
+ /**
589
+ * Initialize Smooth Scroll
590
+ * @param {Object} options User settings
591
+ */
592
+ smoothScroll.init = function (options) {
593
+
594
+ // feature test
595
+ if (!supports()) throw 'Smooth Scroll: This browser does not support the required JavaScript methods and browser APIs.';
596
+
597
+ // Destroy any existing initializations
598
+ smoothScroll.destroy();
599
+
600
+ // Selectors and variables
601
+ settings = extend(defaults, options || {}); // Merge user options with defaults
602
+ fixedHeader = settings.header ? document.querySelector(settings.header) : null; // Get the fixed header
603
+
604
+ // When a toggle is clicked, run the click handler
605
+ document.addEventListener('click', clickHandler, false);
606
+
607
+ // If updateURL and popState are enabled, listen for pop events
608
+ if (settings.updateURL && settings.popstate) {
609
+ window.addEventListener('popstate', popstateHandler, false);
610
+ }
611
+
612
+ };
613
+
614
+
615
+ //
616
+ // Initialize plugin
617
+ //
618
+
619
+ smoothScroll.init(options);
620
+
621
+
622
+ //
623
+ // Public APIs
624
+ //
625
+
626
+ return smoothScroll;
627
+
628
+ };
629
+
630
+ return SmoothScroll;
631
+
632
+ }));