1/* 2 * Implements the hamburger menu behaviour 3 * 4 * 5 * @since 4.8 moved from avia.js to own file as some user request to customize this feature 6 */ 7(function($) 8{ 9 "use strict"; 10 11 $(function() 12 { 13 $.avia_utilities = $.avia_utilities || {}; 14 15 if( 'undefined' == typeof $.avia_utilities.isMobile ) 16 { 17 if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) && 'ontouchstart' in document.documentElement ) 18 { 19 $.avia_utilities.isMobile = true; 20 } 21 else 22 { 23 $.avia_utilities.isMobile = false; 24 } 25 } 26 27 //activates the hamburger mobile menu 28 avia_hamburger_menu(); 29 30 $(window).trigger( 'resize' ); 31 32 }); 33 34 $.avia_utilities = $.avia_utilities || {}; 35 36 function avia_hamburger_menu() 37 { 38 var header = $('#header'), 39 header_main = $('#main .av-logo-container'), //check if we got a top menu that is above the header 40 menu = $('#avia-menu'), 41 burger_wrap = $('.av-burger-menu-main a'), 42 htmlEL = $('html').eq(0), 43 overlay = $('<div class="av-burger-overlay"></div>'), 44 overlay_scroll = $('<div class="av-burger-overlay-scroll"></div>').appendTo(overlay), 45 inner_overlay = $('<div class="av-burger-overlay-inner"></div>').appendTo(overlay_scroll), 46 bgColor = $('<div class="av-burger-overlay-bg"></div>').appendTo(overlay), 47 animating = false, 48 first_level = {}, 49 logo_container = $('.av-logo-container .inner-container'), 50 menu_in_logo_container = logo_container.find('.main_menu'), 51 cloneFirst = htmlEL.is('.html_av-submenu-display-click.html_av-submenu-clone, .html_av-submenu-display-hover.html_av-submenu-clone'), 52 menu_generated = false, 53 cloned_menu_cnt = 0; 54 55 if( ! htmlEL.hasClass( 'html_av-submenu-hidden' ) ) 56 { 57 htmlEL.addClass( 'html_av-submenu-visible' ); 58 } 59 60 /** 61 * Check for alternate mobile menu 62 */ 63 var alternate = $('#avia_alternate_menu'); 64 if( alternate.length > 0 ) 65 { 66 menu = alternate; 67 } 68 69 var set_list_container_height = function() 70 { 71 //necessary for ios since the height is usually not 100% but 100% - menu bar which can be requested by window.innerHeight 72 if($.avia_utilities.isMobile) 73 { 74 overlay_scroll.outerHeight(window.innerHeight); 75 } 76 }, 77 create_list = function( items , append_to ) 78 { 79 if( ! items ) 80 { 81 return; 82 } 83 84 var list, link, current, subitems, megacolumns, sub_current, sub_current_list, new_li, new_ul; 85 86 items.each(function() 87 { 88 current = $(this); 89 subitems = current.find(' > .sub-menu > li'); //find sublists of a regular defined menu 90 if( subitems.length == 0 ) 91 { 92 subitems = current.find(' > .children > li'); //find sublists of a fallback menu 93 } 94 megacolumns = current.find( '.avia_mega_div > .sub-menu > li.menu-item' ); 95 96 // href = '#': we have a custom link that should not link to something - is also in use by megamenu for titles 97 var cur_menu = current.find('>a'); 98 var clone_events = true; 99 100 if( cur_menu.length ) 101 { 102 if( cur_menu.get(0).hash == '#' || 'undefined' == typeof cur_menu.attr('href') || cur_menu.attr('href') == '#' ) 103 { 104 // eventhandler conflict 'click' by megamenu (returns false) - ignore all handlers 105 if( subitems.length > 0 || megacolumns.length > 0 ) 106 { 107 clone_events = false; 108 } 109 } 110 } 111 112 link = cur_menu.clone(clone_events).attr('style',''); 113 114 // megamenus can have '' as url in top menu - allow click event in burger 115 if( 'undefined' == typeof cur_menu.attr('href') ) 116 { 117 link.attr( 'href', '#' ); 118 } 119 120 new_li = $('<li>').append( link ); 121 new_li.attr( 'role', 'menuitem' ); 122 123 // Copy user set classes for menu items - these must not start with menu-item, page-item, page_item (used by default classes) 124 var cls = []; 125 if( 'undefined' != typeof current.attr('class') ) 126 { 127 cls = current.attr('class').split(/\s+/); 128 $.each( cls, function( index, value ){ 129 if( ( value.indexOf('menu-item') != 0 ) && ( value.indexOf('page-item') < 0 ) && ( value.indexOf('page_item') != 0 ) && ( value.indexOf('dropdown_ul') < 0 ) ) 130 { 131 // 'current-menu-item' is also copied !! 132 new_li.addClass( value ); 133 } 134 return true; 135 }); 136 } 137 138 if( 'undefined' != typeof current.attr('id') && '' != current.attr('id') ) 139 { 140 new_li.addClass(current.attr('id')); 141 } 142 else 143 { 144 // fallback menu has no id -> try to find page id in class 145 $.each( cls, function( index, value ){ 146 if( value.indexOf('page-item-') >= 0 ) 147 { 148 new_li.addClass(value); 149 return false;
150 } 151 }); 152 } 153 154 append_to.append(new_li); 155 156 if(subitems.length) 157 { 158 new_ul = $('<ul class="sub-menu">').appendTo(new_li); 159 160 if(cloneFirst && ( link.get(0).hash != '#' && link.attr('href') != '#' )) 161 { 162 new_li.clone(true).prependTo(new_ul); 163 } 164 165 new_li.addClass('av-width-submenu').find('>a').append('<span class="av-submenu-indicator">'); 166 167 create_list( subitems , new_ul); 168 } 169 else if(megacolumns.length) //if we got no normal sublists try megamenu columns and sublists 170 { 171 new_ul = $('<ul class="sub-menu">').appendTo(new_li); 172 173 if(cloneFirst && ( link.get(0).hash != '#' && link.attr('href') != '#' )) 174 { 175 new_li.clone(true).prependTo(new_ul); 176 } 177 178 megacolumns.each(function(iteration) 179 { 180 var megacolumn = $(this), 181 mega_current = megacolumn.find( '> .sub-menu' ), // can be 0 if only a column is used without submenus 182 mega_title = megacolumn.find( '> .mega_menu_title' ), 183 mega_title_link = mega_title.find('a').attr('href') || "#", 184 current_megas = mega_current.length > 0 ? mega_current.find('>li') : null, 185 mega_title_set = false, 186 mega_link = new_li.find('>a'), 187 hide_enty = ''; 188 189 // ignore columns that have no actual link and no subitems 190 if( ( current_megas === null ) || ( current_megas.length == 0 ) ) 191 { 192 if( mega_title_link == '#' ) 193 { 194 hide_enty = ' style="display: none;"'; 195 } 196 } 197 198 if(iteration == 0) new_li.addClass('av-width-submenu').find('>a').append('<span class="av-submenu-indicator">'); 199 200 //if we got a title split up submenu items into multiple columns 201 if(mega_title.length && mega_title.text() != "") 202 { 203 mega_title_set = true; 204 205 //if we are within the first iteration we got a new submenu, otherwise we start a new one 206 if(iteration > 0) 207 { 208 var check_li = new_li.parents('li').eq(0); 209 210 if(check_li.length) new_li = check_li; 211 212 new_ul = $('<ul class="sub-menu">').appendTo(new_li); 213 } 214 215 216 new_li = $('<li' + hide_enty + '>').appendTo(new_ul); 217 new_ul = $('<ul class="sub-menu">').appendTo(new_li); 218 219 $('<a href="'+mega_title_link+'"><span class="avia-bullet"></span><span class="avia-menu-text">' +mega_title.text()+ '</span></a>').insertBefore(new_ul); 220 mega_link = new_li.find('>a'); 221 222 // Clone if we have submenus 223 if(cloneFirst && ( mega_current.length > 0 ) && ( mega_link.length && mega_link.get(0).hash != '#' && mega_link.attr('href') != '#' )) 224 { 225 new_li.clone(true).addClass('av-cloned-title').prependTo(new_ul); 226 } 227 228 } 229 230 // do not append av-submenu-indicator if no submenus (otherwise link action is blocked !!!) 231 if( mega_title_set && ( mega_current.length > 0 ) ) 232 { 233 new_li.addClass('av-width-submenu').find('>a').append('<span class="av-submenu-indicator">'); 234 } 235 236 create_list( current_megas , new_ul); 237 }); 238 239 } 240 241 }); 242 243 burger_wrap.trigger( 'avia_burger_list_created' ); 244 return list; 245 }; 246 247 var burger_ul, burger; 248 249 //prevent scrolling of outer window when scrolling inside 250 $('body').on( 'mousewheel DOMMouseScroll touchmove', '.av-burger-overlay-scroll', function (e) 251 { 252 var height = this.offsetHeight, 253 scrollHeight = this.scrollHeight, 254 direction = e.originalEvent.wheelDelta; 255 256 if(scrollHeight != this.clientHeight) 257 { 258 if( ( this.scrollTop >= (scrollHeight - height) && direction < 0) || (this.scrollTop <= 0 && direction > 0) ) 259 { 260 e.preventDefault(); 261 } 262 } 263 else 264 { 265 e.preventDefault(); 266 } 267 }); 268 269 //prevent scrolling for the rest of the screen 270 $(document).on( 'mousewheel DOMMouseScroll touchmove', '.av-burger-overlay-bg, .av-burger-overlay-active .av-burger-menu-main', function (e) 271 { 272 e.preventDefault(); 273 }); 274 275 //prevent scrolling on mobile devices 276 var touchPos = {}; 277 278 $(document).on('touchstart', '.av-burger-overlay-scroll', function(e) 279 { 280 touchPos.Y = e.originalEvent.touches[0].clientY; 281 }); 282 283 $(document).on('touchend', '.av-burger-overlay-scroll', function(e) 284 { 285 touchPos = {}; 286 }); 287 288 //prevent rubberband scrolling http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/ 289 $(document).on( 'touchmove', '.av-burger-overlay-scroll', function (e) 290 { 291 if(!touchPos.Y) 292 { 293 touchPos.Y = e.originalEvent.touches[0].clientY; 294 } 295 296 var differenceY = e.originalEvent.touches[0].clientY - touchPos.Y, 297 element = this, 298 top = element.scrollTop, 299 totalScroll = element.scrollHeight, 300 currentScroll = top + element.offsetHeight, 301 direction = differenceY > 0 ? "up" : "down"; 302 303 $('body').get(0).scrollTop = touchPos.body; 304 305 if( top <= 0 ) 306 { 307 if( direction == "up" ) 308 { 309 e.preventDefault(); 310 } 311 312 } 313 else if( currentScroll >= totalScroll ) 314 { 315 if( direction == "down" ) 316 { 317 e.preventDefault(); 318 } 319 } 320 }); 321 322 $(window).on( 'debouncedresize', function (e) 323 { 324 var close = true; 325 326 // @since 4.8.3 we support portrait/landscape screens to switch mobile menu 327 if( $.avia_utilities.isMobile && htmlEL.hasClass( 'av-mobile-menu-switch-portrait' ) && htmlEL.hasClass( 'html_text_menu_active' ) ) 328 { 329 var height = $( window ).height(); 330 var width = $( window ).width(); 331 332 if( width <= height ) 333 { 334 // in portrait mode we only need to remove added class 335 htmlEL.removeClass( 'html_burger_menu' ); 336 } 337 else 338 { 339 // in landscape mode 340 var switch_width = htmlEL.hasClass( 'html_mobile_menu_phone' ) ? 768 : 990; 341 if( height < switch_width ) 342 { 343 htmlEL.addClass( 'html_burger_menu' ); 344 close = false;
345 } 346 else 347 { 348 htmlEL.removeClass( 'html_burger_menu' ); 349 } 350 } 351 } 352 353 354 // close burger menu when returning to desktop 355 if( close && burger && burger.length ) 356 { 357 if( ! burger_wrap.is(':visible') ) 358 { 359 burger.filter(".is-active").parents('a').eq(0).trigger('click'); 360 } 361 } 362 363 set_list_container_height(); 364 }); 365 366 //close overlay on overlay click 367 $('.html_av-overlay-side').on( 'click', '.av-burger-overlay-bg', function (e) 368 { 369 e.preventDefault(); 370 burger.parents('a').eq(0).trigger('click'); 371 }); 372 373 //close overlay when smooth scrollign begins 374 $(window).on('avia_smooth_scroll_start', function() 375 { 376 if(burger && burger.length) 377 { 378 burger.filter(".is-active").parents('a').eq(0).trigger('click'); 379 } 380 }); 381 382 383 //toogle hide/show for submenu items 384 $('.html_av-submenu-display-hover').on( 'mouseenter', '.av-width-submenu', function (e) 385 { 386 $(this).children("ul.sub-menu").slideDown('fast'); 387 }); 388 389 $('.html_av-submenu-display-hover').on( 'mouseleave', '.av-width-submenu', function (e) 390 { 391 $(this).children("ul.sub-menu").slideUp('fast'); 392 }); 393 394 $('.html_av-submenu-display-hover').on( 'click', '.av-width-submenu > a', function (e) 395 { 396 e.preventDefault(); 397 e.stopImmediatePropagation(); 398 }); 399 400 // for mobile we use same behaviour as submenu-display-click 401 $('.html_av-submenu-display-hover').on( 'touchstart', '.av-width-submenu > a', function (e) 402 { 403 var menu = $(this); 404 toggle_submenu( menu, e ); 405 }); 406 407 408 //toogle hide/show for submenu items 409 $('.html_av-submenu-display-click').on( 'click', '.av-width-submenu > a', function (e) 410 { 411 var menu = $(this); 412 toggle_submenu( menu, e ); 413 }); 414 415 416 // close mobile menu if click on active menu item 417 $('.html_av-submenu-display-click, .html_av-submenu-visible').on( 'click', '.av-burger-overlay a', function (e) 418 { 419 var loc = window.location.href.match(/(^[^#]*)/)[0]; 420 var cur = $(this).attr('href').match(/(^[^#]*)/)[0]; 421 422 if( cur == loc ) 423 { 424 e.preventDefault(); 425 e.stopImmediatePropagation(); 426 427 burger.parents('a').eq(0).trigger('click'); 428 return false; 429 } 430 431 return true; 432 }); 433 434 435 function toggle_submenu( menu, e ) 436 { 437 e.preventDefault(); 438 e.stopImmediatePropagation(); 439 440 var parent = menu.parents('li').eq(0); 441 442 parent.toggleClass('av-show-submenu'); 443 444 if(parent.is('.av-show-submenu')) 445 { 446 parent.children("ul.sub-menu").slideDown('fast'); 447 } 448 else 449 { 450 parent.children("ul.sub-menu").slideUp('fast'); 451 } 452 }; 453 454 455 (function normalize_layout() 456 { 457 //if we got the menu outside of the main menu container we need to add it to the container as well 458 if( menu_in_logo_container.length ) 459 { 460 return; 461 } 462 463 var menu2 = $('#header .main_menu').clone(true), 464 ul = menu2.find('ul.av-main-nav'), 465 id = ul.attr('id'); 466 467 if( 'string' == typeof id && '' != id.trim() ) 468 { 469 ul.attr('id', id + '-' + cloned_menu_cnt++ ); 470 } 471 menu2.find('.menu-item:not(.menu-item-avia-special)').remove(); 472 menu2.insertAfter(logo_container.find('.logo').first()); 473 474 //check if we got social icons and append it to the secondary menu 475 var social = $('#header .social_bookmarks').clone(true); 476 if( ! social.length ) 477 { 478 social = $('.av-logo-container .social_bookmarks').clone(true); 479 } 480 481 if( social.length ) 482 { 483 menu2.find('.avia-menu').addClass('av_menu_icon_beside'); 484 menu2.append(social); 485 } 486 487 //re select the burger menu if we added a new one 488 burger_wrap = $('.av-burger-menu-main a'); 489 }()); 490 491 492 493 burger_wrap.on('click', function(e) 494 { 495 if( animating ) 496 { 497 return; 498 } 499 500 burger = $(this).find('.av-hamburger'), 501 animating = true; 502 503 if(!menu_generated) 504 { 505 menu_generated = true; 506 burger.addClass("av-inserted-main-menu"); 507 508 burger_ul = $('<ul>').attr( {id:'av-burger-menu-ul', class:'', 'aria-haspopup': 'true', 'aria-controls': 'menu2'} ); 509 var first_level_items = menu.find('> li:not(.menu-item-avia-special)'); //select all first level items that are not special items 510 var list = create_list( first_level_items , burger_ul); 511 512 burger_ul.find('.noMobile').remove(); //remove any menu items with the class noMobile so user can filter manually if he wants 513 burger_ul.appendTo(inner_overlay);
514 first_level = inner_overlay.find('#av-burger-menu-ul > li'); 515 516 if($.fn.avia_smoothscroll) 517 { 518 $('a[href*="#"]', overlay).avia_smoothscroll(overlay); 519 } 520 } 521 522 if(burger.is(".is-active")) 523 { 524 burger.removeClass("is-active"); 525 htmlEL.removeClass("av-burger-overlay-active-delayed"); 526 527 overlay.animate({opacity:0}, function() 528 { 529 overlay.css({display:'none'}); 530 htmlEL.removeClass("av-burger-overlay-active"); 531 animating = false; 532 }); 533 534 } 535 else 536 { 537 set_list_container_height(); 538 539 var offsetTop = header_main.length ? header_main.outerHeight() + header_main.position().top : header.outerHeight() + header.position().top; 540 541 overlay.appendTo($(e.target).parents('.avia-menu')); 542 543 burger_ul.css({padding:( offsetTop ) + "px 0px"}); 544 545 first_level.removeClass('av-active-burger-items'); 546 547 burger.addClass("is-active"); 548 htmlEL.addClass("av-burger-overlay-active"); 549 overlay.css({display:'block'}).animate({opacity:1}, function() 550 { 551 animating = false; 552 }); 553 554 setTimeout(function() 555 { 556 htmlEL.addClass("av-burger-overlay-active-delayed"); 557 }, 100); 558 559 first_level.each(function(i) 560 { 561 var _self = $(this); 562 setTimeout(function() 563 { 564 _self.addClass('av-active-burger-items'); 565 }, (i + 1) * 125); 566 }); 567 568 } 569 570 e.preventDefault(); 571 }); 572 } 573 574})( jQuery );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.