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