symphonycms/symphony-2

View on GitHub
symphony/assets/js/src/symphony.affix.js

Summary

Maintainability
A
1 hr
Test Coverage
/**
 * @package assets
 */

(function($, Symphony) {
    'use strict';

    // holds up all instances
    var instances = $();
    // last scroll position
    var scrollTop = 0;

    /**
     * Create affix elements.
     * Affix elements follow the scroll and are constrain by their container.
     *
     * @since Symphony 2.5
     *
     * @name $.symphonyAffix
     * @class
     *
     * @param {Object} options An object specifying containing the attributes specified below
     * @param {String} [options.container=$(this).parent()] Selector to find affix container
     *
     * @example

            var affix = $('#affix').symphonyAffix({
                container:        '.parent',
            });
     */
    $.fn.symphonyAffix = function(options) {
        var objects = $(this),
            settings = {
                // public
                container: null,
                // private
                top: 0,
                freespace: 0,
                bottom: 0,
                height: 0,
                maxtop: 0
            };

        $.extend(settings, options);


        /*---------------------------------------------------------------------
            Initialisation
        ---------------------------------------------------------------------*/

        objects.each(function createOneAffix() {
            var itemSettings = $.extend({}, settings);
            var item = $(this);
            var updateItemSettings = function () {
                itemSettings.top = itemSettings.container.offset().top;
                itemSettings.freespace = itemSettings.container.height();
                itemSettings.bottom = itemSettings.top + itemSettings.freespace;
                itemSettings.height = item.height();
                itemSettings.maxtop = (itemSettings.freespace - itemSettings.height) + 'px';
            };

            // use parent as default container
            if (!itemSettings.container) {
                itemSettings.container = item.parent();
            }

            // resolve jQuery object
            else {
                itemSettings.container = $(itemSettings.container);
            }

            // cache cssom values
            updateItemSettings();
            item.on('updatesettings.affix', updateItemSettings);

            item.addClass('js-affix');

            // save instance settings
            item.data('affix-settings', itemSettings);

            // register instance
            instances = instances.add(item);
        });

        // Init
        $(window).triggerHandler('scroll');

        return objects;
    };

    /*-----------------------------------------------------------------------*/

    // One listener for all instances
    $(window).on('scroll', function affixScroll() {
        scrollTop = $(this).scrollTop();
        Symphony.Utilities.requestAnimationFrame(function affixScrollRaf() {
            instances.each(function affixScrollOne() {
                var item = $(this);
                var settings = item.data('affix-settings');
                var cssClass = 'js-affix-scroll';
                var top = '';
                if (scrollTop < settings.top) {
                    cssClass = 'js-affix-top';
                } else if (scrollTop > settings.bottom) {
                    cssClass = 'js-affix-bottom';
                    top = settings.maxtop;
                }
                // Do changes only if state changes
                if (!item.hasClass(cssClass)) {
                    item
                        .removeClass('js-affix-scroll js-affix-top js-affix-bottom')
                        .addClass(cssClass)
                        .css({top: top});
                }
            });
        });
    });

})(window.jQuery, window.Symphony);