1/* 2 * SmartMenus jQuery v0.9.6 3 * http://www.smartmenus.org/ 4 * 5 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd. 6 * http://vadikom.com/ 7 * 8 * Released under the MIT license: 9 * http://www.opensource.org/licenses/MIT 10 */ 11 12(function($) { 13 14 var menuTrees = [], 15 IE = !!window.createPopup, // we need to detect it, unfortunately 16 IElt9 = IE && !document.defaultView, 17 IElt8 = IE && !document.querySelector, 18 IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined', 19 mouse = false, // optimize for touch by default - we will detect for mouse input 20 mouseDetectionEnabled = false; 21 22 // Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.) 23 function initMouseDetection(disable) { 24 if (!mouseDetectionEnabled && !disable) { 25 // if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present 26 // in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events) 27 var firstTime = true, 28 lastMove = null; 29 $(document).bind({ 30 'mousemove.smartmenus_mouse': function(e) { 31 var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() }; 32 if (lastMove) { 33 var deltaX = Math.abs(lastMove.x - thisMove.x), 34 deltaY = Math.abs(lastMove.y - thisMove.y); 35 if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) { 36 mouse = true; 37 // if this is the first check after page load, check if we are not over some item by chance and call the mouseenter handler if yes 38 if (firstTime) { 39 var $a = $(e.target).closest('a'); 40 if ($a.is('a')) { 41 $.each(menuTrees, function() { 42 if ($.contains(this.$root[0], $a[0])) { 43 this.itemEnter({ currentTarget: $a[0] }); 44 return false; 45 } 46 }); 47 } 48 firstTime = false; 49 } 50 } 51 } 52 lastMove = thisMove; 53 }, 54 'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) { 55 if (!/^(4|mouse|pen)$/.test(e.originalEvent.pointerType)) { 56 mouse = false; 57 } 58 } 59 }); 60 mouseDetectionEnabled = true; 61 } else if (mouseDetectionEnabled && disable) { 62 $(document).unbind('.smartmenus_mouse'); 63 mouseDetectionEnabled = false; 64 } 65 }; 66 67 $.SmartMenus = function(elm, options) { 68 this.$root = $(elm); 69 this.opts = options; 70 this.rootId = ''; // internal 71 this.$subArrow = null; 72 this.subMenus = []; // all sub menus in the tree (UL elms) in no particular order (only real - e.g. UL's in mega sub menus won't be counted) 73 this.activatedItems = []; // stores last activated A's for each level 74 this.visibleSubMenus = []; // stores visible sub menus UL's 75 this.showTimeout = 0; 76 this.hideTimeout = 0; 77 this.scrollTimeout = 0; 78 this.clickActivated = false; 79 this.zIndexInc = 0; 80 this.$firstLink = null; // we'll use these for some tests 81 this.$firstSub = null; // at runtime so we'll cache them 82 this.disabled = false; 83 this.$disableOverlay = null; 84 this.init(); 85 }; 86 87 $.extend($.SmartMenus, { 88 hideAll: function() { 89 $.each(menuTrees, function() { 90 this.menuHideAll(); 91 }); 92 }, 93 destroy: function() { 94 while (menuTrees.length) { 95 menuTrees[0].destroy(); 96 } 97 initMouseDetection(true); 98 }, 99 prototype: { 100 init: function(refresh) { 101 var self = this; 102 103 if (!refresh) { 104 menuTrees.push(this); 105 106 this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, ''); 107 108 if (this.$root.hasClass('sm-rtl')) { 109 this.opts.rightToLeftSubMenus = true; 110 } 111 112 // init root (main menu) 113 this.$root 114 .data('smartmenus', this) 115 .attr('data-smartmenus-id', this.rootId) 116 .dataSM('level', 1) 117 .bind({ 118 'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this), 119 'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this) 120 }) 121 .delegate('a, div.logo-container', { 122 'mouseenter.smartmenus': $.proxy(this.itemEnter, this),
123 'mouseleave.smartmenus': $.proxy(this.itemLeave, this), 124 'mousedown.smartmenus': $.proxy(this.itemDown, this), 125 'focus.smartmenus': $.proxy(this.itemFocus, this), 126 'blur.smartmenus': $.proxy(this.itemBlur, this), 127 'click.smartmenus': $.proxy(this.itemClick, this), 128 'touchend.smartmenus': $.proxy(this.itemTouchEnd, this) 129 }); 130 131 var eNamespace = '.smartmenus' + this.rootId; 132 // hide menus on tap or click outside the root UL 133 if (this.opts.hideOnClick) { 134 $(document).on('touchstart' + eNamespace, $.proxy(this.docTouchStart, this)) 135 .on('touchmove' + eNamespace, $.proxy(this.docTouchMove, this)) 136 .on('touchend' + eNamespace, $.proxy(this.docTouchEnd, this)) 137 // for Opera Mobile < 11.5, webOS browser, etc. we'll check click too 138 .on('click' + eNamespace, $.proxy(this.docClick, this)); 139 } 140 // hide sub menus on resize 141 $(window).on('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); 142 var $vmenu = $('body.vmenu .vmenu-container'); 143 if ( ! $vmenu.length && UNCODE.wwidth > UNCODE.mediaQuery ) { 144 $(window).on('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this)); 145 } 146 147 if (this.opts.subIndicators) { 148 this.$subArrow = $('<span/>').addClass('sub-arrow'); 149 if (this.opts.subIndicatorsText) { 150 this.$subArrow.html(this.opts.subIndicatorsText); 151 } 152 } 153 154 // make sure mouse detection is enabled 155 initMouseDetection(); 156 } 157 158 // init sub menus 159 this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0); 160 161 this.$firstLink = this.$root.find('a').eq(0); 162 163 // find current item 164 if (this.opts.markCurrentItem) { 165 var reDefaultDoc = /(index|default)\.[^#\?\/]*/i, 166 reHash = /#.*/, 167 locHref = window.location.href.replace(reDefaultDoc, ''), 168 locHrefNoHash = locHref.replace(reHash, ''); 169 this.$root.find('a').each(function() { 170 var href = this.href.replace(reDefaultDoc, ''), 171 $this = $(this); 172 if (href == locHref || href == locHrefNoHash) { 173 $this.addClass('current'); 174 if (self.opts.markCurrentTree) { 175 $this.parents('li').each(function() { 176 var $this = $(this); 177 if ($this.dataSM('sub')) { 178 $this.children('a').addClass('current'); 179 } 180 }); 181 } 182 } 183 }); 184 } 185 }, 186 destroy: function() { 187 this.menuHideAll(); 188 this.$root 189 .removeData('smartmenus') 190 .removeAttr('data-smartmenus-id') 191 .removeDataSM('level') 192 .unbind('.smartmenus') 193 .undelegate('.smartmenus'); 194 var eNamespace = '.smartmenus' + this.rootId; 195 $(document).unbind(eNamespace); 196 $(window).unbind(eNamespace); 197 if (this.opts.subIndicators) { 198 this.$subArrow = null; 199 } 200 var self = this; 201 $.each(this.subMenus, function() { 202 if (this.hasClass('mega-menu')) { 203 this.find('ul').removeDataSM('in-mega'); 204 } 205 if (this.dataSM('shown-before')) { 206 if (IElt8) { 207 this.children().css({ styleFloat: '', width: '' }); 208 } 209 if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) { 210 if (!IE6) { 211 this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap'); 212 } else { 213 this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', ''); 214 } 215 } 216 if (this.dataSM('scroll-arrows')) { 217 this.dataSM('scroll-arrows').remove(); 218 } 219 this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' }); 220 } 221 if (self.opts.subIndicators) { 222 this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove(); 223 } 224 this.removeDataSM('shown-before') 225 .removeDataSM('ie-shim') 226 .removeDataSM('scroll-arrows') 227 .removeDataSM('parent-a') 228 .removeDataSM('level') 229 .removeDataSM('beforefirstshowfired') 230 .parent().removeDataSM('sub'); 231 }); 232 if (this.opts.markCurrentItem) { 233 this.$root.find('a.current').removeClass('current'); 234 } 235 this.$root = null; 236 this.$firstLink = null; 237 this.$firstSub = null; 238 if (this.$disableOverlay) { 239 this.$disableOverlay.remove(); 240 this.$disableOverlay = null; 241 } 242 menuTrees.splice($.inArray(this, menuTrees), 1); 243 }, 244 disable: function(noOverlay) { 245 if (!this.disabled) { 246 this.menuHideAll(); 247 // display overlay over the menu to prevent interaction 248 if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) { 249 var pos = this.$root.offset(); 250 this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({ 251 position: 'absolute', 252 top: pos.top, 253 left: pos.left, 254 width: this.$root.outerWidth(), 255 height: this.$root.outerHeight(),
256 zIndex: this.getStartZIndex() + 1, 257 opacity: 0 258 }).appendTo(document.body); 259 } 260 this.disabled = true; 261 } 262 }, 263 docClick: function(e) { 264 // hide on any click outside the menu or on a menu link 265 if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) { 266 this.menuHideAll($(e.target)); 267 } 268 }, 269 docTouchEnd: function(e) { 270 if (!this.lastTouch) { 271 return; 272 } 273 if (this.visibleSubMenus.length && (this.lastTouch.x2 === undefined || this.lastTouch.x1 == this.lastTouch.x2) && (this.lastTouch.y2 === undefined || this.lastTouch.y1 == this.lastTouch.y2) && (!this.lastTouch.target || !$.contains(this.$root[0], this.lastTouch.target))) { 274 if (this.hideTimeout) { 275 clearTimeout(this.hideTimeout); 276 this.hideTimeout = 0; 277 } 278 // hide with a delay to prevent triggering accidental unwanted click on some page element 279 var self = this; 280 this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350); 281 } 282 this.lastTouch = null; 283 }, 284 docTouchMove: function(e) { 285 if (!this.lastTouch) { 286 return; 287 } 288 var touchPoint = e.originalEvent.touches[0]; 289 this.lastTouch.x2 = touchPoint.pageX; 290 this.lastTouch.y2 = touchPoint.pageY; 291 }, 292 docTouchStart: function(e) { 293 var touchPoint = e.originalEvent.touches[0]; 294 this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target }; 295 }, 296 enable: function() { 297 if (this.disabled) { 298 if (this.$disableOverlay) { 299 this.$disableOverlay.remove(); 300 this.$disableOverlay = null; 301 } 302 this.disabled = false; 303 } 304 }, 305 getHeight: function($elm) { 306 return this.getOffset($elm, true); 307 }, 308 // returns precise width/height float values in IE9+, FF4+, recent WebKit 309 // http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/ 310 getOffset: function($elm, height) { 311 var old, 312 $win = $(window), 313 winW = $win.width(); 314 if ($elm.css('display') == 'none') { 315 old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility }; 316 $elm.css({ position: 'absolute', visibility: 'hidden' }).show(); 317 if ( 318 ($('body').hasClass('menu-mobile-off-canvas') && winW < 960 && $elm.closest('.main-menu-container').length) 319 || 320 (( $('body').hasClass('vmenu-offcanvas-overlay') || $('body').hasClass('vmenu') ) && winW >= 960 && $elm.closest('.main-menu-container').length && !$elm.closest('.menu-horizontal-inner').length) 321 ) { 322 $elm.closest('li').addClass('smartmenu-open-item'); 323 } 324 } 325 var defaultView = $elm[0].ownerDocument.defaultView, 326 compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null), 327 val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']); 328 if (val) { 329 val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft']) 330 + parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight']) 331 + parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth']) 332 + parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']); 333 } else { 334 val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth; 335 } 336 if (old) { 337 $elm.hide().css(old); 338 } 339 return val; 340 }, 341 getWidth: function($elm) { 342 return this.getOffset($elm); 343 }, 344 getStartZIndex: function() { 345 var zIndex = parseInt(this.$root.css('z-index')); 346 return !isNaN(zIndex) ? zIndex : 1; 347 }, 348 handleEvents: function() { 349 return !this.disabled && this.isCSSOn(); 350 }, 351 handleItemEvents: function($a) { 352 return this.handleEvents() && !this.isLinkInMegaMenu($a); 353 }, 354 isCollapsible: function() { 355 return this.$firstSub.css('position') == 'static'; 356 }, 357 isCSSOn: function() { 358 return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'flex' || this.$firstLink.css('display') == 'inline-flex' || this.$firstLink.css('display') == 'table-cell' || this.$firstLink.css('display') == 'inline'; 359 }, 360 isFixed: function() { 361 return this.$root.css('position') == 'fixed'; 362 }, 363 isLinkInMegaMenu: function($a) { 364 return !$a.parent().parent().dataSM('level'); 365 }, 366 isTouchMode: function() { 367 return !mouse || this.isCollapsible(); 368 }, 369 itemActivate: function($a) { 370 var $li = $a.parent(), 371 $ul = $li.parent(), 372 level = $ul.dataSM('level'); 373 // if for some reason the parent item is not activated (e.g. this is an API call to activate the item), activate all parent items first 374 if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) { 375 var self = this; 376 $($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() { 377 self.itemActivate($(this).dataSM('parent-a')); 378 }); 379 } 380 // hide any visible deeper level sub menus 381 if (this.visibleSubMenus.length > level) { 382 for (var i = this.visibleSubMenus.length - 1, l = !this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level; i > l; i--) { 383 //if ( !this.visibleSubMenus[i].closest('.menu-accordion').length ) { 384 this.menuHide(this.visibleSubMenus[i]); 385 //} 386 } 387 } 388 // save new active item and sub menu for this level 389 this.activatedItems[level - 1] = $a; 390 this.visibleSubMenus[level - 1] = $ul; 391 if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) { 392 return; 393 } 394 // show the sub menu if this item has one 395 var $sub = $li.dataSM('sub'); 396 if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) { 397 this.menuShow($sub); 398 } 399 }, 400 itemBlur: function(e) { 401 var $a = $(e.currentTarget); 402 if (!this.handleItemEvents($a)) { 403 return; 404 } 405 this.$root.triggerHandler('blur.smapi', $a[0]); 406 }, 407 itemClick: function(e) { 408 var $a = $(e.currentTarget); 409 410 if (!this.handleItemEvents($a)) { 411 return; 412 } 413 $a.removeDataSM('mousedown'); 414 if (this.$root.triggerHandler('click.smapi', $a[0]) === false) { 415 return false;
416 } 417 var $sub = $a.parent().dataSM('sub'); 418 if (this.isTouchMode()) { 419 // undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu 420 if ($a.dataSM('href')) { 421 $a.attr('href', $a.dataSM('href')).removeDataSM('href'); 422 } 423 // if the sub is not visible 424 if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 425 // try to activate the item and show the sub 426 this.itemActivate($a); 427 // if "itemActivate" showed the sub, prevent the click so that the link is not loaded 428 // if it couldn't show it, then the sub menus are disabled with an !important declaration (e.g. via mobile styles) so let the link get loaded 429 if ($sub.is(':visible')) { 430 return false; 431 } 432 } 433 } else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) { 434 this.clickActivated = true; 435 this.menuShow($sub); 436 return false; 437 } 438 if ($a.hasClass('disabled')) { 439 return false; 440 } 441 if (this.$root.triggerHandler('select.smapi', $a[0]) === false) { 442 return false; 443 } 444 }, 445 itemDown: function(e) { 446 var $a = $(e.currentTarget); 447 if (!this.handleItemEvents($a)) { 448 return; 449 } 450 $a.dataSM('mousedown', true); 451 }, 452 itemEnter: function(e) { 453 var $a = $(e.currentTarget); 454 if (!this.handleItemEvents($a)) { 455 return; 456 } 457 if (!this.isTouchMode()) { 458 if (this.showTimeout) { 459 clearTimeout(this.showTimeout); 460 this.showTimeout = 0; 461 } 462 var self = this; 463 this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout); 464 } 465 this.$root.triggerHandler('mouseenter.smapi', $a[0]); 466 }, 467 itemFocus: function(e) { 468 var $a = $(e.currentTarget); 469 if (!this.handleItemEvents($a)) { 470 return; 471 } 472 // fix (the mousedown check): in some browsers a tap/click produces consecutive focus + click events so we don't need to activate the item on focus 473 if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) { 474 this.itemActivate($a); 475 } 476 this.$root.triggerHandler('focus.smapi', $a[0]); 477 }, 478 itemLeave: function(e) { 479 var $a = $(e.currentTarget); 480 if (!this.handleItemEvents($a)) { 481 return; 482 } 483 if (!this.isTouchMode()) { 484 if ($a[0].blur) { 485 $a[0].blur(); 486 } 487 if (this.showTimeout) { 488 clearTimeout(this.showTimeout); 489 this.showTimeout = 0; 490 } 491 } 492 $a.removeDataSM('mousedown'); 493 this.$root.triggerHandler('mouseleave.smapi', $a[0]); 494 }, 495 itemTouchEnd: function(e) { 496 var $a = $(e.currentTarget); 497 if (!this.handleItemEvents($a)) { 498 return; 499 } 500 // prevent the address bar on iPhone from sliding down when expanding a sub menu 501 var $sub = $a.parent().dataSM('sub'); 502 if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 503 $a.dataSM('href', $a.attr('href')); 504 $a.attr('href', '#'); 505 } 506 }, 507 menuFixLayout: function($ul) { 508 // fixes a menu that is being shown for the first time 509 if (!$ul.dataSM('shown-before')) { 510 $ul.hide().dataSM('shown-before', true); 511 // fix the layout of the items in IE<8 512 if (IElt8) { 513 $ul.children().css({ styleFloat: 'left', width: '100%' }); 514 } 515 } 516 }, 517 menuHide: function($sub) { 518 if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) { 519 return; 520 } 521 $sub.stop(true, true); 522 if ($sub.is(':visible')) { 523 var complete = function() { 524 // unset z-index 525 if (IElt9) { 526 $sub.parent().css('z-index', ''); 527 } else { 528 $sub.css('z-index', ''); 529 } 530 }; 531 // if sub is collapsible (mobile view) 532 if (this.isCollapsible()) { 533 if (this.opts.collapsibleHideFunction) { 534 this.opts.collapsibleHideFunction.call(this, $sub, complete); 535 } else { 536 $sub.hide(this.opts.collapsibleHideDuration, complete); 537 } 538 } else { 539 if (this.opts.hideFunction) { 540 this.opts.hideFunction.call(this, $sub, complete); 541 } else { 542 $sub.hide(this.opts.hideDuration, complete); 543 } 544 } 545 // remove IE iframe shim 546 if ($sub.dataSM('ie-shim')) { 547 $sub.dataSM('ie-shim').remove(); 548 } 549 // deactivate scrolling if it is activated for this sub 550 if ($sub.dataSM('scroll')) { 551 $sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide(); 552 } 553 // unhighlight parent item 554 $sub.dataSM('parent-a').removeClass('highlighted'); 555 var level = $sub.dataSM('level'); 556 this.activatedItems.splice(level - 1, 1); 557 this.visibleSubMenus.splice(level - 1, 1); 558 this.$root.triggerHandler('hide.smapi', $sub[0]); 559 } 560 }, 561 menuHideAll: function($item) { 562 if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return; 563 var $win = $(window), 564 winW = $win.width(); 565 if (this.showTimeout) { 566 clearTimeout(this.showTimeout); 567 this.showTimeout = 0; 568 } 569 // hide all subs 570 for (var i = this.visibleSubMenus.length - 1; i > 0; i--) { 571 if ( this.visibleSubMenus[i].closest('.smartmenu-open-item').length ) { 572 if ( $item != undefined && $item.closest('.smartmenu-open-item').length ) { 573 this.menuHide(this.visibleSubMenus[i]); 574 $(this.visibleSubMenus[i]).closest('.smartmenu-open-item').removeClass('smartmenu-open-item'); 575 } else { 576 return; 577 } 578 } else { 579 //if ( !this.visibleSubMenus[i].closest('.menu-accordion').length ) { 580 this.menuHide(this.visibleSubMenus[i]); 581 //} 582 } 583 } 584 // hide root if it's popup 585 if (this.opts.isPopup) { 586 this.$root.stop(true, true); 587 if (this.$root.is(':visible')) { 588 if (this.opts.hideFunction) { 589 this.opts.hideFunction.call(this, this.$root); 590 } else { 591 this.$root.hide(this.opts.hideDuration); 592 } 593 // remove IE iframe shim 594 if (this.$root.dataSM('ie-shim')) { 595 this.$root.dataSM('ie-shim').remove(); 596 } 597 } 598 } 599 this.activatedItems = []; 600 this.visibleSubMenus = []; 601 this.clickActivated = false;
602 // reset z-index increment 603 this.zIndexInc = 0; 604 }, 605 menuIframeShim: function($ul) { 606 // create iframe shim for the menu 607 if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) { 608 $ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 }) 609 .css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' }) 610 ); 611 } 612 }, 613 menuInit: function($ul) { 614 if (!$ul.dataSM('in-mega')) { 615 this.subMenus.push($ul); 616 // mark UL's in mega drop downs (if any) so we can neglect them 617 if ($ul.hasClass('mega-menu')) { 618 $ul.find('ul').dataSM('in-mega', true); 619 } 620 // get level (much faster than, for example, using parentsUntil) 621 var level = 2, 622 par = $ul[0]; 623 while (par != null && par.parentNode != null && ( par = par.parentNode.parentNode) != this.$root[0]) { 624 level++; 625 } 626 // cache stuff 627 $ul.dataSM('parent-a', $ul.prevAll('a').eq(-1)) 628 .dataSM('level', level) 629 .parent().dataSM('sub', $ul); 630 // add sub indicator to parent item 631 if (this.opts.subIndicators) { 632 $ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone()); 633 } 634 } 635 }, 636 menuPosition: function($sub) { 637 var fixIE = $('html.ie').length; 638 // if (fixIE) { 639 // var $rowParent = $($sub).closest('.main-menu-container'); 640 // $rowParent.height($rowParent.height()); 641 // } 642 var $a = $sub.dataSM('parent-a'), 643 $li = $sub.parent(), 644 $ul = $sub.parent().parent(), 645 // $container = $ul.closest('.row-menu-inner').length ? ( $('body').hasClass('megamenu-side-to-side') ? ( $('body').hasClass('boxed-width') ? $ul.closest('.row-menu') : $(window) ) : $ul.closest('.row-menu-inner') ) : $ul.closest('.uncol'), 646 $container = $ul.closest('.row-menu-inner').length ? ( $('body').hasClass('megamenu-side-to-side') ? $ul.closest('.row-menu') : $ul.closest('.row-menu-inner') ) : $ul.closest('.uncol'), 647 level = $sub.dataSM('level'), 648 subW = this.getWidth($sub), 649 subH = this.getHeight($sub), 650 itemOffset = $a.offset(), 651 itemX = itemOffset.left, 652 itemY = itemOffset.top, 653 itemW = this.getWidth($a), 654 itemH = this.getHeight($a), 655 $win = $(window), 656 winX = $win.scrollLeft(), 657 winY = $win.scrollTop(), 658 winW = $win.width(), 659 winH = $win.height(), 660 containerW = $container.width(), 661 containerOffsetX = containerW + ((winW - containerW) / 2), 662 horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'), 663 subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX, 664 subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY, 665 x, y, leftPos; 666 667 if (horizontalParent) { 668 x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX; 669 y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY; 670 } else { 671 x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : subW - subOffsetX; 672 y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY; 673 } 674 if (this.opts.keepInViewport && !this.isCollapsible()) { 675 if (this.isFixed()) { 676 itemX -= winX; 677 itemY -= winY; 678 winX = winY = 0; 679 } 680 var absX = itemX + x, 681 absY = itemY + y; 682 if (this.opts.rightToLeftSubMenus && absX < winX) { 683 x = horizontalParent ? winX - absX + x : itemW - subOffsetX; 684 } else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) { 685 x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW; 686 } 687 if (!horizontalParent) { 688 if (subH < winH && absY + subH > winY + winH) { 689 y += winY + winH - subH - absY; 690 } else if (subH >= winH || absY < winY) { 691 y += winY - absY; 692 } 693 } 694 // do we need scrolling? 695 // 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH" 696 if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) { 697 var self = this; 698 if (!$sub.dataSM('scroll-arrows')) { 699 $sub.dataSM('scroll-arrows', $([$('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0], $('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]]) 700 .bind({ 701 mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); }, 702 mouseleave: function(e) { 703 self.menuScrollStop($sub); 704 self.menuScrollOut($sub, e); 705 }, 706 'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); } 707 }) 708 .insertAfter($sub) 709 ); 710 } 711 // bind events to show/hide arrows on hover and save scrolling data for this sub 712 var vportY = winY - (itemY + itemH); 713 $sub.dataSM('scroll', { 714 vportY: vportY, 715 subH: subH, 716 winH: winH, 717 step: 1 718 }) 719 .bind({ 720 'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); }, 721 'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); }, 722 'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); } 723 }) 724 .dataSM('scroll-arrows').css({ top: 'auto', left: '0', marginLeft: x + (parseInt($sub.css('border-left-width')) || 0), width: this.getWidth($sub) - (parseInt($sub.css('border-left-width')) || 0) - (parseInt($sub.css('border-right-width')) || 0), zIndex: this.get
724StartZIndex() + this.zIndexInc }) 725 .eq(0).css('margin-top', vportY).end() 726 .eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end() 727 .eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show(); 728 } 729 } 730 if ( !$sub.closest('.menu-accordion').length ) { 731 var rightPos = 'auto'; 732 if ( $sub.closest('.grid-filters').length ) { 733 if ( $sub.closest('.text-right').length ) { 734 leftPos = '0px'; 735 rightPos = 'auto'; 736 } else { 737 leftPos = 'auto'; 738 rightPos = '0px'; 739 } 740 x = 0; 741 } else { 742 if ( $sub.hasClass('mega-menu-inner') ) { 743 $sub.css({ width: containerW}); 744 leftPos = -1 * (parseFloat($sub.closest('ul.menu-smart').offset().left) - parseFloat($sub.closest('.row-menu').offset().left)); 745 if ( ! $('body').hasClass('megamenu-side-to-side') ) { 746 leftPos += parseFloat($sub.closest('.row-menu-inner').css('paddingLeft')); 747 } 748 x = 0; 749 } else { 750 leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px'; 751 x = (level > 2 && x >= 0) ? x + 1 : x - 1; 752 } 753 } 754 } 755 756 // $sub.css({ top: (level > 2) ? $a[0].offsetTop : (fixIE ? itemH : '100%'), left: leftPos, right: rightPos, marginLeft: x, marginTop: (level > 2) ? 0 : y - itemH + ($sub.closest('.menu-borders').length ? 1 : 0) }); 757 $sub.css({ top: (level > 2) ? $a[0].offsetTop : (fixIE ? itemH : '100%'), left: leftPos, right: rightPos, marginLeft: x, marginTop: (level > 2) ? 0 : y - itemH + ($sub.closest('.menu-borders').length && !$sub.closest('.menu-borders.needs-after').length ? 1 : 0) }); 758 // IE iframe shim 759 this.menuIframeShim($sub); 760 if ($sub.dataSM('ie-shim')) { 761 $sub.dataSM('ie-shim').css({ zIndex: $sub.css('z-index'), width: subW, height: subH, marginLeft: x, marginTop: y - itemH + ($sub.closest('.menu-mini').length ? 0 : 1) }); 762 } 763 }, 764 menuScroll: function($sub, up, wheel) { 765 var y = parseFloat($sub.css('margin-top')), 766 scroll = $sub.dataSM('scroll'), 767 navH = $('.navbar-main').outerHeight(), 768 end = scroll.vportY + (up ? navH + 54 : scroll.winH - scroll.subH), 769 step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step); 770 $sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end); 771 y = parseFloat($sub.css('margin-top')); 772 // show opposite arrow if appropriate 773 if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) { 774 $sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show(); 775 } 776 // accelerate when not using mousewheel to scroll 777 if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) { 778 $sub.dataSM('scroll').step += 0.5; 779 } 780 // "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used 781 if (Math.abs(y - end) < 1) { 782 $sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide(); 783 $sub.dataSM('scroll').step = 1; 784 } else if (!wheel) { 785 var self = this; 786 this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval); 787 } 788 }, 789 menuScrollMousewheel: function($sub, e) { 790 var $closestSub = $(e.target).closest('ul'); 791 while ($closestSub.dataSM('in-mega')) { 792 $closestSub = $closestSub.parent().closest('ul'); 793 } 794 if ($closestSub[0] == $sub[0]) { 795 var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0; 796 if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) { 797 this.menuScroll($sub, up, true); 798 } 799 } 800 if ( ! $sub.hasClass('mega-menu-inner') ) { 801 e.preventDefault(); 802 } 803 }, 804 menuScrollOut: function($sub, e) { 805 var reClass = /^scroll-(up|down)/, 806 $closestSub = $(e.relatedTarget).closest('ul'); 807 while ($closestSub.dataSM('in-mega')) { 808 $closestSub = $closestSub.parent().closest('ul'); 809 } 810 if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) { 811 $sub.dataSM('scroll-arrows').css('visibility', 'hidden'); 812 } 813 }, 814 menuScrollOver: function($sub, e) { 815 var reClass = /^scroll-(up|down)/, 816 $closestSub = $(e.target).closest('ul'); 817 while ($closestSub.dataSM('in-mega')) { 818 $closestSub = $closestSub.parent().closest('ul'); 819 } 820 if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) { 821 $sub.dataSM('scroll-arrows').css('visibility', 'visible'); 822 } 823 }, 824 menuScrollStop: function($sub) { 825 if (this.scrollTimeout) { 826 clearTimeout(this.scrollTimeout); 827 this.scrollTimeout = 0; 828 $sub.dataSM('scroll').step = 1; 829 } 830 }, 831 menuShow: function($sub) { 832 if (!$sub.dataSM('beforefirstshowfired')) { 833 $sub.dataSM('beforefirstshowfired', true); 834 if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) { 835 return; 836 } 837 } 838 if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) { 839 return; 840 } 841 this.menuFixLayout($sub); 842 $sub.stop(true, true); 843 if (!$sub.is(':visible')) { 844 $sub.css({ 845 'visibility': 'visible', 846 'pointer-events': 'auto', 847 }); 848 // set z-index - for IE < 9 set it to the parent LI
849 var zIndex = this.getStartZIndex() + (++this.zIndexInc); 850 if (IElt9) { 851 $sub.parent().css('z-index', zIndex); 852 } else { 853 $sub.css('z-index', zIndex); 854 } 855 // highlight parent item 856 if (this.opts.keepHighlighted || this.isCollapsible()) { 857 if ($sub.dataSM('parent-a').attr('data-type') != 'title') 858 $sub.dataSM('parent-a').addClass('highlighted'); 859 } 860 // min/max-width fix - no way to rely purely on CSS as all UL's are nested 861 if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) { 862 if (!IElt8) { 863 $sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 864 if (this.opts.subMenusMinWidth) { 865 $sub.css('min-width', this.opts.subMenusMinWidth); 866 } 867 if (this.opts.subMenusMaxWidth) { 868 var noMaxWidth = this.getWidth($sub); 869 if ( ! $sub.hasClass('mega-menu-inner') ) { 870 $sub.css('max-width', this.opts.subMenusMaxWidth); 871 } 872 if (noMaxWidth > this.getWidth($sub)) { 873 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 874 } 875 } 876 // IE6,7 877 } else { 878 $sub.children().css('styleFloat', 'none'); 879 if (IE6) { 880 $sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1) 881 .children().children('a').css('white-space', 'nowrap'); 882 } else { // IE7 883 $sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 884 if (this.opts.subMenusMinWidth) { 885 $sub.css('min-width', this.opts.subMenusMinWidth); 886 } 887 } 888 if (this.opts.subMenusMaxWidth) { 889 var noMaxWidth = $sub.width(); 890 if (IE6) { 891 var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width(); 892 if (noMaxWidth > maxWidth) { 893 $sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', ''); 894 } else { 895 $sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' }); 896 } 897 } else { // IE7 898 if ( ! $sub.hasClass('mega-menu-inner') ) { 899 $sub.css('max-width', this.opts.subMenusMaxWidth); 900 } 901 if (noMaxWidth > $sub.width()) { 902 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 903 } else { 904 $sub.width(noMaxWidth); 905 } 906 } 907 } else { 908 $sub.width($sub.width()); 909 } 910 $sub.children().css('styleFloat', 'left'); 911 } 912 } 913 if ( $sub.hasClass('mega-menu-inner') && $('body').hasClass('scrollable-megamenu') && UNCODE.wwidth > UNCODE.mediaQuery ) { 914 var $nav = $('.navbar-main'), 915 navH = 0, 916 navTop = 0, 917 $vmenu = $('body.vmenu .vmenu-container, body.menu-overlay .vmenu-container, body.menu-offcanvas .vmenu-container'); 918 if ( $nav.length && typeof $nav[0] !== 'undefined' ) { 919 var navRect = $nav[0].getBoundingClientRect(); 920 navH = navRect.height; 921 navTop = navRect.top; 922 } 923 if ( ! $vmenu.length ) { 924 $sub.css({ maxHeight: UNCODE.wheight - navH }); 925 } 926 } 927 this.menuPosition($sub); 928 // insert IE iframe shim 929 if ($sub.dataSM('ie-shim')) { 930 $sub.dataSM('ie-shim').insertBefore($sub); 931 } 932 var complete = function() { 933 // fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used 934 $sub.css('overflow', ''); 935 }; 936 // if sub is collapsible (mobile view) 937 if (this.isCollapsible()) { 938 if (this.opts.collapsibleShowFunction) { 939 this.opts.collapsibleShowFunction.call(this, $sub, complete); 940 } else { 941 $sub.show(this.opts.collapsibleShowDuration, complete); 942 } 943 } else { 944 if (this.opts.showFunction) { 945 this.opts.showFunction.call(this, $sub, complete); 946 } else { 947 $sub.show(this.opts.showDuration, complete); 948 } 949 } 950 // save new sub menu for this level 951 this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub; 952 this.$root.triggerHandler('show.smapi', $sub[0]); 953 } 954 }, 955 popupHide: function(noHideTimeout) { 956 if (this.hideTimeout) { 957 clearTimeout(this.hideTimeout); 958 this.hideTimeout = 0; 959 } 960 var self = this; 961 this.hideTimeout = setTimeout(function() { 962 self.menuHideAll(); 963 }, noHideTimeout ? 1 : this.opts.hideTimeout); 964 }, 965 popupShow: function(left, top) { 966 if (!this.opts.isPopup) { 967 alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'); 968 return; 969 } 970 if (this.hideTimeout) { 971 clearTimeout(this.hideTimeout); 972 this.hideTimeout = 0; 973 } 974 this.menuFixLayout(this.$root); 975 this.$root.stop(true, true); 976 if (!this.$root.is(':visible')) { 977 this.$root.css({ left: left, top: top }); 978 // IE iframe shim 979 this.menuIframeShim(this.$root); 980 if (this.$root.dataSM('ie-shim')) { 981 this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
981: left, top: top }).insertBefore(this.$root); 982 } 983 // show menu 984 if (this.opts.showFunction) { 985 this.opts.showFunction.call(this, this.$root); 986 } else { 987 this.$root.show(this.opts.showDuration); 988 } 989 this.visibleSubMenus[0] = this.$root; 990 } 991 }, 992 refresh: function() { 993 this.menuHideAll(); 994 this.$root.find('ul').each(function() { 995 var $this = $(this); 996 if ($this.dataSM('scroll-arrows')) { 997 $this.dataSM('scroll-arrows').remove(); 998 } 999 }) 1000 .removeDataSM('in-mega') 1001 .removeDataSM('shown-before') 1002 .removeDataSM('ie-shim') 1003 .removeDataSM('scroll-arrows') 1004 .removeDataSM('parent-a') 1005 .removeDataSM('level') 1006 .removeDataSM('beforefirstshowfired'); 1007 this.$root.find('a.has-submenu').removeClass('has-submenu') 1008 .parent().removeDataSM('sub'); 1009 if (this.opts.subIndicators) { 1010 this.$root.find('span.sub-arrow').remove(); 1011 } 1012 if (this.opts.markCurrentItem) { 1013 this.$root.find('a.current').removeClass('current'); 1014 } 1015 this.subMenus = []; 1016 this.init(true); 1017 }, 1018 rootOut: function(e) { 1019 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 1020 return; 1021 } 1022 if (this.hideTimeout) { 1023 clearTimeout(this.hideTimeout); 1024 this.hideTimeout = 0; 1025 } 1026 if (!this.opts.showOnClick || !this.opts.hideOnClick) { 1027 var self = this; 1028 this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout); 1029 } 1030 }, 1031 rootOver: function(e) { 1032 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 1033 return; 1034 } 1035 if (this.hideTimeout) { 1036 clearTimeout(this.hideTimeout); 1037 this.hideTimeout = 0; 1038 } 1039 }, 1040 winResize: function(e) { 1041 if (!this.handleEvents()) { 1042 // we still need to resize the disable overlay if it's visible 1043 if (this.$disableOverlay) { 1044 var pos = this.$root.offset(); 1045 this.$disableOverlay.css({ 1046 top: pos.top, 1047 left: pos.left, 1048 width: this.$root.outerWidth(), 1049 height: this.$root.outerHeight() 1050 }); 1051 } 1052 return; 1053 } 1054 // hide sub menus on resize - on mobile do it only on orientation change 1055 if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) { 1056 if (this.activatedItems.length) { 1057 this.activatedItems[this.activatedItems.length - 1][0].blur(); 1058 } 1059 this.menuHideAll(); 1060 } 1061 } 1062 } 1063 }); 1064 1065 $.fn.dataSM = function(key, val) { 1066 if (val) { 1067 return this.data(key + '_smartmenus', val); 1068 } 1069 return this.data(key + '_smartmenus'); 1070 } 1071 1072 $.fn.removeDataSM = function(key) { 1073 return this.removeData(key + '_smartmenus'); 1074 } 1075 1076 $.fn.smartmenus = function(options) { 1077 if (typeof options == 'string') { 1078 var args = arguments, 1079 method = options; 1080 Array.prototype.shift.call(args); 1081 return this.each(function() { 1082 var smartmenus = $(this).data('smartmenus'); 1083 if (smartmenus && smartmenus[method]) { 1084 smartmenus[method].apply(smartmenus, args); 1085 } 1086 }); 1087 } 1088 var opts = $.extend({}, $.fn.smartmenus.defaults, options); 1089 return this.each(function() { 1090 new $.SmartMenus(this, opts); 1091 }); 1092 } 1093 1094 // default settings 1095 $.fn.smartmenus.defaults = { 1096 isPopup: false, // is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar 1097 mainMenuSubOffsetX: 0, // pixels offset from default position
1098 mainMenuSubOffsetY: 0, // pixels offset from default position 1099 subMenusSubOffsetX: 0, // pixels offset from default position 1100 subMenusSubOffsetY: 0, // pixels offset from default position 1101 subMenusMinWidth: false, //'10em', // min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 1102 subMenusMaxWidth: false, //'20em', // max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 1103 subIndicators: true, // create sub menu indicators - creates a SPAN and inserts it in the A 1104 subIndicatorsPos: 'prepend', // position of the SPAN relative to the menu item content ('prepend', 'append') 1105 subIndicatorsText: '+', // [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too) 1106 scrollStep: 30, // pixels step when scrolling long sub menus that do not fit in the viewport height 1107 scrollInterval: 30, // interval between each scrolling step 1108 scrollAccelerate: true, // accelerate scrolling or use a fixed step 1109 showTimeout: 250, // timeout before showing the sub menus 1110 hideTimeout: 500, // timeout before hiding the sub menus 1111 showDuration: 0, // duration for show animation - set to 0 for no animation - matters only if showFunction:null 1112 showFunction: null, // custom function to use when showing a sub menu (the default is the jQuery 'show') 1113 // don't forget to call complete() at the end of whatever you do 1114 // e.g.: function($ul, complete) { $ul.fadeIn(250, complete); } 1115 hideDuration: 0, // duration for hide animation - set to 0 for no animation - matters only if hideFunction:null 1116 hideFunction: function($ul, complete) { $ul.fadeOut(200, complete); }, // custom function to use when hiding a sub menu (the default is the jQuery 'hide') 1117 // don't forget to call complete() at the end of whatever you do 1118 // e.g.: function($ul, complete) { $ul.fadeOut(250, complete); } 1119 collapsibleShowDuration:0, // duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null 1120 collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); }, // custom function to use when showing a collapsible sub menu 1121 // (i.e. when mobile styles are used to make the sub menus collapsible) 1122 collapsibleHideDuration:0, // duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null 1123 collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); }, // custom function to use when hiding a collapsible sub menu 1124 // (i.e. when mobile styles are used to make the sub menus collapsible) 1125 showOnClick: false, // show the first-level sub menus onclick instead of onmouseover (matters only for mouse input) 1126 hideOnClick: true, // hide the sub menus on click/tap anywhere on the page 1127 keepInViewport: true, // reposition the sub menus if needed to make sure they always appear inside the viewport 1128 keepHighlighted: true, // keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's) 1129 markCurrentItem: false, // automatically add the 'current' class to the A element of the item linking to the current URL 1130 markCurrentTree: true, // add the 'current' class also to the A elements of all ancestor items of the current item 1131 rightToLeftSubMenus: false, // right to left display of the sub menus (check the CSS for the sub indicators' position) 1132 bottomToTopSubMenus: false, // bottom to top display of the sub menus 1133 overlapControlsInIE: true // make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.) 1134 }; 1135 1136})(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.