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 122 // Copy user set classes for menu items - these must not start with menu-item, page-item, page_item (used by default classes) 123 var cls = []; 124 if( 'undefined' != typeof current.attr('class') ) 125 { 126 cls = current.attr('class').split(/\s+/); 127 $.each( cls, function( index, value ){ 128 if( ( value.indexOf('menu-item') != 0 ) && ( value.indexOf('page-item') < 0 ) && ( value.indexOf('page_item') != 0 ) && ( value.indexOf('dropdown_ul') < 0 ) ) 129 { 130 // 'current-menu-item' is also copied !! 131 new_li.addClass( value ); 132 } 133 return true; 134 }); 135 } 136 137 if( 'undefined' != typeof current.attr('id') && '' != current.attr('id') ) 138 { 139 new_li.addClass(current.attr('id')); 140 } 141 else 142 { 143 // fallback menu has no id -> try to find page id in class 144 $.each( cls, function( index, value ){ 145 if( value.indexOf('page-item-') >= 0 ) 146 { 147 new_li.addClass(value); 148 return false;
149 } 150 }); 151 } 152 153 append_to.append(new_li); 154 155 if(subitems.length) 156 { 157 new_ul = $('<ul class="sub-menu">').appendTo(new_li); 158 159 if(cloneFirst && ( link.get(0).hash != '#' && link.attr('href') != '#' )) 160 { 161 new_li.clone(true).prependTo(new_ul); 162 } 163 164 new_li.addClass('av-width-submenu').find('>a').append('<span class="av-submenu-indicator">'); 165 166 create_list( subitems , new_ul); 167 } 168 else if(megacolumns.length) //if we got no normal sublists try megamenu columns and sublists 169 { 170 new_ul = $('<ul class="sub-menu">').appendTo(new_li); 171 172 if(cloneFirst && ( link.get(0).hash != '#' && link.attr('href') != '#' )) 173 { 174 new_li.clone(true).prependTo(new_ul); 175 } 176 177 megacolumns.each(function(iteration) 178 { 179 var megacolumn = $(this), 180 mega_current = megacolumn.find( '> .sub-menu' ), // can be 0 if only a column is used without submenus 181 mega_title = megacolumn.find( '> .mega_menu_title' ), 182 mega_title_link = mega_title.find('a').attr('href') || "#", 183 current_megas = mega_current.length > 0 ? mega_current.find('>li') : null, 184 mega_title_set = false, 185 mega_link = new_li.find('>a'), 186 hide_enty = ''; 187 188 // ignore columns that have no actual link and no subitems 189 if( ( current_megas === null ) || ( current_megas.length == 0 ) ) 190 { 191 if( mega_title_link == '#' ) 192 { 193 hide_enty = ' style="display: none;"'; 194 } 195 } 196 197 if(iteration == 0) new_li.addClass('av-width-submenu').find('>a').append('<span class="av-submenu-indicator">'); 198 199 //if we got a title split up submenu items into multiple columns 200 if(mega_title.length && mega_title.text() != "") 201 { 202 mega_title_set = true; 203 204 //if we are within the first iteration we got a new submenu, otherwise we start a new one 205 if(iteration > 0) 206 { 207 var check_li = new_li.parents('li').eq(0); 208 209 if(check_li.length) new_li = check_li; 210 211 new_ul = $('<ul class="sub-menu">').appendTo(new_li); 212 } 213 214 215 new_li = $('<li' + hide_enty + '>').appendTo(new_ul); 216 new_ul = $('<ul class="sub-menu">').appendTo(new_li); 217 218 $('<a href="'+mega_title_link+'"><span class="avia-bullet"></span><span class="avia-menu-text">' +mega_title.text()+ '</span></a>').insertBefore(new_ul); 219 mega_link = new_li.find('>a'); 220 221 // Clone if we have submenus 222 if(cloneFirst && ( mega_current.length > 0 ) && ( mega_link.length && mega_link.get(0).hash != '#' && mega_link.attr('href') != '#' )) 223 { 224 new_li.clone(true).addClass('av-cloned-title').prependTo(new_ul); 225 } 226 227 } 228 229 // do not append av-submenu-indicator if no submenus (otherwise link action is blocked !!!) 230 if( mega_title_set && ( mega_current.length > 0 ) ) 231 { 232 new_li.addClass('av-width-submenu').find('>a').append('<span class="av-submenu-indicator">'); 233 } 234 235 create_list( current_megas , new_ul); 236 }); 237 238 } 239 240 }); 241 242 burger_wrap.trigger( 'avia_burger_list_created' ); 243 return list; 244 }; 245 246 var burger_ul, burger; 247 248 //prevent scrolling of outer window when scrolling inside 249 $('body').on( 'mousewheel DOMMouseScroll touchmove', '.av-burger-overlay-scroll', function (e) 250 { 251 var height = this.offsetHeight, 252 scrollHeight = this.scrollHeight, 253 direction = e.originalEvent.wheelDelta; 254 255 if(scrollHeight != this.clientHeight) 256 { 257 if( ( this.scrollTop >= (scrollHeight - height) && direction < 0) || (this.scrollTop <= 0 && direction > 0) ) 258 { 259 e.preventDefault(); 260 } 261 } 262 else 263 { 264 e.preventDefault(); 265 } 266 }); 267 268 //prevent scrolling for the rest of the screen 269 $(document).on( 'mousewheel DOMMouseScroll touchmove', '.av-burger-overlay-bg, .av-burger-overlay-active .av-burger-menu-main', function (e) 270 { 271 e.preventDefault(); 272 }); 273 274 //prevent scrolling on mobile devices 275 var touchPos = {}; 276 277 $(document).on('touchstart', '.av-burger-overlay-scroll', function(e) 278 { 279 touchPos.Y = e.originalEvent.touches[0].clientY; 280 }); 281 282 $(document).on('touchend', '.av-burger-overlay-scroll', function(e) 283 { 284 touchPos = {}; 285 }); 286 287 //prevent rubberband scrolling http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/ 288 $(document).on( 'touchmove', '.av-burger-overlay-scroll', function (e) 289 { 290 if(!touchPos.Y) 291 { 292 touchPos.Y = e.originalEvent.touches[0].clientY; 293 } 294 295 var differenceY = e.originalEvent.touches[0].clientY - touchPos.Y, 296 element = this, 297 top = element.scrollTop, 298 totalScroll = element.scrollHeight, 299 currentScroll = top + element.offsetHeight, 300 direction = differenceY > 0 ? "up" : "down"; 301 302 $('body').get(0).scrollTop = touchPos.body; 303 304 if( top <= 0 ) 305 { 306 if( direction == "up" ) 307 { 308 e.preventDefault(); 309 } 310 311 } 312 else if( currentScroll >= totalScroll ) 313 { 314 if( direction == "down" ) 315 { 316 e.preventDefault(); 317 } 318 } 319 }); 320 321 $(window).on( 'debouncedresize', function (e) 322 { 323 var close = true; 324 325 // @since 4.8.3 we support portrait/landscape screens to switch mobile menu 326 if( $.avia_utilities.isMobile && htmlEL.hasClass( 'av-mobile-menu-switch-portrait' ) && htmlEL.hasClass( 'html_text_menu_active' ) ) 327 { 328 var height = $( window ).height(); 329 var width = $( window ).width(); 330 331 if( width <= height ) 332 { 333 // in portrait mode we only need to remove added class 334 htmlEL.removeClass( 'html_burger_menu' ); 335 } 336 else 337 { 338 // in landscape mode 339 var switch_width = htmlEL.hasClass( 'html_mobile_menu_phone' ) ? 768 : 990; 340 if( height < switch_width ) 341 { 342 htmlEL.addClass( 'html_burger_menu' ); 343 close = false;
344 } 345 else 346 { 347 htmlEL.removeClass( 'html_burger_menu' ); 348 } 349 } 350 } 351 352 353 // close burger menu when returning to desktop 354 if( close && burger && burger.length ) 355 { 356 if( ! burger_wrap.is(':visible') ) 357 { 358 burger.filter(".is-active").parents('a').eq(0).trigger('click'); 359 } 360 } 361 362 set_list_container_height(); 363 }); 364 365 //close overlay on overlay click 366 $('.html_av-overlay-side').on( 'click', '.av-burger-overlay-bg', function (e) 367 { 368 e.preventDefault(); 369 burger.parents('a').eq(0).trigger('click'); 370 }); 371 372 //close overlay when smooth scrollign begins 373 $(window).on('avia_smooth_scroll_start', function() 374 { 375 if(burger && burger.length) 376 { 377 burger.filter(".is-active").parents('a').eq(0).trigger('click'); 378 } 379 }); 380 381 382 //toogle hide/show for submenu items 383 $('.html_av-submenu-display-hover').on( 'mouseenter', '.av-width-submenu', function (e) 384 { 385 $(this).children("ul.sub-menu").slideDown('fast'); 386 }); 387 388 $('.html_av-submenu-display-hover').on( 'mouseleave', '.av-width-submenu', function (e) 389 { 390 $(this).children("ul.sub-menu").slideUp('fast'); 391 }); 392 393 $('.html_av-submenu-display-hover').on( 'click', '.av-width-submenu > a', function (e) 394 { 395 e.preventDefault(); 396 e.stopImmediatePropagation(); 397 }); 398 399 // for mobile we use same behaviour as submenu-display-click 400 $('.html_av-submenu-display-hover').on( 'touchstart', '.av-width-submenu > a', function (e) 401 { 402 var menu = $(this); 403 toggle_submenu( menu, e ); 404 }); 405 406 407 //toogle hide/show for submenu items 408 $('.html_av-submenu-display-click').on( 'click', '.av-width-submenu > a', function (e) 409 { 410 var menu = $(this); 411 toggle_submenu( menu, e ); 412 }); 413 414 415 // close mobile menu if click on active menu item 416 $('.html_av-submenu-display-click, .html_av-submenu-visible').on( 'click', '.av-burger-overlay a', function (e) 417 { 418 var loc = window.location.href.match(/(^[^#]*)/)[0]; 419 var cur = $(this).attr('href').match(/(^[^#]*)/)[0]; 420 421 if( cur == loc ) 422 { 423 e.preventDefault(); 424 e.stopImmediatePropagation(); 425 426 burger.parents('a').eq(0).trigger('click'); 427 return false; 428 } 429 430 return true; 431 }); 432 433 434 function toggle_submenu( menu, e ) 435 { 436 e.preventDefault(); 437 e.stopImmediatePropagation(); 438 439 var parent = menu.parents('li').eq(0); 440 441 parent.toggleClass('av-show-submenu'); 442 443 if(parent.is('.av-show-submenu')) 444 { 445 parent.children("ul.sub-menu").slideDown('fast'); 446 } 447 else 448 { 449 parent.children("ul.sub-menu").slideUp('fast'); 450 } 451 }; 452 453 454 (function normalize_layout() 455 { 456 //if we got the menu outside of the main menu container we need to add it to the container as well 457 if( menu_in_logo_container.length ) 458 { 459 return; 460 } 461 462 var menu2 = $('#header .main_menu').clone(true), 463 ul = menu2.find('ul.av-main-nav'), 464 id = ul.attr('id'); 465 466 if( 'string' == typeof id && '' != id.trim() ) 467 { 468 ul.attr('id', id + '-' + cloned_menu_cnt++ ); 469 } 470 menu2.find('.menu-item:not(.menu-item-avia-special)').remove(); 471 menu2.insertAfter(logo_container.find('.logo').first()); 472 473 //check if we got social icons and append it to the secondary menu 474 var social = $('#header .social_bookmarks').clone(true); 475 if( ! social.length ) 476 { 477 social = $('.av-logo-container .social_bookmarks').clone(true); 478 } 479 480 if( social.length ) 481 { 482 menu2.find('.avia-menu').addClass('av_menu_icon_beside'); 483 menu2.append(social); 484 } 485 486 //re select the burger menu if we added a new one 487 burger_wrap = $('.av-burger-menu-main a'); 488 }()); 489 490 491 492 burger_wrap.on('click', function(e) 493 { 494 if( animating ) 495 { 496 return; 497 } 498 499 burger = $(this).find('.av-hamburger'), 500 animating = true; 501 502 if(!menu_generated) 503 { 504 menu_generated = true; 505 burger.addClass("av-inserted-main-menu"); 506 507 burger_ul = $('<ul>').attr({id:'av-burger-menu-ul', class:''}); 508 var first_level_items = menu.find('> li:not(.menu-item-avia-special)'); //select all first level items that are not special items 509 var list = create_list( first_level_items , burger_ul); 510 511 burger_ul.find('.noMobile').remove(); //remove any menu items with the class noMobile so user can filter manually if he wants 512 burger_ul.appendTo(inner_overlay);
513 first_level = inner_overlay.find('#av-burger-menu-ul > li'); 514 515 if($.fn.avia_smoothscroll) 516 { 517 $('a[href*="#"]', overlay).avia_smoothscroll(overlay); 518 } 519 } 520 521 if(burger.is(".is-active")) 522 { 523 burger.removeClass("is-active"); 524 htmlEL.removeClass("av-burger-overlay-active-delayed"); 525 526 overlay.animate({opacity:0}, function() 527 { 528 overlay.css({display:'none'}); 529 htmlEL.removeClass("av-burger-overlay-active"); 530 animating = false; 531 }); 532 533 } 534 else 535 { 536 set_list_container_height(); 537 538 var offsetTop = header_main.length ? header_main.outerHeight() + header_main.position().top : header.outerHeight() + header.position().top; 539 540 overlay.appendTo($(e.target).parents('.avia-menu')); 541 542 burger_ul.css({padding:( offsetTop ) + "px 0px"}); 543 544 first_level.removeClass('av-active-burger-items'); 545 546 burger.addClass("is-active"); 547 htmlEL.addClass("av-burger-overlay-active"); 548 overlay.css({display:'block'}).animate({opacity:1}, function() 549 { 550 animating = false; 551 }); 552 553 setTimeout(function() 554 { 555 htmlEL.addClass("av-burger-overlay-active-delayed"); 556 }, 100); 557 558 first_level.each(function(i) 559 { 560 var _self = $(this); 561 setTimeout(function() 562 { 563 _self.addClass('av-active-burger-items'); 564 }, (i + 1) * 125); 565 }); 566 567 } 568 569 e.preventDefault(); 570 }); 571 } 572 573})( 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.