component-navigation.js

/**
 * Component Navigation
 * @module Navigation
 * @param  {jQuery} $ Instance of jQuery
 * @return {Object} List of navigation methods
 */
XA.component.navigation = (function($) {
    var timeout = 200,
        timer = 0,
        submenu,
        dropDownEvents = {
            show: function(sm) {
                this.debounce();
                submenu = sm;
                submenu.closest("li").addClass("show");
            },
            debounce: function() {
                if (timer) {
                    clearTimeout(timer);
                    timer = null;
                }
            },
            hide: function() {
                if (submenu) {
                    submenu.closest("li").removeClass("show");
                }
            },
            queueHide: function() {
                timer = setTimeout(function() {
                    dropDownEvents.hide();
                }, timeout);
            },
            focus: function() {
                $(this)
                    .closest("li")
                    .siblings()
                    .removeClass("show");
                $(this)
                    .closest("li")
                    .addClass("show");
            },
            blur: function() {
                if (
                    $(this)
                        .closest("li")
                        .is(".last")
                ) {
                    $(this)
                        .parents(".rel-level1")
                        .removeClass("show");
                }
            }
        };

    /**
     * Prepares DOM structure of Navigation component and
     * adds Event listeners of showing and hiding
     * different levels of navigation.
     * @method
     * @alias module:Navigation.dropDownNavigation
     * @memberOf module:Navigation
     * breadcrum elements wrapped by jquery
     * @param {jQuery} navi Root DOM element of
     * navigation component wrapped by jQuery
     * @private
     */
    function dropDownNavigation(navi) {
        navi.on(
            "mouseover",
            ".rel-level1 > a, .rel-level1 >.navigation-title>a, .rel-level2 >.navigation-title>a",
            function() {
                $(this)
                    .closest("li")
                    .siblings()
                    .removeClass("show");
                $(this)
                    .closest("li.rel-level1")
                    .siblings()
                    .removeClass("show");
                $(this)
                    .closest("li.rel-level1")
                    .siblings()
                    .find(".show")
                    .removeClass("show");
                var elem = $(this)
                    .closest("li")
                    .find(">ul");
                dropDownEvents.show(elem);
            }
        );
        navi.on(
            "mouseleave",
            ".rel-level1 > a, .rel-level1 >.navigation-title",
            dropDownEvents.queueHide
        );
        navi.on("mouseover", ".rel-level1 > ul", dropDownEvents.debounce);
        navi.on("mouseleave", ".rel-level1 > ul", dropDownEvents.queueHide);
        navi.on(
            "focus",
            ".rel-level1 > a, .rel-level1 >.navigation-title, .rel-level1 >.navigation-title",
            dropDownEvents.focus
        );
        navi.on("blur", ".rel-level2 > a", dropDownEvents.blur);
        navi.on("mouseleave", function() {
            $(this)
                .find(".show")
                .removeClass("show");
        });
        navi.find(".rel-level1").each(function() {
            if ($(this).find("ul").length) {
                $(this).addClass("submenu");
            }
        });

        navi.find(".rel-level2").each(function() {
            //if level2 menu has children
            if ($(this).parents("#header") > 0) {
                if ($(this).find("ul").length) {
                    $(this).addClass("submenu");
                    $(this)
                        .parents(".rel-level1")
                        .addClass("wide-nav");
                }
            }

            //if level2 menu should be navigation-image variant
            if ($(this).find("> img").length) {
                $(this).addClass("submenu navigation-image");
            }
        });

        navi.on("click", ".sxaToogleNavBtn", function() {
            var $this = jQuery(this);
            $this.find(".sxaWrappedList").toggleClass("hidden");
        });
    }
    /**
     * Prepares DOM structure of Mobile Navigation component and
     * adds Event listeners of showing and hiding
     * different levels of navigation.
     * @method
     * @alias module:Navigation.mobileNavigation
     * @memberOf module:Navigation
     * breadcrum elements wrapped by jquery
     * @param {jQuery} navi Root DOM element of
     * navigation component wrapped by jQuery
     * @private
     */
    function mobileNavigation(navi) {
        function checkChildren(nav) {
            nav.find(".rel-level1").each(function() {
                if (!$(this).find("ul").length) {
                    $(this).addClass("no-child");
                }
            });
        }

        function bindEvents(nav) {
            nav.find(".navigation-title").on("click", function(e) {
                var navlvl = $(this).closest("li"),
                    menuParent = navlvl.parents(".navigation");

                if (menuParent.hasClass("navigation-mobile")) {
                    if (!$(e.target).is("a")) {
                        if (navlvl.hasClass("active")) {
                            navlvl.find(">ul").slideToggle(function() {
                                navlvl.removeClass("active");
                            });
                        } else {
                            navlvl.find(">ul").slideToggle(function() {
                                navlvl.addClass("active");
                            });
                        }
                    }
                }
            });

            nav.find(".rel-level1").on("focus", function() {
                $(this)
                    .siblings("ul")
                    .slideDown();
                $(this)
                    .closest("li")
                    .siblings()
                    .find("ul")
                    .slideUp();
            });
        }
        checkChildren(navi);
        bindEvents(navi);
    }

    /**
     * @method
     * @alias module:Navigation.toggleIcon
     * @memberOf module:Navigation
     * @param {$} toggle
     * navigation elements wrapped by jquery
     * @private
     */
    function toggleIcon(toggle) {
        $(toggle).on("click", function() {
            $(this)
                .parents(".navigation")
                .toggleClass("active");
            $(this).toggleClass("active");
        });
    }

    /**
     * This object stores all public api methods
     * @type {Object.<Methods>}
     * @memberOf module:Navigation
     * */
    var api = {};

    /**
     * initIstance method. <br/>
     * If added <b>navigation-main</b> class
     * called [dropDownNavigation]{@link module:Navigation.dropDownNavigation},
     * [mobileNavigation]{@link module:Navigation.mobileNavigation} methods. <br/>
     * If added <b>navigation-mobile</b> class
     * called only [mobileNavigation]{@link module:Navigation.mobileNavigation},
     * @memberOf module:Navigation
     * @method
     * @param {jQuery} component Root DOM element of
     * navigation component wrapped by jQuery
     * @alias module:Navigation.initInstance
     */
    api.initInstance = function(component) {
        if (component.hasClass("navigation-main")) {
            dropDownNavigation(component);
            mobileNavigation(component);
        } else if (component.hasClass("navigation-mobile")) {
            mobileNavigation(component);
        }
    };
    /**
     * init method calls [initInstance]{@link module:Navigation.initInstance} method
     * in a loop for each navigation component on a page. <br/>
     *
     * For navigation with set <b>mobile-nav</b> class
     * calls [toggleIcon]{@link module:Navigation.toggleIcon} method
     *
     * @memberOf module:Navigation
     * @alias module:Navigation.init
     */
    api.init = function() {
        var navigation = $(".navigation:not(.initialized)");
        navigation.each(function() {
            api.initInstance($(this));
            $(this).addClass("initialized");
        });

        var toggle = $(".mobile-nav:not(.initialized)");
        toggle.each(function() {
            toggleIcon(this);
            $(this).addClass("initialized");
        });
    };

    return api;
})(jQuery, document);

XA.register("navigation", XA.component.navigation);