menu.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. (function($, v, undefined) {
  2. "use strict";
  3. vamtam_greensock_wait( function() {
  4. var mainHeader = $('header.main-header');
  5. var main = $( '#main' );
  6. var body = $( 'body' );
  7. var header_contents = mainHeader.find( '.header-contents' );
  8. var menu_toggle = document.getElementById( 'vamtam-megamenu-main-menu-toggle' );
  9. var original_toggle = document.querySelector( '#main-menu > .mega-menu-wrap > .mega-menu-toggle' );
  10. // main menu custom toggle
  11. if ( menu_toggle ) {
  12. menu_toggle.addEventListener( 'click', function( e ) {
  13. e.preventDefault();
  14. requestAnimationFrame( function() {
  15. var is_open = original_toggle.classList.contains( 'mega-menu-open' );
  16. menu_toggle.classList.toggle( 'mega-menu-open', ! is_open );
  17. original_toggle.classList.toggle( 'mega-menu-open', ! is_open );
  18. } );
  19. } );
  20. }
  21. // overlay menu
  22. var overlay_menu = document.getElementById( 'vamtam-overlay-menu' );
  23. var overlay_menu_toggle = document.querySelector( '.vamtam-overlay-menu-toggle' );
  24. var overlay_open = false;
  25. var toggle_clone;
  26. var toggle_overlay_menu = function( e ) {
  27. e.preventDefault();
  28. requestAnimationFrame( function() {
  29. overlay_open = ! overlay_open;
  30. if ( overlay_open ) {
  31. toggle_clone = overlay_menu_toggle.cloneNode( true );
  32. // measure
  33. var offset = overlay_menu_toggle.getBoundingClientRect();
  34. // mutate
  35. document.body.appendChild( toggle_clone );
  36. Object.assign( toggle_clone.style, {
  37. position: 'fixed',
  38. top: offset.top + 'px',
  39. left: offset.left + 'px',
  40. } );
  41. requestAnimationFrame( function() {
  42. overlay_menu.classList.add( 'open' );
  43. toggle_clone.classList.add( 'is-active' );
  44. } );
  45. } else {
  46. toggle_clone.classList.remove( 'is-active' );
  47. overlay_menu.classList.remove( 'open' );
  48. setTimeout( function() {
  49. requestAnimationFrame( function() {
  50. toggle_clone.remove();
  51. } );
  52. }, 650 );
  53. }
  54. } );
  55. };
  56. document.body.addEventListener( 'click', function( e ) {
  57. var button = e.target.closest( 'button' );
  58. if ( button && button.classList.contains( 'vamtam-overlay-menu-toggle' ) ) {
  59. toggle_overlay_menu( e );
  60. }
  61. } );
  62. // add left/right classes to submenus depending on resolution
  63. var allSubMenus = $( '#main-menu .sub-menu, #top-nav-wrapper .sub-menu' );
  64. window.addEventListener( 'resize', window.VAMTAM.debounce( function() {
  65. var winWidth = window.innerWidth;
  66. allSubMenus.show().removeClass( 'invert-position' ).each( function() {
  67. if ( $( this ).offset().left + $( this ).width() > winWidth ) {
  68. $( this ).addClass( 'invert-position' );
  69. }
  70. } );
  71. allSubMenus.css( 'display', '' );
  72. }, 100 ), false );
  73. // scrolling below
  74. var smoothScrollTimer, smoothScrollCallback;
  75. var smoothScrollListener = function() {
  76. clearTimeout( smoothScrollTimer );
  77. smoothScrollTimer = setTimeout( scrollToElComplete, 200 );
  78. };
  79. var scrollToElComplete = function() {
  80. window.removeEventListener( 'scroll', smoothScrollListener, { passive: true } );
  81. v.blockStickyHeaderAnimation = false;
  82. setTimeout( function() {
  83. requestAnimationFrame( function() {
  84. document.body.classList.remove( 'no-sticky-header-animation-tmp' );
  85. } );
  86. }, 50 );
  87. if ( smoothScrollCallback ) {
  88. smoothScrollCallback();
  89. }
  90. };
  91. var scrollToEl = function( el, duration, callback ) {
  92. requestAnimationFrame( function() {
  93. var el_offset = el.offset().top;
  94. v.blockStickyHeaderAnimation = true;
  95. // measure header height
  96. var header_height = 0;
  97. if ( mainHeader.hasClass( 'layout-standard' ) || mainHeader.hasClass( 'logo-text-menu' ) ) {
  98. if ( el_offset >= main.offset().top ) {
  99. header_height = mainHeader.find( '.second-row-columns' ).height();
  100. } else {
  101. header_height = mainHeader.height();
  102. }
  103. } else {
  104. if ( body.hasClass( 'no-sticky-header-animation' ) ) {
  105. // single line header with a special page template
  106. header_height = mainHeader.height();
  107. } else {
  108. header_height = header_contents.height();
  109. if ( 'stickyHeader' in v ) {
  110. v.stickyHeader.singleRowStick();
  111. }
  112. // in this case stick the header,
  113. // we'd like the menu to be visible after scrolling
  114. document.body.classList.add( 'no-sticky-header-animation-tmp' );
  115. }
  116. }
  117. var scroll_position = el_offset - v.admin_bar_fix - header_height;
  118. smoothScrollCallback = callback;
  119. window.addEventListener( 'scroll', smoothScrollListener, { passive: true } );
  120. window.scroll( { left: 0, top: scroll_position, behavior: 'smooth' } );
  121. if ( el.attr( 'id' ) ) {
  122. if ( history.pushState ) {
  123. history.pushState( null, null, '#' + el.attr( 'id' ) );
  124. } else {
  125. window.location.hash = el.attr( 'id' );
  126. }
  127. }
  128. menu_toggle && menu_toggle.classList.remove( 'mega-menu-open' );
  129. original_toggle && original_toggle.classList.remove( 'mega-menu-open' );
  130. } );
  131. };
  132. window.FLBuilderLayout && Object.assign( window.FLBuilderLayout, {
  133. /**
  134. * Monkey patches the built-in animated scroll with a better implementation
  135. * which does not use jQuery
  136. */
  137. _scrollToElement: function( el, callback ) {
  138. var config = window.FLBuilderLayoutConfig.anchorLinkAnimations;
  139. if ( el.length ) {
  140. menu_toggle.classList.toggle( 'mega-menu-open', false );
  141. original_toggle.classList.toggle( 'mega-menu-open', false );
  142. scrollToEl( el, config.duration / 1000, callback );
  143. }
  144. },
  145. } );
  146. $( document.body ).on('click', '.vamtam-animated-page-scroll[href], .vamtam-animated-page-scroll [href], .vamtam-animated-page-scroll [data-href], .mega-vamtam-animated-page-scroll[href], .mega-vamtam-animated-page-scroll [href], .mega-vamtam-animated-page-scroll [data-href]', function(e) {
  147. var href = $( this ).prop( 'href' ) || $( this ).data( 'href' );
  148. var el = $( '#' + ( href ).split( "#" )[1] );
  149. var l = document.createElement('a');
  150. l.href = href;
  151. if(el.length && l.pathname === window.location.pathname) {
  152. menu_toggle.classList.toggle( 'mega-menu-open', false );
  153. original_toggle.classList.toggle( 'mega-menu-open', false );
  154. scrollToEl( el );
  155. e.preventDefault();
  156. }
  157. });
  158. if ( window.location.hash !== "" &&
  159. (
  160. $( '.vamtam-animated-page-scroll[href*="' + window.location.hash + '"]' ).length ||
  161. $( '.vamtam-animated-page-scroll [href*="' + window.location.hash + '"]').length ||
  162. $( '.vamtam-animated-page-scroll [data-href*="'+window.location.hash+'"]' ).length ||
  163. $( '.mega-vamtam-animated-page-scroll[href*="' + window.location.hash + '"]' ).length ||
  164. $( '.mega-vamtam-animated-page-scroll [href*="' + window.location.hash + '"]').length ||
  165. $( '.mega-vamtam-animated-page-scroll [data-href*="'+window.location.hash+'"]' ).length
  166. )
  167. ) {
  168. var el = $( window.location.hash );
  169. if ( el.length > 0 ) {
  170. $( window ).add( 'html, body, #page' ).scrollTop( 0 );
  171. }
  172. setTimeout( function() {
  173. scrollToEl( el );
  174. }, 400 );
  175. }
  176. // adds .current-menu-item classes
  177. var hashes = [
  178. // ['top', $('<div></div>'), $('#top')]
  179. ];
  180. $('#main-menu').find('.mega-menu, .menu').find('.maybe-current-menu-item, .mega-current-menu-item, .current-menu-item').each(function() {
  181. var link = $('> a', this);
  182. if(link.prop('href').indexOf('#') > -1) {
  183. var link_hash = link.prop('href').split('#')[1];
  184. if('#'+link_hash !== window.location.hash) {
  185. $(this).removeClass('mega-current-menu-item current-menu-item');
  186. }
  187. hashes.push([link_hash, $(this), $('#'+link_hash)]);
  188. }
  189. });
  190. if ( hashes.length ) {
  191. var winHeight = 0;
  192. var documentHeight = 0;
  193. var prev_upmost_data = null;
  194. v.addScrollHandler( {
  195. init: function() {},
  196. add_current_menu_item: function( hash ) {
  197. // there may be more than one links with the same hash,
  198. // so we need to loop over all of the hashes
  199. for ( var i = 0; i < hashes.length; i++ ) {
  200. if ( hashes[i][0] === hash ) {
  201. hashes[i][1][0].classList.add( 'mega-current-menu-item', 'current-menu-item' );
  202. }
  203. }
  204. },
  205. measure: function( cpos ) {
  206. winHeight = window.innerHeight;
  207. documentHeight = document.body.offsetHeight;
  208. this.upmost = Infinity;
  209. this.upmost_data = null;
  210. for ( var i = 0; i < hashes.length; i++ ) {
  211. var el = hashes[i][2];
  212. if ( el.length ) {
  213. var top = el.offset().top + 10;
  214. if (
  215. top > cpos &&
  216. top < this.upmost &&
  217. (
  218. top < cpos + winHeight / 2 ||
  219. ( top < cpos + winHeight && cpos + winHeight === documentHeight )
  220. )
  221. ) {
  222. this.upmost_data = hashes[i];
  223. this.upmost = top;
  224. }
  225. }
  226. }
  227. },
  228. mutate: function( cpos ) {
  229. for ( var i = 0; i < hashes.length; i++ ) {
  230. if ( hashes[i][2].length ) {
  231. hashes[i][1][0].classList.remove( 'mega-current-menu-item', 'current-menu-item' );
  232. hashes[i][1][0].childNodes[0].blur();
  233. }
  234. }
  235. if ( this.upmost_data ) {
  236. this.add_current_menu_item( this.upmost_data[0] );
  237. // attempt to push a state to the history if the current hash is different from the previous one
  238. if ( 'history' in window && ( prev_upmost_data !== null ? prev_upmost_data[0] : '' ) !== this.upmost_data[0] ) {
  239. window.history.pushState(
  240. this.upmost_data[0],
  241. $( '> a', this.upmost_data[1] ).text(),
  242. ( cpos !== 0 ? '#' + this.upmost_data[0] : location.href.replace( location.hash, '' ) )
  243. );
  244. prev_upmost_data = $.extend({}, this.upmost_data);
  245. }
  246. } else if ( this.upmost_data === null && prev_upmost_data !== null ) {
  247. this.add_current_menu_item( prev_upmost_data[0] );
  248. }
  249. }
  250. } );
  251. }
  252. });
  253. })( jQuery, window.VAMTAM );