/** * This file contain the scrips for menu frontend. * @author ExpressTech System * * @since 4.0.0 */ jQuery( document ).ready( function( jQuery ) { /** * RmpMenu Class * This RMP class is handling the frontend events and action on menu elements. * @since 4.0.0 * @access public * * @class RmpMenu */ class RmpMenu { /** * This is constructor function which is initialize the elements and options. * @access public * @since 4.0.0 * @param {Array} options List of options. */ constructor( options ) { RmpMenu.activeToggleClass = 'is-active'; RmpMenu.openContainerClass = 'rmp-menu-open'; RmpMenu.activeSubMenuArrowClass = 'rmp-menu-subarrow-active'; RmpMenu.subMenuClass = '.rmp-submenu'; RmpMenu.activeTopMenuClass = 'rmp-topmenu-active'; this.options = options; this.menuId = this.options['menu_id']; this.trigger = '#rmp_menu_trigger-' + this.menuId; this.isOpen = false; this.container = '#rmp-container-' + this.menuId; this.headerBar = '#rmp-header-bar-' + this.menuId; this.menuWrap = 'ul#rmp-menu-'+ this.menuId; this.subMenuArrow = '.rmp-menu-subarrow'; this.wrapper = '.rmp-container'; this.linkElement = '.rmp-menu-item-link'; this.pageWrapper = this.options['page_wrapper']; this.use_desktop_menu = this.options['use_desktop_menu']; this.originalHeight = '', this.animationSpeed = this.options['animation_speed'] * 1000; this.hamburgerBreakpoint = this.options['tablet_breakpoint']; this.subMenuTransitionTime = this.options['sub_menu_speed'] * 1000; if ( this.options['button_click_trigger'].length > 0 ) { this.trigger = this.trigger +' , '+ this.options['button_click_trigger']; } //Append hamburger icon inside an element if ( this.options['button_position_type'] == 'inside-element' ) { var destination = jQuery(this.trigger).attr('data-destination'); jQuery(this.trigger).appendTo(jQuery(destination).parent()); } this.init(); } /** * This function register the events and initiate the menu settings. */ init() { const self = this; /** * Register click event of trigger. * @fires click */ jQuery( this.trigger ).on( 'click', function( e ) { e.stopPropagation(); self.triggerMenu(); } ); // Show/Hide sub menu item when click on item toggle. jQuery( self.menuWrap ).find( self.subMenuArrow ).on( 'click', function( e ) { e.preventDefault(); e.stopPropagation(); self.triggerSubArrow( this ); }); if ( 'on' == self.options['menu_close_on_body_click'] ) { jQuery( document ).on( 'click', 'body', function ( e ) { if ( jQuery( window ).width() < self.hamburgerBreakpoint ) { if ( self.isOpen ) { if ( jQuery( e.target ).closest( self.container ).length || jQuery( e.target ).closest( self.target ).length ) { return; } } self.closeMenu(); } }); } /** * Close the menu when click on menu item link before load. */ if ( self.options['menu_close_on_link_click'] == 'on') { jQuery( this.menuWrap +' '+ self.linkElement ).on( 'click', function(e) { if( jQuery(window).width() < self.hamburgerBreakpoint ) { e.preventDefault(); // When close menu on parent clicks is on. if ( self.options['menu_item_click_to_trigger_submenu'] == 'on' ) { if( jQuery(this).is( '.rmp-menu-item-has-children > ' + self.linkElement ) ) { return; } } let _href = jQuery(this).attr('href'); let _target = ( typeof jQuery(this).attr('target') ) == 'undefined' ? '_self' : jQuery(this).attr('target'); if( self.isOpen ) { if( jQuery(e.target).closest(this.subMenuArrow).length) { return; } if( typeof _href != 'undefined' ) { self.closeMenu(); setTimeout(function() { window.open( _href, _target); }, self.animationSpeed); } } } }); } // Expand Sub items on Parent Item Click. if ( 'on' == self.options['menu_item_click_to_trigger_submenu'] ) { jQuery( this.menuWrap +' .rmp-menu-item-has-children > ' + self.linkElement ).on( 'click', function(e) { if ( jQuery(window).width() < self.hamburgerBreakpoint ) { e.preventDefault(); self.triggerSubArrow( jQuery(this).children( '.rmp-menu-subarrow' ).first() ); } }); } jQuery(document).on('keydown', function (event) { let menuOpen = jQuery('.rmp-container.rmp-menu-open'); if (menuOpen.length) { let activeMenu = menuOpen.find('.rmp-selected-menu-item').length ? menuOpen.find('.rmp-selected-menu-item') : menuOpen.find('.rmp-menu-current-item'); let parentContainer = jQuery('.rmp-container.rmp-menu-open'); let menuItems = menuOpen.find('.rmp-menu-item'); if (event.keyCode === 9) { menuItems.removeClass('rmp-selected-menu-item'); if (activeMenu.length) { if (activeMenu.hasClass('rmp-menu-item-has-children')) { activeMenu.children('.rmp-menu-item-link').first().find('.rmp-menu-subarrow').click(); let firstChild = activeMenu.find('.rmp-submenu').children('.rmp-menu-item').first(); firstChild.addClass('rmp-selected-menu-item').children('.rmp-menu-item-link').first().focus(); } else { let nextMenu = activeMenu.next('.rmp-menu-item'); if (nextMenu.length) { nextMenu.addClass('rmp-selected-menu-item').children('.rmp-menu-item-link').first().focus(); } else { let parentSubmenu = activeMenu.closest('.rmp-submenu'); if (parentSubmenu.length) { let parentMenu = parentSubmenu.closest('.rmp-menu-item'); let nextSibling = parentMenu.next('.rmp-menu-item'); parentMenu.children('.rmp-menu-item-link').first().find('.rmp-menu-subarrow').click(); if (nextSibling.length) { nextSibling.addClass('rmp-selected-menu-item').children('.rmp-menu-item-link').first().focus(); } else { let parentSibling = parentMenu.closest('.rmp-submenu').closest('.rmp-menu-item').next('.rmp-menu-item'); if (parentSibling.length) { parentSibling.find('.rmp-menu-item-link').addClass('rmp-selected-menu-item').children('.rmp-menu-item-link').first().focus(); } else { parentContainer.find('.rmp-menu-item').first().addClass('rmp-selected-menu-item').children('.rmp-menu-item-link').first().focus(); } } } else { parentContainer.find('.rmp-menu-item').first().addClass('rmp-selected-menu-item').children('.rmp-menu-item-link').first().focus(); } } } } else { menuItems.first().addClass('rmp-selected-menu-item').children('.rmp-menu-item-link').first().focus(); } event.preventDefault(); } if (event.keyCode === 13 && activeMenu.length) { activeMenu.click(); } } }); // Add rmp-topmenu-active class to current menu item on load this.setActiveMenuItemOnLoad(); } // Add rmp-topmenu-active class to current menu item on load setActiveMenuItemOnLoad() { const currentURL = window.location.href; const menuItems = jQuery(this.menuWrap).find('a'); menuItems.each(function() { if (this.href === currentURL) { jQuery(this).closest('.rmp-menu-item-has-children').addClass(RmpMenu.activeTopMenuClass); return false; // Exit the loop once we've found and marked the current item } }); } /** * Set push translate for toggle and page wrapper. */ setWrapperTranslate() { let translate,translateContainer; switch( this.options['menu_appear_from'] ) { case 'left': translate = 'translateX(' + this.menuWidth() + 'px)'; translateContainer = 'translateX(-' + this.menuWidth() + 'px)'; break; case 'right': translate = 'translateX(-' + this.menuWidth() + 'px)'; translateContainer = 'translateX(' + this.menuWidth() + 'px)'; break; case 'top': translate = 'translateY(' + this.wrapperHeight() + 'px)'; translateContainer = 'translateY(-' + this.menuHeight() + 'px)'; break; case 'bottom': translate = 'translateY(-' + this.menuHeight() + 'px)'; translateContainer = 'translateY(' + this.menuHeight() + 'px)'; break; } if ( this.options['animation_type'] == 'push' ) { jQuery(this.pageWrapper).css( { 'transform':translate } ); //If push Wrapper has body element then handle menu position. if ( 'body' == this.pageWrapper ) { jQuery( this.container ).css( { 'transform' : translateContainer } ); } } if ( this.options['button_push_with_animation'] == 'on' ) { jQuery( this.trigger ).css( { 'transform' : translate } ); } } /** * Clear push translate on button and page wrapper. */ clearWrapperTranslate() { if ( this.options['animation_type'] == 'push' ) { jQuery(this.pageWrapper).css( { 'transform' : '' } ); } if ( this.options['button_push_with_animation'] == 'on' ) { jQuery( this.trigger ).css( { 'transform' : '' } ); } } /** * Function to fadeIn the hamburger menu container. */ fadeMenuIn() { jQuery(this.container).fadeIn(this.animationSpeed); } /** * Function to fadeOut the hamburger menu container. */ fadeMenuOut() { jQuery(this.container) .fadeOut(this.animationSpeed, function() { jQuery(this).css('display', ''); }); } /** * Function is use to open the hamburger menu. * * @since 4.0.0 */ openMenu() { var self = this; jQuery(this.trigger).addClass(RmpMenu.activeToggleClass); jQuery(this.container).addClass(RmpMenu.openContainerClass); //this.pushMenuTrigger(); if ( this.options['animation_type'] == 'fade'){ this.fadeMenuIn(); } else { this.setWrapperTranslate(); } this.isOpen = true; } /** * Function is use to close the hamburger menu. * * @since 4.0.0 */ closeMenu() { jQuery(this.trigger).removeClass(RmpMenu.activeToggleClass); jQuery(this.container).removeClass(RmpMenu.openContainerClass); if ( this.options['animation_type'] == 'fade') { this.fadeMenuOut(); } else { this.clearWrapperTranslate(); } this.isOpen = false; } /** * Function is responsible for checking the menu is open or close. * * @since 4.0.0 * @param {Event} e */ triggerMenu() { this.isOpen ? this.closeMenu() : this.openMenu(); } triggerSubArrow( subArrow ) { var self = this; var sub_menu = jQuery( subArrow ).parent().siblings( RmpMenu.subMenuClass ); //Accordion animation. if ( self.options['accordion_animation'] == 'on' ) { // Get Top Most Parent and the siblings. var top_siblings = sub_menu.parents('.rmp-menu-item-has-children').last().siblings('.rmp-menu-item-has-children'); var first_siblings = sub_menu.parents('.rmp-menu-item-has-children').first().siblings('.rmp-menu-item-has-children'); // Close up just the top level parents to key the rest as it was. top_siblings.children('.rmp-submenu').slideUp(self.subMenuTransitionTime, 'linear').removeClass('rmp-submenu-open'); // Set each parent arrow to inactive. top_siblings.each(function() { jQuery(this).find(self.subMenuArrow).first().html(self.options['inactive_toggle_contents']); jQuery(this).find(self.subMenuArrow).first().removeClass(RmpMenu.activeSubMenuArrowClass); }); // Now Repeat for the current item siblings. first_siblings.children('.rmp-submenu').slideUp(self.subMenuTransitionTime, 'linear').removeClass('rmp-submenu-open'); first_siblings.each(function() { jQuery(this).find(self.subMenuArrow).first().html(self.options['inactive_toggle_contents']); jQuery(this).find(self.subMenuArrow).first().removeClass(RmpMenu.activeSubMenuArrowClass); }); } // Active sub menu as default behavior. if( sub_menu.hasClass('rmp-submenu-open') ) { sub_menu.slideUp(self.subMenuTransitionTime, 'linear',function() { jQuery(this).css( 'display', '' ); } ).removeClass('rmp-submenu-open'); jQuery( subArrow ).html( self.options['inactive_toggle_contents'] ); jQuery( subArrow ).removeClass(RmpMenu.activeSubMenuArrowClass); } else { sub_menu.slideDown(self.subMenuTransitionTime, 'linear').addClass( 'rmp-submenu-open' ); jQuery( subArrow ).html(self.options['active_toggle_contents'] ); jQuery( subArrow ).addClass(RmpMenu.activeSubMenuArrowClass); } } /** * Function to add tranform style on trigger. * * @version 4.0.0 * * @param {Event} e Event object. */ pushMenuTrigger( e ) { if ( 'on' == this.options['button_push_with_animation'] ) { jQuery( this.trigger ).css( { 'transform' : this.menuWidth() } ); } } /** * Returns the height of container. * * @version 4.0.0 * * @return Number */ menuHeight() { return jQuery( this.container ).height(); } /** * Returns the width of the container. * * @version 4.0.0 * * @return Number */ menuWidth() { return jQuery( this.container ).width(); } wrapperHeight() { return jQuery( this.wrapper ).height(); } backUpSlide( backButton ) { let translateTo = parseInt( jQuery( this.menuWrap )[0].style.transform.replace( /^\D+/g, '' ) ) - 100; jQuery( this.menuWrap ).css( { 'transform': 'translateX(-' + translateTo + '%)' } ); let previousSubmenuHeight = jQuery( backButton ).parent( 'ul' ).parent( 'li' ).parent( '.rmp-submenu' ).height(); if ( ! previousSubmenuHeight ) { jQuery( this.menuWrap ).css( { 'height': this.originalHeight } ); } else { jQuery( this.menuWrap + this.menuId ).css( { 'height': previousSubmenuHeight + 'px' } ); } } } /** * Create multiple instance of menu and pass the options. * * @version 4.0.0 */ for ( let index = 0; index < rmp_menu.menu.length; index++ ) { let rmp = new RmpMenu( rmp_menu.menu[index] ); } } );