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