Source: components/video-defer.js

; (function () {
    'use strict';

    /**
     * Play videos based on scroll position
     * @namespace
     */
    db.libs.videoDefer = (function ($) {

        var name = 'videoDefer';

        /**
         * The threshold for when videos in view should be played
         * @private
         * @memberof db.libs.videoDefer
         * @constant {number}
         */
        var threshold = 200;

        /**
         * The array for all the videos to be played
         * @private
         * @memberof db.libs.videoDefer
         * @type {array}
         */
        var videos = [];

        /**
         * Check to see if scroll-listener has been added
         * @private
         * @memberof db.libs.videoDefer
         * @type {bool}
         */
        var scrollListenerAdded = false;

        /**
         * Plays a video with <code>data-video-defer="view"</code> attribute if it's within the viewport threshold
         * @private
         * @memberof db.libs.videoDefer
         */
        function playVideosInView() {
            var offset = $(document).scrollTop() + $(window).height() + threshold;
            videos.each(function (i, video) {
                if (video !== null) {
                    if ($(video).offset().top < offset) {
                        video.play(); // Take it away!
                        videos[i] = null;
                        $(video).attr('data-is-played', 'true');
                    }
                }
            });
        }

        /**
        * Find videos in document that haven't been played yet
        * @private
        * @memberof db.libs.videoDefer
        */
        function findVideos() {
            videos = $('[data-video-defer="view"]:not([data-is-played="true"])');
        }

        /**
        * Bind scroll-listener
        * @private
        * @memberof db.libs.videoDefer
        */
        function bindScroll() {
            scrollListenerAdded = true;
            $(window).on('scroll', function () {
                window.requestAnimationFrame(playVideosInView);
            });
        }

        /**
         * Initialize the component
         * @public
         * @memberof db.libs.videoDefer
         */
        function init() {
            if (!db.utils.isInitialized($('body'), name)) {
                if (document.readyState === 'complete') {
                    playVideosInView();
                } else {
                    window.addEventListener('load', function () {
                        setTimeout(function () {
                            playVideosInView();
                        }, 0);
                    });
                }

                // Find videos in document
                findVideos();

                // Bind scroll
                if(videos.length && !scrollListenerAdded) {
                    bindScroll();
                }

                // Set component as initialized
                db.utils.initialized($('body'), name);
            }
        }

        /**
         * Reflow the component
         * @public
         * @memberof db.libs.videoDefer
         */
        function reflow() {
            if (!scrollListenerAdded) {
                bindScroll();
            }

            findVideos();
            playVideosInView();
        }

        return {
            init: init,
            reflow: reflow
        };

    })(jQuery);
})();