1/* global jQuery */ 2(function ($) { 3 4 var FrontMenu = { 5 6 init: function () { 7 8 this.header_wrap = $('#header'); 9 this.menu_wrap = this.header_wrap.find('.header_nav_container'); 10 this.buttons_wrap = this.header_wrap.find('.mw_header_buttons_container'); 11 this.top_level_menu_items = this.menu_wrap.find('.menu > .menu-item'); 12 this.items_with_submenu = this.menu_wrap.find('.menu-item-has-children'); 13 this.items_with_submenu_anchors = this.items_with_submenu.children('span'); 14 this.submenus = this.top_level_menu_items.find('.sub-menu'); 15 this.mobile_nav_button = $('#mobile_nav'); 16 this.mobile_nav_close_button = $('#mobile_nav_close'); 17 18 this.tolerance_margin = 10; 19 this.placeholders_added = false; 20 this.is_mobile_menu = false; 21 this.is_full_width_menu = this.header_wrap.hasClass('header_in_s2'); 22 23 this.bindEvents(); 24 25 }, 26 27 bindEvents: function () { 28 29 this.checkForMobileMenu(); //DOM ready 30 $(window).load($.proxy(this.checkForMobileMenu, this)); 31 $(window).on('resize', $.proxy(this.checkForMobileMenu, this)); 32 33 }, 34 35 checkForMobileMenu: function () { 36 37 if (!this.menu_wrap.hasClass('open')) { 38 39 var available_width = 0, 40 all_items_width = 0; 41 42 this.header_wrap.removeClass('is-mobile_menu'); 43 this.menu_wrap.removeClass('open'); 44 //$('body').off('wheel.mio__front_menu__noscroll mousewheel.mio__front_menu__noscroll'); 45 $('.mw_mobile_nav_close_overlay').remove(); 46 this.is_mobile_menu = false; 47 48 for (var i = 0, length = this.top_level_menu_items.length; i < length; i++) { 49 all_items_width = all_items_width + this.top_level_menu_items.eq(i).outerWidth(true); 50 } 51 52 var right_menu_width = $('.mw_header_right_menu').outerWidth(true) || 0; 53 54 all_items_width = all_items_width + right_menu_width; 55 56 available_width = this.menu_wrap.width(); 57 58 let isMobile = window.matchMedia('only screen and (max-width: 767px)').matches; 59 60 if (all_items_width && (((available_width - this.tolerance_margin) <= all_items_width) || isMobile)) { 61 this.header_wrap.addClass('is-mobile_menu'); 62 this.is_mobile_menu = true; 63 } 64 //Bind specific events 65 this.unbindDesktopEvents(); 66 this.unbindMobileEvents(); 67 68 if (this.is_mobile_menu) { 69 this.bindMobileEvents(); 70 } else { 71 this.bindDesktopEvents(); 72 } 73 } 74 75 }, 76 77 bindDesktopEvents: function () { 78 79 this.checkForOverflowedSubmenus(); 80 $(window).on('load.mio_menu__desktop__checkoverflow', $.proxy(this.checkForOverflowedSubmenus, this)); 81 $(window).on('resize.mio_menu__desktop__checkoverflow', $.proxy(this.checkForOverflowedSubmenus, this)); 82 83 //Hovers 84 var t = this; 85 this.items_with_submenu.on('mouseenter.mio_menu__desktop__hovers', function () { 86 t.showHideSubmenu($(this), 'show'); 87 }); 88 this.items_with_submenu.on('mouseleave.mio_menu__desktop__hovers', function () { 89 t.showHideSubmenu($(this), 'hide'); 90 }); 91 92 //Click on parent item 93 this.items_with_submenu_anchors.on('touchstart.mio_menu__desktop__taps', function () { 94 var el = $(this); 95 el.data('scrolling', false); 96 }); 97 this.items_with_submenu_anchors.on('touchmove.mio_menu__desktop__taps', function () { 98 var el = $(this); 99 el.data('scrolling', true); 100 }); 101 this.items_with_submenu_anchors.on('touchend.mio__front_menu__open_submenu', function (evt) { 102 var el = $(this); 103 if (el.data('scrolling') !== true) { 104 t.checkForTap(evt, el); 105 } 106 el.data('scrolling', false); 107 }); 108 109 }, 110 111 unbindDesktopEvents: function () { 112 113 $(window).off('load.mio_menu__desktop__checkoverflow'); 114 $(window).off('resize.mio_menu__desktop__checkoverflow'); 115 116 //Hovers 117 this.items_with_submenu.off('mouseenter.mio_menu__desktop__hovers'); 118 this.items_with_submenu.off('mouseleave.mio_menu__desktop__hovers'); 119 120 //Click on parent item 121 this.items_with_submenu_anchors.off('touchstart.mio_menu__desktop__taps'); 122 this.items_with_submenu_anchors.off('touchmove.mio_menu__desktop__taps'); 123 this.items_with_submenu_anchors.off('touchend.mio__front_menu__open_submenu'); 124 125 //Runtimes 126 this.items_with_submenu_anchors.off('click.mio_menu__desktop__prevent_click'); 127 $(document).off('click.mio__front_menu__close_submenu'); 128 129 130 }, 131 132 bindMobileEvents: function () { 133 134 var t = this; 135 this.items_with_submenu_anchors.on('click.mio_menu__mobile__toggle_submenu', function (evt) { 136 evt.preventDefault(); 137 t.showHideSubmenu($(this).parent(), 'toggle', true); 138 }); 139 this.mobile_nav_button.on('click.mio_menu__mobile__open_menu', function (evt) { 140 evt.preventDefault(); 141 t.openMobileMenu(); 142 }); 143 this.mobile_nav_close_button.on('click.mio_menu__mobile__close_menu', function (evt) { 144 evt.preventDefault(); 145 t.closeMobileMenu(); 146 }); 147 148 }, 149 150 unbindMobileEvents: function () { 151 152 this.items_with_submenu_anchors.off('click.mio_menu__mobile__toggle_submenu'); 153 this.mobile_nav_button.off('click.mio_menu__mobile__open_menu'); 154 this.mobile_nav_close_button.off('click.mio_menu__mobile__close_menu'); 155 156 }, 157 158 checkForOverflowedSubmenus: function () { 159 160 161 var body = $('html'); 162 body.css('overflow-x', ''); 163 164 var document_width = $(window).width(); 165 166 this.items_with_submenu.removeClass('is-submenu_on_left'); 167 168 this.submenus.show(); 169 170 var t = this; 171 this.submenus.each(function () { 172 var submenu = $(this); 173 var adjusted = false;
174 175 var is_top_level_on_s2 = (t.is_full_width_menu && submenu.parents('.sub-menu').length === 0); 176 177 if (is_top_level_on_s2) { //Only on top-level menus on s2 header style 178 submenu.css({ 179 'left': '50%', 180 'right': '', 181 'margin-left': '' 182 }); 183 } else { 184 submenu.css({ 185 'left': '', 186 'right': '' 187 }); 188 } 189 190 var submenu_right_side_offset = (submenu.offset().left + submenu.outerWidth(true)); 191 192 if (submenu_right_side_offset > document_width) { 193 adjusted = true; 194 195 var is_third_level = ($(this).parents('.sub-menu').length > 0); 196 197 if (is_third_level) { 198 $(this).parent().addClass('is-submenu_on_left'); 199 } 200 201 if (is_top_level_on_s2) { 202 submenu.css({ 203 'margin-left': (document_width - submenu_right_side_offset) 204 }); 205 } else { 206 submenu.css({ 207 'left': 'auto', 208 'right': (is_third_level) ? '100%' : '0' 209 }); 210 } 211 212 } 213 214 //Additional check for S2 menus on left side 215 if (is_top_level_on_s2 && adjusted === false) { 216 217 var submenu_left_offset = submenu.offset().left, 218 menu_left_offset = t.menu_wrap.offset().left; 219 220 221 if (submenu_left_offset < menu_left_offset) { 222 submenu.css({ 223 'margin-left': (menu_left_offset - submenu_left_offset) 224 }); 225 } 226 227 } 228 229 }); 230 231 this.submenus.hide(); 232 233 body.css('overflow-x', 'hidden'); 234 235 }, 236 237 /* 238 * @param action 'show'|'hide'|'toggle' 239 */ 240 showHideSubmenu: function (element, action, slide) { 241 slide = typeof slide === 'undefined' ? false : true; 242 243 if (action === 'toggle') { 244 action = (element.data('mio_hovering') === true) ? 'hide' : 'show'; //If submenu is open, close it and vice versa 245 } 246 247 element.data('mio_hovering', (action === 'show')); 248 249 var submenu = element.children('.sub-menu'); 250 251 element.children('span').toggleClass('opened'); 252 253 254 //submenu.velocity( 'stop' ).velocity( velocity_action, { duration: 200, complete: complete_function } ); 255 256 if (action === 'show') { 257 submenu.show(); 258 259 } else { 260 submenu.hide(); 261 } 262 263 }, 264 265 266 /* 267 * If we detect click on parent and submenu is not visible at this time - it was probably tap and we want just to show submenu 268 */ 269 checkForTap: function (evt, anchor_element) { 270 271 //Prevent clicks legacy event 272 evt.preventDefault(); 273 anchor_element.on('click.mio_menu__desktop__prevent_click', function (evt) { 274 evt.preventDefault(); 275 }); 276 277 //Add placeholder items 278 if (this.placeholders_added === false) { 279 this.addPlaceholderItems(); 280 } 281 282 //Close all other parent submenus - only on desktop menu 283 if (this.is_mobile_menu === false) { 284 this.closeAllOpenSubmenus(anchor_element.parent()); 285 } 286 287 //Open submenu 288 this.showHideSubmenu(anchor_element.parent(), 'show'); 289 290 291 //Close on tap outside menu 292 this.bindCloseSubmenuOnClickOutside(anchor_element.parent()); 293 294 }, 295 296 bindCloseSubmenuOnClickOutside: function (submenu_parent) { 297 298 this.items_with_submenu.on('click', function (evt) { 299 evt.stopPropagation(); 300 }); 301 302 var t = this; 303 $(document).on('click.mio__front_menu__close_submenu', function () { 304 t.showHideSubmenu(submenu_parent, 'hide'); 305 $(document).off('click.mio__front_menu__close_submenu'); 306 }); 307 308 }, 309 310 /* 311 * @param jQuery li-element of currently clicked submenu - it's parent submenu won't be closed 312 */ 313 closeAllOpenSubmenus: function (clicked_parent) { 314 clicked_parent = clicked_parent || false; 315 316 var open_menus = this.items_with_submenu.filter(function () { 317 var submenu_parent = $(this); 318 if (clicked_parent !== false) { 319 if (submenu_parent.is(clicked_parent.parents('ul:first').parent('li'))) return false; //We don't want to close parent submenu_wrapper of current submenu wrapper 320 } 321 return submenu_parent.data('mio_hovering'); //Mio hovering is also indicating, if current menu is open 322 }); 323 324 var t = this; 325 open_menus.each(function () { 326 t.showHideSubmenu($(this), 'hide'); 327 }); 328 }, 329 330 addPlaceholderItems: function () { 331 332 this.items_with_submenu.each(function () { 333 var parent = $(this), 334 new_element = parent.clone().empty().removeClass('menu-item-has-children'); 335 new_element.append(parent.clone().children('a')); 336 parent.find('.sub-menu:first').prepend(new_element); 337 }); 338 339 this.checkForOverflowedSubmenus(); 340 341 this.placeholders_added = true; 342 343 }, 344 345 toggleMobileMenu: function () { 346 347 var menu_open = this.menu_wrap.is(':visible'); 348 349 if (menu_open) this.menu_wrap.hide(); 350 else this.menu_wrap.show(); 351 352 if (menu_open) { 353 $('.mobile_nav_menu').show(); 354 355 356 } else { 357 $('.mobile_nav_close').show(); 358 359 } 360 361 }, 362
363 openMobileMenu: function () { 364 this.menu_wrap.addClass('open'); 365 this.menu_wrap.before('<div class="mw_mobile_nav_close_overlay"></div>'); 366 var t = this; 367 $('.mw_mobile_nav_close_overlay').click(function () { 368 t.closeMobileMenu(); 369 }); 370 $('body').addClass('mobile_menu_opened'); 371 //$('body').on('wheel.mio__front_menu__noscroll mousewheel.mio__front_menu__noscroll', function () {return false;}); 372 }, 373 374 closeMobileMenu: function () { 375 this.menu_wrap.removeClass('open'); 376 $('.mw_mobile_nav_close_overlay').remove(); 377 $('body').removeClass('mobile_menu_opened'); 378 //$('body').off('wheel.mio__front_menu__noscroll mousewheel.mio__front_menu__noscroll'); 379 } 380 381 382 }; 383 384 385 //Dom ready 386 $(function () { 387 FrontMenu.init(); 388 }); 389 390 //Menu changed in editor 391 $(document).on('mio_editor__replaced_menu', function () { 392 FrontMenu.unbindDesktopEvents(); 393 FrontMenu.unbindMobileEvents(); 394 FrontMenu.init(); 395 }); 396 397 398})(jQuery); 399 400function reload_replaced_header_menu() { 401 jQuery(document).trigger("mio_editor__replaced_menu"); 402}
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.