creative_rails 1.0.2

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.
@@ -0,0 +1,947 @@
1
+
2
+ (function(root, factory) {
3
+ if (typeof define === 'function' && define.amd) {
4
+ define(factory);
5
+ } else if (typeof exports === 'object') {
6
+ module.exports = factory(require, exports, module);
7
+ } else {
8
+ root.ScrollReveal = factory();
9
+ }
10
+ }(this, function(require, exports, module) {
11
+
12
+
13
+ ///// ///// ///// /////
14
+ ///// ///// ///// /////
15
+ ///// ///// ///// /////
16
+ ///// ///// ///// /////
17
+ ///// ///// /////
18
+ ///// ///// /////
19
+ ///// ///// ///// /////
20
+ ///// ///// ///// /////
21
+ ///// /////
22
+ ///// /////
23
+ ///// ///// ///// /////
24
+ ///// ///// ///// /////
25
+ ///// ///// ///// /////
26
+ ///// ///// ///// /////
27
+
28
+ /**
29
+ * ScrollReveal
30
+ * ------------
31
+ * Version : 3.1.4
32
+ * Website : scrollrevealjs.org
33
+ * Repo : github.com/jlmakes/scrollreveal.js
34
+ * Author : Julian Lloyd (@jlmakes)
35
+ */
36
+
37
+ ;(function() {
38
+ 'use strict';
39
+
40
+ var
41
+ sr,
42
+ Tools,
43
+ _requestAnimationFrame;
44
+
45
+ this.ScrollReveal = (function() {
46
+
47
+ /**
48
+ * Configuration
49
+ * -------------
50
+ * This object signature can be passed directly to the ScrollReveal constructor,
51
+ * or as the second argument of the `reveal()` method.
52
+ */
53
+
54
+ ScrollReveal.prototype.defaults = {
55
+
56
+ // 'bottom', 'left', 'top', 'right'
57
+ origin : 'bottom',
58
+
59
+ // Can be any valid CSS distance, e.g. '5rem', '10%', '20vw', etc.
60
+ distance : '20px',
61
+
62
+ // Time in milliseconds.
63
+ duration : 500,
64
+ delay : 0,
65
+
66
+ // Starting angles in degrees, will transition from these values to 0 in all axes.
67
+ rotate : { x: 0, y: 0, z: 0 },
68
+
69
+ // Starting opacity value, before transitioning to the computed opacity.
70
+ opacity : 0,
71
+
72
+ // Starting scale value, will transition from this value to 1
73
+ scale : 0.9,
74
+
75
+ // Accepts any valid CSS easing, e.g. 'ease', 'ease-in-out', 'linear', etc.
76
+ easing : 'cubic-bezier(0.6, 0.2, 0.1, 1)',
77
+
78
+ // When null, `<html>` is assumed to be the reveal container. You can pass a
79
+ // DOM node as a custom container, e.g. document.querySelector('.fooContainer')
80
+ // or a selector, e.g. '.fooContainer'
81
+ container : null,
82
+
83
+ // true/false to control reveal animations on mobile.
84
+ mobile : true,
85
+
86
+ // true: reveals occur every time elements become visible
87
+ // false: reveals occur once as elements become visible
88
+ reset : false,
89
+
90
+ // 'always' — delay for all reveal animations
91
+ // 'once' — delay only the first time reveals occur
92
+ // 'onload' - delay only for animations triggered by first load
93
+ useDelay : 'always',
94
+
95
+ // Change when an element is considered in the viewport. The default value
96
+ // of 0.20 means 20% of an element must be visible for its reveal to occur.
97
+ viewFactor : 0.2,
98
+
99
+ // Pixel values that alter the container boundaries.
100
+ // e.g. Set `{ top: 48 }`, if you have a 48px tall fixed toolbar.
101
+ // --
102
+ // Visual Aid: https://scrollrevealjs.org/assets/viewoffset.png
103
+ viewOffset : { top: 0, right: 0, bottom: 0, left: 0 },
104
+
105
+ // Callbacks that fire for each completed element reveal, and if
106
+ // `config.reset = true`, for each completed element reset. When creating your
107
+ // callbacks, remember they are passed the element’s DOM node that triggered
108
+ // it as the first argument.
109
+ afterReveal : function(domEl) {},
110
+ afterReset : function(domEl) {}
111
+ };
112
+
113
+
114
+
115
+ function ScrollReveal(config) {
116
+
117
+ // Support instantiation without the `new` keyword.
118
+ if (typeof this == 'undefined' || Object.getPrototypeOf(this) !== ScrollReveal.prototype) {
119
+ return new ScrollReveal(config)
120
+ }
121
+
122
+ sr = this; // Save reference to instance.
123
+ sr.tools = new Tools(); // *required utilities
124
+
125
+ if (sr.isSupported()) {
126
+
127
+ sr.tools.extend(sr.defaults, config || {});
128
+
129
+ _resolveContainer(sr.defaults);
130
+
131
+ sr.store = {
132
+ elements : {},
133
+ containers : []
134
+ };
135
+
136
+ sr.sequences = {};
137
+ sr.history = [];
138
+ sr.uid = 0;
139
+ sr.initialized = false;
140
+ }
141
+
142
+ // Note: IE9 only supports console if devtools are open.
143
+ else if (typeof console !== 'undefined' && console !== null) {
144
+ console.log('ScrollReveal is not supported in this browser.');
145
+ }
146
+
147
+ return sr
148
+ }
149
+
150
+
151
+
152
+ /**
153
+ * Check if client supports CSS Transform and CSS Transition.
154
+ * @return {boolean}
155
+ */
156
+ ScrollReveal.prototype.isSupported = function() {
157
+ var style = document.documentElement.style;
158
+ return 'WebkitTransition' in style && 'WebkitTransform' in style
159
+ || 'transition' in style && 'transform' in style
160
+ };
161
+
162
+
163
+
164
+ /**
165
+ * Creates a reveal set, a group of elements that will animate when they
166
+ * become visible. If [interval] is provided, a new sequence is created
167
+ * that will ensure elements reveal in the order they appear in the DOM.
168
+ *
169
+ * @param {string|Node} [selector] The element (node) or elements (selector) to animate.
170
+ * @param {Object} [config] Override the defaults for this reveal set.
171
+ * @param {number} [interval] Time between sequenced element animations (milliseconds).
172
+ * @param {boolean} [sync] Used internally when updating reveals for async content.
173
+ *
174
+ * @return {Object} The current ScrollReveal instance.
175
+ */
176
+ ScrollReveal.prototype.reveal = function(selector, config, interval, sync) {
177
+
178
+ var
179
+ container,
180
+ elements,
181
+ elem,
182
+ elemId,
183
+ sequence,
184
+ sequenceId;
185
+
186
+ // Resolve container.
187
+ if (config && config.container) {
188
+ container = _resolveContainer(config);
189
+ } else {
190
+ container = sr.defaults.container;
191
+ }
192
+
193
+ // Let’s check to see if a DOM node was passed in as the first argument,
194
+ // otherwise query the container for all elements matching the selector.
195
+ if (sr.tools.isNode(selector)) {
196
+ elements = [selector];
197
+ } else {
198
+ elements = Array.prototype.slice.call(container.querySelectorAll(selector));
199
+ }
200
+
201
+ if (!elements.length) {
202
+ console.log('ScrollReveal: reveal on "'+ selector + '" failed, no elements found.');
203
+ return sr
204
+ }
205
+
206
+ // No custom configuration was passed, but a sequence interval instead.
207
+ // let’s shuffle things around to make sure everything works.
208
+ if (config && typeof config == 'number') {
209
+ interval = config;
210
+ config = {};
211
+ }
212
+
213
+ // Prepare a new sequence if an interval is passed.
214
+ if (interval && typeof interval == 'number') {
215
+ sequenceId = _nextUid();
216
+
217
+ sequence = sr.sequences[sequenceId] = {
218
+ id : sequenceId,
219
+ interval : interval,
220
+ elemIds : [],
221
+ active : false
222
+ }
223
+ }
224
+
225
+ // Begin main loop to configure ScrollReveal elements.
226
+ for (var i = 0; i < elements.length; i++) {
227
+
228
+ // Check if the element has already been configured and grab it from the store.
229
+ elemId = elements[i].getAttribute('data-sr-id');
230
+ if (elemId) {
231
+ elem = sr.store.elements[elemId];
232
+ }
233
+
234
+ // Otherwise, let’s do some basic setup.
235
+ else {
236
+ elem = {
237
+ id : _nextUid(),
238
+ domEl : elements[i],
239
+ seen : false,
240
+ revealing : false
241
+ };
242
+ elem.domEl.setAttribute('data-sr-id', elem.id);
243
+ }
244
+
245
+ // Sequence only setup
246
+ if (sequence) {
247
+
248
+ elem.sequence = {
249
+ id : sequence.id,
250
+ index : sequence.elemIds.length
251
+ };
252
+
253
+ sequence.elemIds.push(elem.id);
254
+ }
255
+
256
+ // New or existing element, it’s time to update its configuration, styles,
257
+ // and send the updates to our store.
258
+ _configure(elem, config || {});
259
+ _style(elem);
260
+ _updateStore(elem);
261
+
262
+ // We need to make sure elements are set to visibility: visible, even when
263
+ // on mobile and `config.mobile == false`, or if unsupported.
264
+ if (sr.tools.isMobile() && !elem.config.mobile || !sr.isSupported()) {
265
+ elem.domEl.setAttribute('style', elem.styles.inline);
266
+ elem.disabled = true;
267
+ }
268
+
269
+ // Otherwise, proceed normally.
270
+ else if (!elem.revealing) {
271
+ elem.domEl.setAttribute('style',
272
+ elem.styles.inline
273
+ + elem.styles.transform.initial
274
+ );
275
+ }
276
+ }
277
+
278
+ // Each `reveal()` is recorded so that when calling `sync()` while working
279
+ // with asynchronously loaded content, it can re-trace your steps but with
280
+ // all your new elements now in the DOM.
281
+
282
+ // Since `reveal()` is called internally by `sync()`, we don’t want to
283
+ // record or intiialize each reveal during syncing.
284
+ if (!sync && sr.isSupported()) {
285
+ _record(selector, config);
286
+
287
+ // We push initialization to the event queue using setTimeout, so that we can
288
+ // give ScrollReveal room to process all reveal calls before putting things into motion.
289
+ // --
290
+ // Philip Roberts - What the heck is the event loop anyway? (JSConf EU 2014)
291
+ // https://www.youtube.com/watch?v=8aGhZQkoFbQ
292
+ if (sr.initTimeout) {
293
+ window.clearTimeout(sr.initTimeout);
294
+ }
295
+ sr.initTimeout = window.setTimeout(_init, 0);
296
+ }
297
+
298
+ return sr
299
+ };
300
+
301
+
302
+
303
+ /**
304
+ * Re-runs `reveal()` for each record stored in history, effectively capturing
305
+ * any content loaded asynchronously that matches existing reveal set selectors.
306
+ *
307
+ * @return {Object} The current ScrollReveal instance.
308
+ */
309
+ ScrollReveal.prototype.sync = function() {
310
+ if (sr.history.length && sr.isSupported()) {
311
+ for (var i = 0; i < sr.history.length; i++) {
312
+ var record = sr.history[i];
313
+ sr.reveal(record.selector, record.config, record.interval, true);
314
+ };
315
+ _init();
316
+ } else {
317
+ console.log('ScrollReveal: sync failed, no reveals found.');
318
+ }
319
+ return sr
320
+ };
321
+
322
+
323
+
324
+ /**
325
+ * Private Methods
326
+ * ---------------
327
+ * These methods remain accessible only to the ScrollReveal instance, even
328
+ * though they only "exist" during instantiation outside of the constructors scope.
329
+ * --
330
+ * http://stackoverflow.com/questions/111102/how-do-javascript-closures-work
331
+ */
332
+
333
+ function _resolveContainer(config) {
334
+ var container = config.container;
335
+
336
+ // Check if our container is defined by a selector.
337
+ if (container && typeof container == 'string') {
338
+ return config.container = window.document.querySelector(container);
339
+ }
340
+
341
+ // Check if our container is defined by a node.
342
+ else if (container && !sr.tools.isNode(container)) {
343
+ console.log('ScrollReveal: Invalid container provided, using <html> instead.');
344
+ config.container = null;
345
+ }
346
+
347
+ // Otherwise use <html> by default.
348
+ if (container == null) {
349
+ config.container = window.document.documentElement;
350
+ }
351
+
352
+ return config.container
353
+ }
354
+
355
+
356
+
357
+ /**
358
+ * A consistent way of creating unique IDs.
359
+ * @returns {number}
360
+ */
361
+ function _nextUid() {
362
+ return ++sr.uid;
363
+ }
364
+
365
+
366
+
367
+ function _configure(elem, config) {
368
+
369
+ // If the element hasn’t already been configured, let’s use a clone of the
370
+ // defaults extended by the configuration passed as the second argument.
371
+ if (!elem.config) {
372
+ elem.config = sr.tools.extendClone(sr.defaults, config);
373
+ }
374
+
375
+ // Otherwise, let’s use a clone of the existing element configuration extended
376
+ // by the configuration passed as the second argument.
377
+ else {
378
+ elem.config = sr.tools.extendClone(elem.config, config);
379
+ }
380
+
381
+ // Infer CSS Transform axis from origin string.
382
+ if (elem.config.origin === 'top' || elem.config.origin === 'bottom') {
383
+ elem.config.axis = 'Y';
384
+ } else {
385
+ elem.config.axis = 'X';
386
+ }
387
+
388
+ // Let’s make sure our our pixel distances are negative for top and left.
389
+ // e.g. config.origin = 'top' and config.distance = '25px' starts at `top: -25px` in CSS.
390
+ if (elem.config.origin === 'top' || elem.config.origin === 'left') {
391
+ elem.config.distance = '-' + elem.config.distance;
392
+ }
393
+ }
394
+
395
+
396
+
397
+ function _style(elem) {
398
+ var computed = window.getComputedStyle(elem.domEl);
399
+
400
+ if (!elem.styles) {
401
+ elem.styles = {
402
+ transition : {},
403
+ transform : {},
404
+ computed : {}
405
+ };
406
+
407
+ // Capture any existing inline styles, and add our visibility override.
408
+ // --
409
+ // See section 4.2. in the Documentation:
410
+ // https://github.com/jlmakes/scrollreveal.js#42-improve-user-experience
411
+ elem.styles.inline = elem.domEl.getAttribute('style') || '';
412
+ elem.styles.inline += '; visibility: visible; ';
413
+
414
+ // grab the elements existing opacity.
415
+ elem.styles.computed.opacity = computed.opacity;
416
+
417
+ // grab the elements existing transitions.
418
+ if (!computed.transition || computed.transition == 'all 0s ease 0s') {
419
+ elem.styles.computed.transition = '';
420
+ } else {
421
+ elem.styles.computed.transition = computed.transition + ', ';
422
+ }
423
+ }
424
+
425
+ // Create transition styles
426
+ elem.styles.transition.instant = _generateTransition(elem, 0);
427
+ elem.styles.transition.delayed = _generateTransition(elem, elem.config.delay);
428
+
429
+ // Generate transform styles, first with the webkit prefix.
430
+ elem.styles.transform.initial = ' -webkit-transform:';
431
+ elem.styles.transform.target = ' -webkit-transform:';
432
+ _generateTransform(elem);
433
+
434
+ // And again without any prefix.
435
+ elem.styles.transform.initial += 'transform:';
436
+ elem.styles.transform.target += 'transform:';
437
+ _generateTransform(elem);
438
+
439
+ }
440
+
441
+
442
+
443
+ function _generateTransition(elem, delay) {
444
+ var config = elem.config;
445
+
446
+ return '-webkit-transition: ' + elem.styles.computed.transition +
447
+ '-webkit-transform ' + config.duration / 1000 + 's '
448
+ + config.easing + ' '
449
+ + delay / 1000 + 's, opacity '
450
+ + config.duration / 1000 + 's '
451
+ + config.easing + ' '
452
+ + delay / 1000 + 's; ' +
453
+
454
+ 'transition: ' + elem.styles.computed.transition +
455
+ 'transform ' + config.duration / 1000 + 's '
456
+ + config.easing + ' '
457
+ + delay / 1000 + 's, opacity '
458
+ + config.duration / 1000 + 's '
459
+ + config.easing + ' '
460
+ + delay / 1000 + 's; '
461
+ }
462
+
463
+
464
+
465
+ function _generateTransform(elem) {
466
+ var config = elem.config;
467
+ var transform = elem.styles.transform;
468
+
469
+ if (parseInt(config.distance)) {
470
+ transform.initial += ' translate' + config.axis + '(' + config.distance + ')';
471
+ transform.target += ' translate' + config.axis + '(0)';
472
+ }
473
+ if (config.scale) {
474
+ transform.initial += ' scale(' + config.scale + ')';
475
+ transform.target += ' scale(1)';
476
+ }
477
+ if (config.rotate.x) {
478
+ transform.initial += ' rotateX(' + config.rotate.x + 'deg)';
479
+ transform.target += ' rotateX(0)';
480
+ }
481
+ if (config.rotate.y) {
482
+ transform.initial += ' rotateY(' + config.rotate.y + 'deg)';
483
+ transform.target += ' rotateY(0)';
484
+ }
485
+ if (config.rotate.z) {
486
+ transform.initial += ' rotateZ(' + config.rotate.z + 'deg)';
487
+ transform.target += ' rotateZ(0)';
488
+ }
489
+ transform.initial += '; opacity: ' + config.opacity + ';';
490
+ transform.target += '; opacity: ' + elem.styles.computed.opacity + ';';
491
+ }
492
+
493
+
494
+
495
+ function _updateStore(elem) {
496
+ var container = elem.config.container;
497
+
498
+ // If this element’s container isn’t already in the store, let’s add it.
499
+ if (container && sr.store.containers.indexOf(container) == -1) {
500
+ sr.store.containers.push(elem.config.container);
501
+ }
502
+
503
+ // Update the element stored with our new element.
504
+ sr.store.elements[elem.id] = elem;
505
+ };
506
+
507
+
508
+
509
+ function _record(selector, config, interval) {
510
+
511
+ // Save the `reveal()` arguments that triggered this `_record()` call, so we
512
+ // can re-trace our steps when calling the `sync()` method.
513
+ var record = {
514
+ selector : selector,
515
+ config : config,
516
+ interval : interval
517
+ };
518
+ sr.history.push(record);
519
+ }
520
+
521
+
522
+
523
+ function _init() {
524
+ if (sr.isSupported()) {
525
+
526
+ // Initial animate call triggers valid reveal animations on first load.
527
+ // Subsequent animate calls are made inside the event handler.
528
+ _animate();
529
+
530
+ // Then we loop through all container nodes in the store and bind event
531
+ // listeners to each.
532
+ for (var i = 0; i < sr.store.containers.length; i++) {
533
+ sr.store.containers[i].addEventListener('scroll', _handler);
534
+ sr.store.containers[i].addEventListener('resize', _handler);
535
+ }
536
+
537
+ // Let’s also do a one-time binding of window event listeners.
538
+ if (!sr.initialized) {
539
+ window.addEventListener('scroll', _handler);
540
+ window.addEventListener('resize', _handler);
541
+ sr.initialized = true;
542
+ }
543
+ }
544
+ return sr
545
+ }
546
+
547
+
548
+
549
+ function _handler() {
550
+ _requestAnimationFrame(_animate);
551
+ }
552
+
553
+
554
+
555
+ function _setActiveSequences() {
556
+
557
+ var
558
+ active,
559
+ elem,
560
+ elemId,
561
+ sequence;
562
+
563
+ // Loop through all sequences
564
+ sr.tools.forOwn(sr.sequences, function(sequenceId) {
565
+ sequence = sr.sequences[sequenceId];
566
+ active = false;
567
+
568
+ // For each sequenced elemenet, let’s check visibility and if
569
+ // any are visible, set it’s sequence to active.
570
+ for (var i = 0; i < sequence.elemIds.length; i++) {
571
+ elemId = sequence.elemIds[i]
572
+ elem = sr.store.elements[elemId];
573
+ if (_isElemVisible(elem) && !active) {
574
+ active = true;
575
+ }
576
+ }
577
+
578
+ sequence.active = active;
579
+ });
580
+ }
581
+
582
+
583
+
584
+ function _animate() {
585
+
586
+ var
587
+ delayed,
588
+ elem;
589
+
590
+ _setActiveSequences();
591
+
592
+ // Loop through all elements in the store
593
+ sr.tools.forOwn(sr.store.elements, function(elemId) {
594
+
595
+ elem = sr.store.elements[elemId];
596
+ delayed = _shouldUseDelay(elem);
597
+
598
+ // Let’s see if we should reveal, and if so, whether to use delay.
599
+ if (_shouldReveal(elem)) {
600
+ if (delayed) {
601
+ elem.domEl.setAttribute('style',
602
+ elem.styles.inline
603
+ + elem.styles.transform.target
604
+ + elem.styles.transition.delayed
605
+ );
606
+ } else {
607
+ elem.domEl.setAttribute('style',
608
+ elem.styles.inline
609
+ + elem.styles.transform.target
610
+ + elem.styles.transition.instant
611
+ );
612
+ }
613
+
614
+ // Let’s queue the `afterReveal` callback and tag the element.
615
+ _queueCallback('reveal', elem, delayed);
616
+ elem.revealing = true;
617
+ elem.seen = true;
618
+
619
+ if (elem.sequence) {
620
+ _queueNextInSequence(elem, delayed);
621
+ }
622
+ }
623
+
624
+ // If we got this far our element shouldn’t reveal, but should it reset?
625
+ else if (_shouldReset(elem)) {
626
+ elem.domEl.setAttribute('style',
627
+ elem.styles.inline
628
+ + elem.styles.transform.initial
629
+ + elem.styles.transition.instant
630
+ );
631
+ _queueCallback('reset', elem);
632
+ elem.revealing = false;
633
+ }
634
+ });
635
+ }
636
+
637
+
638
+
639
+ /**
640
+ * Sequence callback that triggers the next element.
641
+ */
642
+ function _queueNextInSequence(elem, delayed) {
643
+
644
+ var
645
+ elapsed = 0,
646
+ delay = 0,
647
+ sequence = sr.sequences[elem.sequence.id];
648
+
649
+ // We’re processing a sequenced element, so let's block other elements in this sequence.
650
+ sequence.blocked = true;
651
+
652
+ // Since we’re triggering animations a part of a sequence after animations on first load,
653
+ // we need to check for that condition and explicitly add the delay to our timer.
654
+ if (delayed && elem.config.useDelay == 'onload') {
655
+ delay = elem.config.delay;
656
+ }
657
+
658
+ // If a sequence timer is already running, capture the elapsed time and clear it.
659
+ if (elem.sequence.timer) {
660
+ elapsed = Math.abs(elem.sequence.timer.started - new Date());
661
+ window.clearTimeout(elem.sequence.timer);
662
+ }
663
+
664
+ // Start a new timer.
665
+ elem.sequence.timer = { started: new Date() };
666
+ elem.sequence.timer.clock = window.setTimeout(function() {
667
+
668
+ // Sequence interval has passed, so unblock the sequence and re-run the handler.
669
+ sequence.blocked = false;
670
+ elem.sequence.timer = null;
671
+ _handler();
672
+
673
+ }, Math.abs(sequence.interval) + delay - elapsed);
674
+ }
675
+
676
+
677
+
678
+ function _queueCallback(type, elem, delayed) {
679
+
680
+ var
681
+ elapsed = 0,
682
+ duration = 0,
683
+ callback = 'after';
684
+
685
+ // Check which callback we’re working with.
686
+ switch (type) {
687
+
688
+ case 'reveal':
689
+ duration = elem.config.duration;
690
+ if (delayed) {
691
+ duration += elem.config.delay;
692
+ }
693
+ callback += 'Reveal';
694
+ break
695
+
696
+ case 'reset':
697
+ duration = elem.config.duration;
698
+ callback += 'Reset';
699
+ break
700
+ }
701
+
702
+ // If a timer is already running, capture the elapsed time and clear it.
703
+ if (elem.timer) {
704
+ elapsed = Math.abs(elem.timer.started - new Date());
705
+ window.clearTimeout(elem.timer.clock);
706
+ }
707
+
708
+ // Start a new timer.
709
+ elem.timer = { started: new Date() };
710
+ elem.timer.clock = window.setTimeout(function() {
711
+
712
+ // The timer completed, so let’s fire the callback and null the timer.
713
+ elem.config[callback](elem.domEl);
714
+ elem.timer = null;
715
+
716
+ }, duration - elapsed);
717
+ }
718
+
719
+
720
+
721
+ function _shouldReveal(elem) {
722
+ if (elem.sequence) {
723
+ var sequence = sr.sequences[elem.sequence.id];
724
+ return sequence.active
725
+ && !sequence.blocked
726
+ && !elem.revealing
727
+ && !elem.disabled
728
+ }
729
+ return _isElemVisible(elem)
730
+ && !elem.revealing
731
+ && !elem.disabled
732
+ }
733
+
734
+
735
+
736
+ function _shouldUseDelay(elem) {
737
+ var config = elem.config.useDelay;
738
+ return config === 'always'
739
+ || (config === 'onload' && !sr.initialized)
740
+ || (config === 'once' && !elem.seen)
741
+ }
742
+
743
+
744
+
745
+ function _shouldReset(elem) {
746
+ if (elem.sequence) {
747
+ var sequence = sr.sequences[elem.sequence.id];
748
+ return !sequence.active
749
+ && elem.config.reset
750
+ && elem.revealing
751
+ && !elem.disabled
752
+ }
753
+ return !_isElemVisible(elem)
754
+ && elem.config.reset
755
+ && elem.revealing
756
+ && !elem.disabled
757
+ }
758
+
759
+
760
+
761
+ function _getContainer(container) {
762
+ return {
763
+ width : container.clientWidth,
764
+ height : container.clientHeight
765
+ }
766
+ }
767
+
768
+
769
+
770
+ function _getScrolled(container) {
771
+
772
+ // Return the container scroll values, plus the its offset.
773
+ if (container && container !== window.document.documentElement) {
774
+ var offset = _getOffset(container);
775
+ return {
776
+ x : container.scrollLeft + offset.left,
777
+ y : container.scrollTop + offset.top
778
+ }
779
+ }
780
+
781
+ // Otherwise, default to the window object’s scroll values.
782
+ else {
783
+ return {
784
+ x : window.pageXOffset,
785
+ y : window.pageYOffset
786
+ }
787
+ }
788
+ }
789
+
790
+
791
+
792
+ function _getOffset(domEl) {
793
+
794
+ var
795
+ offsetTop = 0,
796
+ offsetLeft = 0,
797
+
798
+ // Grab the element’s dimensions.
799
+ offsetHeight = domEl.offsetHeight,
800
+ offsetWidth = domEl.offsetWidth;
801
+
802
+ // Now calculate the distance between the element and its parent, then
803
+ // again for the parent to its parent, and again etc... until we have the
804
+ // total distance of the element to the document’s top and left origin.
805
+ do {
806
+ if (!isNaN(domEl.offsetTop)) {
807
+ offsetTop += domEl.offsetTop;
808
+ }
809
+ if (!isNaN(domEl.offsetLeft)) {
810
+ offsetLeft += domEl.offsetLeft;
811
+ }
812
+ } while (domEl = domEl.offsetParent);
813
+
814
+ return {
815
+ top : offsetTop,
816
+ left : offsetLeft,
817
+ height : offsetHeight,
818
+ width : offsetWidth
819
+ }
820
+ }
821
+
822
+
823
+
824
+ function _isElemVisible(elem) {
825
+
826
+ var
827
+ offset = _getOffset(elem.domEl),
828
+ container = _getContainer(elem.config.container),
829
+ scrolled = _getScrolled(elem.config.container),
830
+ vF = elem.config.viewFactor,
831
+
832
+ // Define the element geometry.
833
+ elemHeight = offset.height,
834
+ elemWidth = offset.width,
835
+ elemTop = offset.top,
836
+ elemLeft = offset.left,
837
+ elemBottom = elemTop + elemHeight,
838
+ elemRight = elemLeft + elemWidth;
839
+
840
+ return confirmBounds() || isPositionFixed()
841
+
842
+ function confirmBounds() {
843
+
844
+ var
845
+ // Define the element’s functional boundaries using its view factor.
846
+ top = elemTop + elemHeight * vF,
847
+ left = elemLeft + elemWidth * vF,
848
+ bottom = elemBottom - elemHeight * vF,
849
+ right = elemRight - elemWidth * vF,
850
+
851
+ // Define the container functional boundaries using its view offset.
852
+ viewTop = scrolled.y + elem.config.viewOffset.top,
853
+ viewLeft = scrolled.x + elem.config.viewOffset.left,
854
+ viewBottom = scrolled.y - elem.config.viewOffset.bottom + container.height,
855
+ viewRight = scrolled.x - elem.config.viewOffset.right + container.width;
856
+
857
+ return top < viewBottom
858
+ && bottom > viewTop
859
+ && left > viewLeft
860
+ && right < viewRight
861
+ }
862
+
863
+ function isPositionFixed() {
864
+ return (window.getComputedStyle(elem.domEl).position === 'fixed')
865
+ }
866
+ }
867
+
868
+
869
+
870
+ return ScrollReveal
871
+
872
+ })();
873
+
874
+
875
+ /**
876
+ * helper.tools.js
877
+ * ---------------
878
+ * Simple deep object extend, and a few other agnostic helper methods.
879
+ * gist: https://gist.github.com/jlmakes/9f104e3f1b4d86334987
880
+ */
881
+
882
+ Tools = (function() {
883
+
884
+ Tools.prototype.isObject = function(object) {
885
+ return object !== null && typeof object === 'object' && object.constructor == Object
886
+ };
887
+
888
+ Tools.prototype.isNode = function(object) {
889
+ return typeof Node === 'object'
890
+ ? object instanceof Node
891
+ : object && typeof object === 'object'
892
+ && typeof object.nodeType === 'number'
893
+ && typeof object.nodeName === 'string'
894
+ };
895
+
896
+ Tools.prototype.forOwn = function(object, callback) {
897
+ if (!this.isObject(object)) {
898
+ throw new TypeError('Expected "object", but received "' + typeof object + '".');
899
+ } else {
900
+ for (var property in object) {
901
+ if (object.hasOwnProperty(property)) {
902
+ callback(property);
903
+ }
904
+ }
905
+ }
906
+ };
907
+
908
+ Tools.prototype.extend = function(target, source) {
909
+ this.forOwn(source, function(property) {
910
+ if (this.isObject(source[property])) {
911
+ if (!target[property] || !this.isObject(target[property])) {
912
+ target[property] = {};
913
+ }
914
+ this.extend(target[property], source[property]);
915
+ } else {
916
+ target[property] = source[property];
917
+ }
918
+ }.bind(this));
919
+ return target
920
+ };
921
+
922
+ Tools.prototype.extendClone = function(target, source) {
923
+ return this.extend(this.extend({}, target), source)
924
+ };
925
+
926
+ Tools.prototype.isMobile = function() {
927
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
928
+ };
929
+
930
+ function Tools() {};
931
+ return Tools
932
+
933
+ })();
934
+
935
+
936
+
937
+ _requestAnimationFrame = window.requestAnimationFrame ||
938
+ window.webkitRequestAnimationFrame ||
939
+ window.mozRequestAnimationFrame;
940
+
941
+
942
+
943
+ }).call(this);
944
+
945
+ return this.ScrollReveal;
946
+
947
+ }));