creative_rails 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }));