Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
drupal/melt_sticky_drawer / js / meltStickyDrawer.js
Size: Mime:
(function ($, _, window) {

    function StickyDrawer(options) {
        this.setupVars(options);
        this.setupEvents();
    }

    StickyDrawer.prototype.defaults = {
        target: '.sticky-drawer',
        targetWrapper: '.sticky-drawer-wrapper',
        toggle: '.sticky-drawer-toggle',
        scrollToContainer: '.sticky-drawer-wrapper',
        fixedClass: 'is-fixed',
        isResizing: false,
        toggleAction: 'scroll'
    };

    /**
     * Sets up all of the variables to be used across the different methods
     *
     * @param {object} options - object that will override defaults
     *
     */
    StickyDrawer.prototype.setupVars = function setupVars(options) {
        this.options = _.merge(this.defaults, drupalSettings.meltStickyDrawer, options);
        this.target = this.options.target;
        this.targetWrapper = this.options.targetWrapper;
        this.toggle = this.options.toggle;
        this.toggleAction = this.options.toggleAction;
        this.toggleEl = document.querySelector(this.toggle);
        this.targetEl = document.querySelector(this.target);

        // Exit if target element is not found.
        if (!this.targetEl) {
            throw new Error('StickyDrawerError: Can not find HTML element with the selector of ' + this.target)
        };

        this.isFixed = this.targetEl.classList.contains(this.options.fixedClass);
        this.targetElHeight = this.targetEl.getBoundingClientRect().height;
        this.targetWrapperEl = document.querySelector(this.targetWrapper);
        this.windowHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
        var fixedHeights = this.getFixedHeights();
        this.targetFixedHeight = fixedHeights.target;
        this.wrapperFixedHeight = fixedHeights.wrapper;

        if (!this.isFixed) {
            this.setTargetWrapperHeight();
        }

        this.triggerHeight = (this.targetWrapperEl.offsetTop - this.windowHeight) + this.targetFixedHeight;

    }


    StickyDrawer.prototype.setupEvents = function setupEvents() {
        var stickyDrawer = this;
        var fixedClass = this.options.fixedClass;

        // Handle scroll
        $(window).scroll(_.throttle(function () {
            stickyDrawer.init();
        }, 100));

        // Handle window resize
        $(window).resize(_.debounce(function () {
            stickyDrawer.options.isResizing = true;
            stickyDrawer.init();
            stickyDrawer.options.isResizing = false;
        }, 200));

        // Handle click
        $(document).on('click', this.toggle, function (event) {
            event.preventDefault();

            // Custom `stickydrawer:toggle` event that allows developers to
            // manipulate the stickyDrawer before we scroll.
            $(event.currentTarget).trigger('stickydrawer:toggle', [stickyDrawer]);

            // Add 'is-expanded' class if user selected "expand" action
            if(stickyDrawer.toggleAction === 'expand') {
                var body = document.body;

                // Prevent scrolling when expanded.
                if(stickyDrawer.isFixed && !stickyDrawer.targetEl.classList.contains('is-expanded')){
                    stickyDrawer.targetEl.classList.add('is-expanded');
                    body.style.overflow = 'hidden';
                } else {
                    stickyDrawer.targetEl.classList.remove('is-expanded');
                    body.style.overflow = '';
                }
            }

            // If the action type is not expanded, then the default will be to scroll.
            if (stickyDrawer.toggleAction !== 'expand') {
                if (stickyDrawer.isFixed) {
                    //or to scroll to the element with the ID "#someID":
                    TweenLite.to(window, .3, {
                        scrollTo: {
                            y: stickyDrawer.options.targetWrapper,
                            offsetY: stickyDrawer.options.scrollToOffset || 30,
                            autoKill: false // needed to use this for Safari mobile
                        }
                    });
                } else {
                    TweenLite.to(window, .3, {
                        scrollTo: {
                            y: 0,
                            autoKill: false // needed to use this for Safari mobile
                        }
                    })
                }
            }


        });
    }

    /**
     * Adds the unfixed height to the target's wrapper to maintain scroll positioning
     */
    StickyDrawer.prototype.setTargetWrapperHeight = function setTargetWrapperHeight() {
        this.targetWrapperEl.style.height = (this.targetElHeight + this.wrapperFixedHeight) + 'px';
    };

    /**
     * This quickly sets the target to it's fixed state so we can
     * get it's height and then sets it back to its original state
     *
     * @returns {number} height - height of target when fixed
     *
     */
    StickyDrawer.prototype.getFixedHeights = function () {
        var fixedClass = this.options.fixedClass;
        var targetHeight, targetElRect;

        // Only add class if target hasn't already been fixed
        if (!this.isFixed) {
            this.targetEl.classList.add(fixedClass);
        }

        // Get the rect after we add the fixed class so we can get the correct top value
        targetElRect = this.targetEl.getBoundingClientRect();

        if (this.toggleAction === 'expand') {
            targetHeight = Math.abs(this.windowHeight - targetElRect.y);
        } else {
            targetHeight = targetElRect.height;
        }

        var wrapperHeight = this.targetWrapperEl.getBoundingClientRect().height;

        // Only add class if target hasn't already been fixed
        if (!this.isFixed) {
            this.targetEl.classList.remove(fixedClass);
        }

        return {
            target: targetHeight,
            wrapper: wrapperHeight
        };
    };

    /**
     * Removes transition state from sticky drawer when in "expand" mode.
     */
    StickyDrawer.prototype.removeTransition = function removeTransition() {
        if (this.toggleAction === 'expand') {
            this.targetEl.style.transition = '';
            document.body.style.overflow = '';
        }
    }

    /**
     * Removes transition state from sticky drawer when in "expand" mode.
     */
     StickyDrawer.prototype.addTransition = function addTransition() {
        if (this.toggleAction === 'expand') {
            this.targetEl.style.transition = 'transform .2s'
        }
    }



    /**
     * Main function that initializes the sticky drawer
     */
    StickyDrawer.prototype.init = function init() {

        var fixedClass = this.options.fixedClass;

        // Reset variables when resizing windows
        if (this.options.isResizing) {
            this.targetWrapperEl.style = null;
            this.targetEl.classList.remove(fixedClass);
            this.targetEl.classList.remove('is-expanded');
            this.removeTransition();
            this.setupVars();
        }

        var scrollPos = window.pageYOffset || document.documentElement.scrollTop;

        var wrapperInView = scrollPos > this.triggerHeight;
        var isExpanded = this.targetEl.classList.contains('is-expanded');

        // Remove fixed class if wrapper in view of the viewport
        if (wrapperInView && this.isFixed) {
            this.targetEl.classList.remove(fixedClass);
            this.toggleEl.classList.remove(fixedClass);
            this.isFixed = false;
            this.removeTransition();
        }

        // Add the fixed class when the wrapper is out of the viewport
        if (!wrapperInView && !this.isFixed) {
            this.targetEl.classList.add(fixedClass);
            this.toggleEl.classList.add(fixedClass);
            this.isFixed = true;

            // Set the transition after setting the class, otherwise it'll animate in when
            // the fixedClass is set. We need to set it AFTER the window resize event has fired
            // which is after 250ms.
            setTimeout(function () {
                this.addTransition();
            }.bind(this), 300);
        }

        if(!wrapperInView && this.isFixed && !this.targetEl.style.transition) {
            setTimeout(function () {
                this.addTransition();
            }.bind(this), 300);
        }
    };

    // Execute code
    setTimeout(function () {
        try {
            var stickyDrawer = new StickyDrawer();
            stickyDrawer.init();
        } catch (err) {
            // Silently fail.
        }


    }, 250);

})(jQuery, _.noConflict(), window);