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