1/*jslint browser: true, white: true, this: true */ 2/*global console,jQuery,megamenu,window,navigator*/ 3 4/*! Max Mega Menu jQuery Plugin */ 5(function($) { 6 "use strict"; 7 8 $.maxmegamenu = function(menu, options) { 9 var plugin = this; 10 var $menu = $(menu); 11 var $toggle_bar = $menu.siblings(".mega-menu-toggle"); 12 13 var defaults = { 14 event: $menu.attr("data-event"), 15 effect: $menu.attr("data-effect"), 16 effect_speed: parseInt($menu.attr("data-effect-speed")), 17 effect_mobile: $menu.attr("data-effect-mobile"), 18 effect_speed_mobile: parseInt($menu.attr("data-effect-speed-mobile")), 19 panel_width: $menu.attr("data-panel-width"), 20 panel_inner_width: $menu.attr("data-panel-inner-width"), 21 mobile_force_width: $menu.attr("data-mobile-force-width"), 22 second_click: $menu.attr("data-second-click"), 23 vertical_behaviour: $menu.attr("data-vertical-behaviour"), 24 document_click: $menu.attr("data-document-click"), 25 breakpoint: $menu.attr("data-breakpoint"), 26 unbind_events: $menu.attr("data-unbind") 27 }; 28 29 plugin.settings = {}; 30 31 var items_with_submenus = $("li.mega-menu-megamenu.mega-menu-item-has-children," + 32 "li.mega-menu-flyout.mega-menu-item-has-children," + 33 "li.mega-menu-tabbed > ul.mega-sub-menu > li.mega-menu-item-has-children," + 34 "li.mega-menu-flyout li.mega-menu-item-has-children", menu); 35 36 plugin.hidePanel = function(anchor, immediate) { 37 38 anchor.parent().triggerHandler("before_close_panel"); 39 40 if ( (!immediate && plugin.settings.effect == 'slide') || (plugin.isMobileView() && plugin.settings.effect_mobile == 'slide') ) { 41 var speed = plugin.isMobileView() ? plugin.settings.effect_speed_mobile : plugin.settings.effect_speed; 42 43 anchor.siblings(".mega-sub-menu").animate({'height':'hide', 'paddingTop':'hide', 'paddingBottom':'hide', 'minHeight':'hide'}, speed, function() { 44 anchor.siblings(".mega-sub-menu").css("display", ""); 45 anchor.parent().removeClass("mega-toggle-on").triggerHandler("close_panel"); 46 }); 47 48 return; 49 } 50 51 if (immediate) { 52 anchor.siblings(".mega-sub-menu").css("display", "none").delay(plugin.settings.effect_speed).queue(function(){ 53 $(this).css("display", "").dequeue(); 54 }); 55 } 56 57 // pause video widget videos 58 anchor.siblings(".mega-sub-menu").find('.widget_media_video video').each(function() { 59 this.player.pause(); 60 }); 61 62 anchor.parent().removeClass("mega-toggle-on").triggerHandler("close_panel"); 63 plugin.addAnimatingClass(anchor.parent()); 64 }; 65 66 plugin.addAnimatingClass = function(element) { 67 if (plugin.settings.effect === "disabled") { 68 return; 69 } 70 71 $(".mega-animating").removeClass("mega-animating"); 72 73 var timeout = plugin.settings.effect_speed + parseInt(megamenu.timeout, 10); 74 75 element.addClass("mega-animating"); 76 77 setTimeout(function() { 78 element.removeClass("mega-animating"); 79 }, timeout ); 80 }; 81 82 plugin.hideAllPanels = function() { 83 $(".mega-toggle-on > a.mega-menu-link", $menu).each(function() { 84 plugin.hidePanel($(this), false); 85 }); 86 }; 87 88 plugin.hideSiblingPanels = function(anchor, immediate) { 89 anchor.parent().parent().find(".mega-toggle-on").children("a.mega-menu-link").each(function() { // all open children of open siblings 90 plugin.hidePanel($(this), immediate); 91 }); 92 }; 93 94 plugin.isDesktopView = function() { 95 return Math.max(window.outerWidth, $(window).width()) > plugin.settings.breakpoint; // account for scrollbars 96 }; 97 98 plugin.isMobileView = function() { 99 return !plugin.isDesktopView(); 100 }; 101 102 plugin.showPanel = function(anchor) { 103 anchor.parent().triggerHandler("before_open_panel"); 104 105 $(".mega-animating").removeClass("mega-animating"); 106 107 if (plugin.isMobileView() && anchor.parent().hasClass("mega-hide-sub-menu-on-mobile")) { 108 return; 109 } 110 111 if (plugin.isDesktopView() && ($menu.hasClass("mega-menu-horizontal") || $menu.hasClass("mega-menu-vertical"))) { 112 plugin.hideSiblingPanels(anchor, true); 113 } 114 115 if ((plugin.isMobileView() && $menu.hasClass("mega-keyboard-navigation")) || plugin.settings.vertical_behaviour === "accordion") { 116 plugin.hideSiblingPanels(anchor, false); 117 } 118 119 plugin.calculateDynamicSubmenuWidths(anchor); 120 121 // apply jQuery transition (only if the effect is set to "slide", other transitions are CSS based) 122 if ( plugin.settings.effect == "slide" || plugin.isMobileView() && plugin.settings.effect_mobile == 'slide') { 123 var speed = plugin.isMobileView() ? plugin.settings.effect_speed_mobile : plugin.settings.effect_speed; 124 125 anchor.siblings(".mega-sub-menu").css("display", "none").animate({'height':'show', 'paddingTop':'show', 'paddingBottom':'show', 'minHeight':'show'}, speed, function() { 126 $(this).css("display", ""); 127 }); 128 } 129 130 anchor.parent().addClass("mega-toggle-on").triggerHandler("open_panel"); 131 }; 132 133 plugin.calculateDynamicSubmenuWidths = function(anchor) { 134 // apply dynamic width and sub menu position (only to top level mega menus) 135 if (anchor.parent().hasClass("mega-menu-megamenu") && anchor.parent().parent().hasClass("max-mega-menu") && plugin.settings.panel_width && $(plugin.settings.panel_width).length > 0) { 136 if (plugin.isDesktopView()) { 137 var submenu_offset = $menu.offset(); 138 var target_offset = $(plugin.settings.panel_width).offset(); 139 140 anchor.siblings(".mega-sub-menu").css({ 141 width: $(plugin.settings.panel_width).outerWidth(), 142 left: (target_offset.left - submenu_offset.left) + "px" 143 }); 144 } else { 145 anchor.siblings(".mega-sub-menu").css({ 146 width: "", 147 left: "" 148 }); 149 } 150 } 151 152 // apply inner width to sub menu by adding padding to the left and right of the mega menu 153 if (anchor.parent().hasClass("mega-menu-megamenu") && anchor.parent().parent().hasClass("max-mega-menu") && plugin.settings.panel_inner_width && $(plugin.settings.panel_inner_width).length > 0) { 154 var target_width = 0; 155 156 if ($(plugin.settings.panel_inner_width).length) { 157 // jQuery selector 158 target_width = parseInt($(plugin.settings.panel_inner_width).width(), 10); 159 } else { 160 // we"re using a pixel width 161 target_width = parseInt(plugin.settings.panel_inner_width, 10); 162 } 163 164 var submenu_width = parseInt(anchor.siblings(".mega-sub-menu").innerWidth(), 10); 165 166 if (plugin.isDesktopView() && target_width > 0 && target_width < submenu_width) { 167 anchor.siblings(".mega-sub-menu").css({ 168 "paddingLeft": (submenu_width - target_width) / 2 + "px", 169 "paddingRight": (submenu_width - target_width) / 2 + "px" 170 }); 171 } else { 172 anchor.siblings(".mega-sub-menu").css({ 173 "paddingLeft": "", 174 "paddingRight": "" 175 }); 176 } 177 } 178 } 179 180 var bindClickEvents = function() { 181 var dragging = false;
182 183 $(document).on({ 184 "touchmove": function(e) { dragging = true; }, 185 "touchstart": function(e) { dragging = false; } 186 }); 187 188 $(document).on("click touchend", function(e) { // hide menu when clicked away from 189 if (!dragging && plugin.settings.document_click === "collapse" && ! $(e.target).closest(".max-mega-menu li").length && ! $(e.target).closest(".mega-menu-toggle").length ) { 190 plugin.hideAllPanels(); 191 plugin.hideMobileMenu(); 192 } 193 dragging = false; 194 }); 195 196 $("> a.mega-menu-link", items_with_submenus).on("touchend.megamenu", function(e) { 197 plugin.unbindHoverEvents(); 198 plugin.unbindHoverIntentEvents(); 199 }); 200 201 $("> a.mega-menu-link", items_with_submenus).on("click.megamenu", function(e) { 202 if (plugin.isDesktopView() && $(this).parent().hasClass("mega-toggle-on") && $(this).parent().parent().parent().hasClass("mega-menu-tabbed") ) { 203 if (plugin.settings.second_click === "go") { 204 return; 205 } else { 206 e.preventDefault(); 207 return; 208 } 209 } 210 if (dragging) { 211 return; 212 } 213 if (plugin.isMobileView() && $(this).parent().hasClass("mega-hide-sub-menu-on-mobile")) { 214 return; // allow all clicks on parent items when sub menu is hidden on mobile 215 } 216 if ((plugin.settings.second_click === "go" || $(this).parent().hasClass("mega-click-click-go")) && $(this).attr('href') !== undefined) { // check for second click 217 if (!$(this).parent().hasClass("mega-toggle-on")) { 218 e.preventDefault(); 219 plugin.showPanel($(this)); 220 } 221 } else { 222 e.preventDefault(); 223 224 if ($(this).parent().hasClass("mega-toggle-on")) { 225 plugin.hidePanel($(this), false); 226 } else { 227 plugin.showPanel($(this)); 228 } 229 } 230 }); 231 }; 232 233 var bindHoverEvents = function() { 234 items_with_submenus.on({ 235 "mouseenter.megamenu" : function() { 236 plugin.unbindClickEvents(); 237 if (! $(this).hasClass("mega-toggle-on")) { 238 plugin.showPanel($(this).children("a.mega-menu-link")); 239 } 240 }, 241 "mouseleave.megamenu" : function() { 242 if ($(this).hasClass("mega-toggle-on") && ! $(this).hasClass("mega-disable-collapse") && ! $(this).parent().parent().hasClass("mega-menu-tabbed")) { 243 plugin.hidePanel($(this).children("a.mega-menu-link"), false); 244 } 245 } 246 }); 247 }; 248 249 var bindHoverIntentEvents = function() { 250 items_with_submenus.hoverIntent({ 251 over: function () { 252 plugin.unbindClickEvents(); 253 if (! $(this).hasClass("mega-toggle-on")) { 254 plugin.showPanel($(this).children("a.mega-menu-link")); 255 } 256 }, 257 out: function () { 258 if ($(this).hasClass("mega-toggle-on") && ! $(this).hasClass("mega-disable-collapse") && ! $(this).parent().parent().hasClass("mega-menu-tabbed")) { 259 plugin.hidePanel($(this).children("a.mega-menu-link"), false); 260 } 261 }, 262 timeout: megamenu.timeout, 263 interval: megamenu.interval 264 }); 265 }; 266 267 var bindKeyboardEvents = function() { 268 var tab_key = 9; 269 var escape_key = 27; 270 271 $("body").on("keyup", function(e) { 272 var keyCode = e.keyCode || e.which; 273 274 if (keyCode === escape_key) { 275 $menu.parent().removeClass("mega-keyboard-navigation"); 276 plugin.hideAllPanels(); 277 } 278 279 if ( $menu.parent().hasClass("mega-keyboard-navigation") && ! ( $(e.target).closest(".max-mega-menu li").length || $(e.target).closest(".mega-menu-toggle").length ) ) { 280 $menu.parent().removeClass("mega-keyboard-navigation"); 281 plugin.hideAllPanels(); 282 283 if ( plugin.isMobileView() ) { 284 plugin.hideMobileMenu(); 285 } 286 } 287 }); 288 289 $menu.parent().on("keyup", function(e) { 290 var keyCode = e.keyCode || e.which; 291 var active_link = $(e.target); 292 293 if (keyCode === tab_key) { 294 $menu.parent().addClass("mega-keyboard-navigation"); 295 296 if ( active_link.parent().is(items_with_submenus) ) { 297 plugin.showPanel(active_link); 298 } else { 299 plugin.hideSiblingPanels(active_link); 300 } 301 302 if ( active_link.hasClass("mega-menu-toggle") ) { 303 plugin.showMobileMenu(); 304 } 305 } 306 }); 307 }; 308 309 plugin.unbindAllEvents = function() { 310 $("ul.mega-sub-menu, li.mega-menu-item, li.mega-menu-row, li.mega-menu-column, a.mega-menu-link, span.mega-indicator", menu).off().unbind(); 311 }; 312 313 plugin.unbindClickEvents = function() { 314 $("> a.mega-menu-link", items_with_submenus).off("click.megamenu touchend.megamenu"); 315 }; 316 317 plugin.unbindHoverEvents = function() {
318 items_with_submenus.unbind("mouseenter.megamenu mouseleave.megamenu"); 319 }; 320 321 plugin.unbindHoverIntentEvents = function() { 322 items_with_submenus.unbind("mouseenter mouseleave").removeProp('hoverIntent_t').removeProp('hoverIntent_s'); // hoverintent does not allow namespaced events 323 }; 324 325 plugin.unbindMegaMenuEvents = function() { 326 if (plugin.settings.event === "hover_intent") { 327 plugin.unbindHoverIntentEvents(); 328 } 329 330 if (plugin.settings.event === "hover") { 331 plugin.unbindHoverEvents(); 332 } 333 334 plugin.unbindClickEvents(); 335 } 336 337 plugin.bindMegaMenuEvents = function() { 338 if (plugin.isDesktopView() && plugin.settings.event === "hover_intent") { 339 bindHoverIntentEvents(); 340 } 341 342 if (plugin.isDesktopView() && plugin.settings.event === "hover") { 343 bindHoverEvents(); 344 } 345 346 bindClickEvents(); // always bind click events for touch screen devices 347 bindKeyboardEvents(); 348 }; 349 350 plugin.monitorView = function() { 351 if (plugin.isDesktopView()) { 352 $menu.data("view", "desktop"); 353 } else { 354 $menu.data("view", "mobile"); 355 plugin.switchToMobile(); 356 } 357 358 plugin.checkWidth(); 359 360 $(window).resize(function() { 361 plugin.checkWidth(); 362 }); 363 }; 364 365 plugin.checkWidth = function() { 366 if ( plugin.isMobileView() && $menu.data("view") === "desktop" ) { 367 $menu.data("view", "mobile"); 368 plugin.switchToMobile(); 369 } 370 371 if ( plugin.isDesktopView() && $menu.data("view") === "mobile" ) { 372 $menu.data("view", "desktop"); 373 plugin.switchToDesktop(); 374 } 375 376 plugin.calculateDynamicSubmenuWidths($("> li.mega-menu-megamenu > a.mega-menu-link", $menu)); 377 }; 378 379 plugin.reverseRightAlignedItems = function() { 380 if ( ! $('body').hasClass('rtl') ) { 381 $menu.append($menu.children("li.mega-item-align-right").get().reverse()); 382 } 383 }; 384 385 plugin.addClearClassesToMobileItems = function() { 386 $(".mega-menu-row", $menu).each(function() { 387 $("> .mega-sub-menu > .mega-menu-column:not(.mega-hide-on-mobile)", $(this)).filter(":even").addClass('mega-menu-clear'); // :even is 0 based 388 }); 389 } 390 391 plugin.switchToMobile = function() { 392 plugin.unbindMegaMenuEvents(); 393 plugin.bindMegaMenuEvents(); 394 plugin.reverseRightAlignedItems(); 395 plugin.addClearClassesToMobileItems(); 396 plugin.hideAllPanels(); 397 }; 398 399 plugin.switchToDesktop = function() { 400 plugin.unbindMegaMenuEvents(); 401 plugin.bindMegaMenuEvents(); 402 plugin.reverseRightAlignedItems(); 403 plugin.hideAllPanels(); 404 405 $menu.css({ 406 width: '', 407 left: '', 408 display: '' 409 }); 410 411 $toggle_bar.removeClass('mega-menu-open'); 412 }; 413 414 plugin.initToggleBar = function() { 415 // mobile menu 416 $toggle_bar.on("click", function(e) { 417 if ( $(e.target).is(".mega-menu-toggle, .mega-menu-toggle-block, .mega-menu-toggle-animated-block, .mega-menu-toggle-animated-block *, .mega-toggle-blocks-left, .mega-toggle-blocks-center, .mega-toggle-blocks-right, .mega-toggle-label, .mega-toggle-label span") ) { 418 if ($(this).hasClass("mega-menu-open")) { 419 plugin.hideMobileMenu(); 420 } else { 421 plugin.showMobileMenu(); 422 } 423 } 424 }); 425 }; 426 427 plugin.hideMobileMenu = function() { 428 if ( ! $toggle_bar.is(":visible")) { 429 return; 430 } 431 432 $('body').removeClass($menu.attr('id') + "-mobile-open"); 433 434 if (plugin.settings.effect_mobile == 'slide') { 435 $menu.animate({'height':'hide'}, plugin.settings.effect_speed_mobile, function() { 436 $menu.css({ 437 width: '', 438 left: '', 439 display: '' 440 }); 441 }); 442 } 443 444 $toggle_bar.removeClass("mega-menu-open"); 445 }; 446 447 plugin.showMobileMenu = function() { 448 if ( ! $toggle_bar.is(":visible")) { 449 return; 450 } 451 452 $('body').addClass($menu.attr('id') + "-mobile-open"); 453 454 plugin.toggleBarForceWidth(); 455 456 if (plugin.settings.effect_mobile == 'slide') { 457 $menu.animate({'height':'show'}, plugin.settings.effect_speed_mobile); 458 } 459 460 $toggle_bar.addClass("mega-menu-open"); 461 }; 462 463 plugin.toggleBarForceWidth = function() { 464 if ($(plugin.settings.mobile_force_width).length) { 465 var submenu_offset = $toggle_bar.offset(); 466 var target_offset = $(plugin.settings.mobile_force_width).offset(); 467 468 $menu.css({ 469 width: $(plugin.settings.mobile_force_width).outerWidth(), 470 left: (target_offset.left - submenu_offset.left) + "px" 471 }); 472 } 473 }; 474 475 plugin.init = function() { 476 $menu.triggerHandler("before_mega_menu_init"); 477 plugin.settings = $.extend({}, defaults, options); 478 $menu.removeClass("mega-no-js"); 479 480 plugin.initToggleBar(); 481 482 if (plugin.settings.unbind_events == 'true') { 483 plugin.unbindAllEvents(); 484 } 485 486 $("span.mega-indicator", $menu).on('click', function(e) { 487 e.preventDefault(); 488 e.stopPropagation(); 489 plugin.hidePanel($(this).parent(), false); 490 }); 491 492 $(window).on("load", function() { 493 plugin.calculateDynamicSubmenuWidths($("> li.mega-menu-megamenu > a.mega-menu-link", $menu)); 494 }); 495 496 plugin.bindMegaMenuEvents(); 497 plugin.monitorView(); 498 $menu.triggerHandler("after_mega_menu_init"); 499 }; 500 501 plugin.init(); 502 }; 503 504 $.fn.maxmegamenu = function(options) { 505 return this.each(function() { 506 if (undefined === $(this).data("maxmegamenu")) { 507 var plugin = new $.maxmegamenu(this, options); 508 $(this).data("maxmegamenu", plugin); 509 } 510 }); 511 }; 512 513 $(function() { 514 $('.max-mega-menu').maxmegamenu(); 515 }); 516})(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.