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