vendor: 14,874 bytes, lines 1-513
1/*! 2 * Bowser - a browser detector 3 * https://github.com/ded/bowser 4 * MIT License | (c) Dustin Diaz 2015 5 */ 6 7!function (name, definition) { 8 if (typeof module != 'undefined' && module.exports) module.exports = definition() 9 else if (typeof define == 'function' && define.amd) define(name, definition) 10 else this[name] = definition() 11}('bowser', function () { 12 /** 13 * See useragents.js for examples of navigator.userAgent 14 */ 15 16 var t = true 17 18 function detect(ua) { 19 20 function getFirstMatch(regex) { 21 var match = ua.match(regex); 22 return (match && match.length > 1 && match[1]) || ''; 23 } 24 25 function getSecondMatch(regex) { 26 var match = ua.match(regex); 27 return (match && match.length > 1 && match[2]) || ''; 28 } 29 30 var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase() 31 , likeAndroid = /like android/i.test(ua) 32 , android = !likeAndroid && /android/i.test(ua) 33 , nexusMobile = /nexus\s*[0-6]\s*/i.test(ua) 34 , nexusTablet = !nexusMobile && /nexus\s*[0-9]+/i.test(ua) 35 , chromeos = /CrOS/.test(ua) 36 , silk = /silk/i.test(ua) 37 , sailfish = /sailfish/i.test(ua) 38 , tizen = /tizen/i.test(ua) 39 , webos = /(web|hpw)os/i.test(ua) 40 , windowsphone = /windows phone/i.test(ua) 41 , windows = !windowsphone && /windows/i.test(ua) 42 , mac = !iosdevice && !silk && /macintosh/i.test(ua) 43 , linux = !android && !sailfish && !tizen && !webos && /linux/i.test(ua) 44 , edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i) 45 , versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i) 46 , tablet = /tablet/i.test(ua) 47 , mobile = !tablet && /[^-]mobi/i.test(ua) 48 , xbox = /xbox/i.test(ua) 49 , result 50 51 if (/opera|opr|opios/i.test(ua)) { 52 result = { 53 name: 'Opera' 54 , opera: t 55 , version: versionIdentifier || getFirstMatch(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i) 56 } 57 } 58 else if (/coast/i.test(ua)) { 59 result = { 60 name: 'Opera Coast' 61 , coast: t 62 , version: versionIdentifier || getFirstMatch(/(?:coast)[\s\/](\d+(\.\d+)?)/i) 63 } 64 } 65 else if (/yabrowser/i.test(ua)) { 66 result = { 67 name: 'Yandex Browser' 68 , yandexbrowser: t 69 , version: versionIdentifier || getFirstMatch(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i) 70 } 71 } 72 else if (/ucbrowser/i.test(ua)) { 73 result = { 74 name: 'UC Browser' 75 , ucbrowser: t 76 , version: getFirstMatch(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i) 77 } 78 } 79 else if (/mxios/i.test(ua)) { 80 result = { 81 name: 'Maxthon' 82 , maxthon: t 83 , version: getFirstMatch(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i) 84 } 85 } 86 else if (/epiphany/i.test(ua)) { 87 result = { 88 name: 'Epiphany' 89 , epiphany: t 90 , version: getFirstMatch(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i) 91 } 92 } 93 else if (/puffin/i.test(ua)) { 94 result = { 95 name: 'Puffin' 96 , puffin: t 97 , version: getFirstMatch(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i) 98 } 99 } 100 else if (/sleipnir/i.test(ua)) { 101 result = { 102 name: 'Sleipnir' 103 , sleipnir: t 104 , version: getFirstMatch(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i) 105 } 106 } 107 else if (/k-meleon/i.test(ua)) { 108 result = { 109 name: 'K-Meleon' 110 , kMeleon: t 111 , version: getFirstMatch(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i) 112 } 113 } 114 else if (windowsphone) { 115 result = { 116 name: 'Windows Phone' 117 , windowsphone: t 118 } 119 if (edgeVersion) { 120 result.msedge = t 121 result.version = edgeVersion 122 } 123 else { 124 result.msie = t 125 result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i) 126 } 127 } 128 else if (/msie|trident/i.test(ua)) { 129 result = { 130 name: 'Internet Explorer' 131 , msie: t 132 , version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i) 133 } 134 } else if (chromeos) { 135 result = { 136 name: 'Chrome' 137 , chromeos: t 138 , chromeBook: t 139 , chrome: t 140 , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 141 } 142 } else if (/chrome.+? edge/i.test(ua)) { 143 result = { 144 name: 'Microsoft Edge' 145 , msedge: t 146 , version: edgeVersion 147 } 148 } 149 else if (/vivaldi/i.test(ua)) { 150 result = { 151 name: 'Vivaldi' 152 , vivaldi: t 153 , version: getFirstMatch(/vivaldi\/(\d+(\.\d+)?)/i) || versionIdentifier 154 } 155 } 156 else if (sailfish) { 157 result = { 158 name: 'Sailfish' 159 , sailfish: t 160 , version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i) 161 } 162 } 163 else if (/seamonkey\//i.test(ua)) { 164 result = { 165 name: 'SeaMonkey' 166 , seamonkey: t 167 , version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i) 168 } 169 } 170 else if (/firefox|iceweasel|fxios/i.test(ua)) { 171 result = { 172 name: 'Firefox' 173 , firefox: t 174 , version: getFirstMatch(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i) 175 } 176 if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) { 177 result.firefoxos = t 178 } 179 } 180 else if (silk) { 181 result = { 182 name: 'Amazon Silk' 183 , silk: t 184 , version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i) 185 } 186 } 187 else if (/phantom/i.test(ua)) { 188 result = { 189 name: 'PhantomJS' 190 , phantom: t 191 , version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i) 192 } 193 } 194 else if (/slimerjs/i.test(ua)) { 195 result = { 196 name: 'SlimerJS' 197 , slimer: t 198 , version: getFirstMatch(/slimerjs\/(\d+(\.\d+)?)/i) 199 } 200 } 201 else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) { 202 result = { 203 name: 'BlackBerry' 204 , blackberry: t 205 , version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i) 206 } 207 } 208 else if (webos) { 209 result = { 210 name: 'WebOS' 211 , webos: t 212 , version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i) 213 }; 214 if( /touchpad\//i.test(ua) ){ 215 result.touchpad = t; 216 } 217 } 218 else if (/bada/i.test(ua)) { 219 result = { 220 name: 'Bada' 221 , bada: t 222 , version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i) 223 }; 224 } 225 else if (tizen) { 226 result = { 227 name: 'Tizen' 228 , tizen: t 229 , version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier 230 }; 231 } 232 else if (/qupzilla/i.test(ua)) { 233 result = { 234 name: 'QupZilla' 235 , qupzilla: t 236 , version: getFirstMatch(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i) || versionIdentifier 237 } 238 } 239 else if (/chromium/i.test(ua)) { 240 result = { 241 name: 'Chromium' 242 , chromium: t 243 , version: getFirstMatch(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i) || versionIdentifier 244 } 245 } 246 else if (/chrome|crios|crmo/i.test(ua)) { 247 result = { 248 name: 'Chrome' 249 , chrome: t 250 , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 251 } 252 } 253 else if (android) { 254 result = { 255 name: 'Android' 256 , version: versionIdentifier 257 } 258 } 259 else if (/safari|applewebkit/i.test(ua)) { 260 result = { 261 name: 'Safari' 262 , safari: t 263 } 264 if (versionIdentifier) { 265 result.version = versionIdentifier 266 } 267 } 268 else if (iosdevice) { 269 result = { 270 name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod' 271 } 272 // WTF: version is not part of user agent in web apps 273 if (versionIdentifier) { 274 result.version = versionIdentifier 275 } 276 } 277 else if(/googlebot/i.test(ua)) { 278 result = { 279 name: 'Googlebot' 280 , googlebot: t 281 , version: getFirstMatch(/googlebot\/(\d+(\.\d+))/i) || versionIdentifier 282 } 283 } 284 else { 285 result = { 286 name: getFirstMatch(/^(.*)\/(.*) /), 287 version: getSecondMatch(/^(.*)\/(.*) /) 288 }; 289 } 290 291 // set webkit or gecko flag for browsers based on these engines 292 if (!result.msedge && /(apple)?webkit/i.test(ua)) { 293 if (/(apple)?webkit\/537\.36/i.test(ua)) { 294 result.name = result.name || "Blink" 295 result.blink = t 296 } else { 297 result.name = result.name || "Webkit" 298 result.webkit = t 299 } 300 if (!result.version && versionIdentifier) { 301 result.version = versionIdentifier 302 } 303 } else if (!result.opera && /gecko\//i.test(ua)) { 304 result.name = result.name || "Gecko" 305 result.gecko = t 306 result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i) 307 } 308 309 // set OS flags for platforms that have multiple browsers 310 if (!result.msedge && (android || result.silk)) { 311 result.android = t 312 } else if (iosdevice) { 313 result[iosdevice] = t 314 result.ios = t 315 } else if (mac) { 316 result.mac = t 317 } else if (xbox) { 318 result.xbox = t 319 } else if (windows) { 320 result.windows = t 321 } else if (linux) { 322 result.linux = t 323 } 324 325 // OS version extraction 326 var osVersion = ''; 327 if (result.windowsphone) { 328 osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i); 329 } else if (iosdevice) { 330 osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i); 331 osVersion = osVersion.replace(/[_\s]/g, '.'); 332 } else if (android) { 333 osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i); 334 } else if (result.webos) { 335 osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i); 336 } else if (result.blackberry) { 337 osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i); 338 } else if (result.bada) { 339 osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i); 340 } else if (result.tizen) { 341 osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i); 342 } 343 if (osVersion) { 344 result.osversion = osVersion; 345 } 346 347 // device type extraction 348 var osMajorVersion = osVersion.split('.')[0]; 349 if ( 350 tablet 351 || nexusTablet 352 || iosdevice == 'ipad' 353 || (android && (osMajorVersion == 3 || (osMajorVersion >= 4 && !mobile))) 354 || result.silk 355 ) { 356 result.tablet = t 357 } else if ( 358 mobile 359 || iosdevice == 'iphone' 360 || iosdevice == 'ipod' 361 || android 362 || nexusMobile 363 || result.blackberry 364 || result.webos 365 || result.bada 366 ) { 367 result.mobile = t 368 } 369 370 // Graded Browser Support 371 // http://developer.yahoo.com/yui/articles/gbs 372 if (result.msedge || 373 (result.msie && result.version >= 10) || 374 (result.yandexbrowser && result.version >= 15) || 375 (result.vivaldi && result.version >= 1.0) || 376 (result.chrome && result.version >= 20) || 377 (result.firefox && result.version >= 20.0) || 378 (result.safari && result.version >= 6) || 379 (result.opera && result.version >= 10.0) || 380 (result.ios && result.osversion && result.osversion.split(".")[0] >= 6) || 381 (result.blackberry && result.version >= 10.1) 382 || (result.chromium && result.version >= 20) 383 ) { 384 result.a = t; 385 } 386 else if ((result.msie && result.version < 10) || 387 (result.chrome && result.version < 20) || 388 (result.firefox && result.version < 20.0) || 389 (result.safari && result.version < 6) || 390 (result.opera && result.version < 10.0) || 391 (result.ios && result.osversion && result.osversion.split(".")[0] < 6) 392 || (result.chromium && result.version < 20) 393 ) { 394 result.c = t 395 } else result.x = t 396 397 return result 398 } 399 400 var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '') 401 402 bowser.test = function (browserList) { 403 for (var i = 0; i < browserList.length; ++i) { 404 var browserItem = browserList[i]; 405 if (typeof browserItem=== 'string') { 406 if (browserItem in bowser) { 407 return true; 408 } 409 } 410 } 411 return false; 412 } 413 414 /** 415 * Get version precisions count 416 * 417 * @example 418 * getVersionPrecision("1.10.3") // 3 419 * 420 * @param {string} version 421 * @return {number} 422 */ 423 function getVersionPrecision(version) { 424 return version.split(".").length; 425 } 426 427 /** 428 * Array::map polyfill 429 * 430 * @param {Array} arr 431 * @param {Function} iterator 432 * @return {Array} 433 */ 434 function map(arr, iterator) { 435 var result = [], i; 436 if (Array.prototype.map) { 437 return Array.prototype.map.call(arr, iterator); 438 } 439 for (i = 0; i < arr.length; i++) { 440 result.push(iterator(arr[i])); 441 } 442 return result; 443 } 444 445 /** 446 * Calculate browser version weight 447 * 448 * @example 449 * compareVersions(['1.10.2.1', '1.8.2.1.90']) // 1 450 * compareVersions(['1.010.2.1', '1.09.2.1.90']); // 1 451 * compareVersions(['1.10.2.1', '1.10.2.1']); // 0 452 * compareVersions(['1.10.2.1', '1.0800.2']); // -1 453 * 454 * @param {Array<String>} versions versions to compare 455 * @return {Number} comparison result 456 */ 457 function compareVersions(versions) { 458 // 1) get common precision for both versions, for example for "10.0" and "9" it should be 2 459 var precision = Math.max(getVersionPrecision(versions[0]), getVersionPrecision(versions[1])); 460 var chunks = map(versions, function (version) { 461 var delta = precision - getVersionPrecision(version); 462 463 // 2) "9" -> "9.0" (for precision = 2) 464 version = version + new Array(delta + 1).join(".0"); 465 466 // 3) "9.0" -> ["000000000"", "000000009"] 467 return map(version.split("."), function (chunk) { 468 return new Array(20 - chunk.length).join("0") + chunk; 469 }).reverse(); 470 }); 471 472 // iterate in reverse order by reversed chunks array 473 while (--precision >= 0) { 474 // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) 475 if (chunks[0][precision] > chunks[1][precision]) { 476 return 1; 477 } 478 else if (chunks[0][precision] === chunks[1][precision]) { 479 if (precision === 0) { 480 // all version chunks are same 481 return 0; 482 } 483 } 484 else { 485 return -1; 486 } 487 } 488 } 489 490 /** 491 * Check if browser is unsupported 492 * 493 * @example 494 * bowser.isUnsupportedBrowser({ 495 * msie: "10", 496 * firefox: "23", 497 * chrome: "29", 498 * safari: "5.1", 499 * opera: "16", 500 * phantom: "534" 501 * }); 502 * 503 * @param {Object} minVersions map of minimal version to browser 504 * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map 505 * @param {String} [ua] user agent string 506 * @return {Boolean} 507 */ 508 function isUnsupportedBrowser(minVersions, strictMode, ua) { 509 var _bowser = bowser; 510 511 // make strictMode param optional with ua param usage 512 if (typeof strictMode === 'string') { 513 ua = strictMode;
514 strictMode = void(0); 515 } 516 517 if (strictMode === void(0)) { 518 strictMode = false; 519 } 520 if (ua) { 521 _bowser = detect(ua); 522 } 523 524 var version = "" + _bowser.version; 525 for (var browser in minVersions) { 526 if (minVersions.hasOwnProperty(browser)) { 527 if (_bowser[browser]) { 528 // browser version and min supported version. 529 return compareVersions([version, minVersions[browser]]) < 0; 530 } 531 } 532 } 533 534 return strictMode; // not found 535 } 536 537 /** 538 * Check if browser is supported 539 * 540 * @param {Object} minVersions map of minimal version to browser 541 * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map 542 * @param {String} [ua] user agent string 543 * @return {Boolean} 544 */ 545 function check(minVersions, strictMode, ua) { 546 return !isUnsupportedBrowser(minVersions, strictMode, ua); 547 } 548 549 bowser.isUnsupportedBrowser = isUnsupportedBrowser; 550 bowser.compareVersions = compareVersions; 551 bowser.check = check; 552 553 /* 554 * Set our detect method to the main bowser object so we can 555 * reuse it to test other user agents. 556 * This is needed to implement future tests. 557 */ 558 bowser._detect = detect; 559 560 return bowser 561}); 562 563(function($){ 564 UABBTrigger = { 565 566 /** 567 * Trigger a hook. 568 * 569 * @since 1.1.0.3 570 * @method triggerHook 571 * @param {String} hook The hook to trigger. 572 * @param {Array} args An array of args to pass to the hook. 573 */ 574 triggerHook: function( hook, args ) 575 { 576 $( 'body' ).trigger( 'uabb-trigger.' + hook, args ); 577 }, 578 579 /** 580 * Add a hook. 581 * 582 * @since 1.1.0.3 583 * @method addHook 584 * @param {String} hook The hook to add. 585 * @param {Function} callback A function to call when the hook is triggered. 586 */ 587 addHook: function( hook, callback ) 588 { 589 $( 'body' ).on( 'uabb-trigger.' + hook, callback ); 590 }, 591 592 /** 593 * Remove a hook. 594 * 595 * @since 1.1.0.3 596 * @method removeHook 597 * @param {String} hook The hook to remove. 598 * @param {Function} callback The callback function to remove. 599 */ 600 removeHook: function( hook, callback ) 601 { 602 $( 'body' ).off( 'uabb-trigger.' + hook, callback ); 603 }, 604 }; 605})(jQuery); 606 607jQuery(document).ready(function( $ ) { 608 609 if( typeof bowser !== 'undefined' && bowser !== null ) { 610 611 var uabb_browser = bowser.name, 612 uabb_browser_v = bowser.version, 613 uabb_browser_class = uabb_browser.replace(/\s+/g, '-').toLowerCase(), 614 uabb_browser_v_class = uabb_browser_class + parseInt( uabb_browser_v ); 615 616 $('html').addClass(uabb_browser_class).addClass(uabb_browser_v_class); 617 618 } 619 620 $('.uabb-row-separator').parents('html').css('overflow-x', 'hidden'); 621}); 622 623;(function($) { 624 625 PPAdvancedMenu = function( settings ) { 626 627 // set params 628 this.settingsId = settings.id; 629 this.nodeClass = '.fl-node-' + settings.id; 630 this.wrapperClass = this.nodeClass + ' .pp-advanced-menu'; 631 this.type = settings.type; 632 this.mobileToggle = settings.mobile; 633 this.mobileBelowRow = 'below' === settings.menuPosition; 634 this.breakpoints = settings.breakpoints; 635 this.mobileBreakpoint = settings.mobileBreakpoint; 636 this.mediaBreakpoint = settings.mediaBreakpoint; 637 this.mobileMenuType = settings.mobileMenuType; 638 this.offCanvasDirection = settings.offCanvasDirection; 639 this.postId = bb_powerpack.post_id; 640 this.isBuilderActive = settings.isBuilderActive; 641 this.currentBrowserWidth = window.innerWidth; 642 this.fullScreenMenu = null; 643 this.offCanvasMenu = null; 644 this.$submenus = null; 645 646 // initialize the menu 647 $( this._initMenu.bind( this ) ); 648 649 // check if viewport is resizing 650 $( window ).on( 'resize', function( e ) { 651 652 var width = window.innerWidth; 653 654 // if screen width is resized, reload the menu 655 if( width != this.currentBrowserWidth ) { 656 657 this._initMenu(); 658 this._clickOrHover(); 659 this.currentBrowserWidth = width; 660 } 661 662 }.bind( this ) ); 663 664 $( 'body' ).on( 'click', function( e ) { 665 if ( 'undefined' !== typeof FLBuilderConfig ){ 666 return; 667 } 668 669 if ( $( this.wrapperClass ).find( '.pp-advanced-menu-mobile-toggle' ).hasClass( 'pp-active' ) && ( 'expanded' !== this.mobileToggle ) ) { 670 if ( $( e.target ).parents('.fl-module-pp-advanced-menu').length > 0 ) { 671 return; 672 } 673 if ( $( e.target ).is( 'input' ) && $( e.target ).parents('.pp-advanced-menu').length > 0 ) { 674 return; 675 } 676 if ( $( e.target ).hasClass( 'pp-menu-close-btn' ) ) { 677 return; 678 } 679 $( this.wrapperClass ).find( '.pp-advanced-menu-mobile-toggle' ).trigger( 'click' ); 680 } 681 682 $( this.wrapperClass ).find( '.pp-has-submenu' ).each( function() { 683 if ( ! $( this ).find( '> .sub-menu' ).is( ':visible' ) ) { 684 $( this ).removeClass( 'pp-active' ); 685 } 686 } ); 687 $( this.wrapperClass ).find( '.pp-has-submenu' ).removeClass( 'focus' ); 688 $( this.wrapperClass ).find( '.pp-has-submenu .sub-menu' ).removeClass( 'focus' ); 689 $( this.wrapperClass ).find( '.pp-has-submenu-container' ).removeClass( 'focus' ); 690 $( this.wrapperClass ).find( '.pp-menu-toggle' ).attr( 'aria-expanded', false ); 691 692 }.bind( this ) ); 693 694 // Esc key to close the submenu. 695 $( document ).on( 'keyup', function( e ) { 696 if ( 27 == e.which ) { 697 $( this.wrapperClass ).find( '.pp-has-submenu' ).each( function() { 698 if ( ! $( this ).find( '> .sub-menu' ).is( ':visible' ) ) { 699 $( this ).removeClass( 'pp-active' ); 700 } 701 } ); 702 $( this.wrapperClass ).find( '.pp-has-submenu' ).removeClass( 'focus' ); 703 $( this.wrapperClass ).find( '.pp-has-submenu .sub-menu' ).removeClass( 'focus' ); 704 $( this.wrapperClass ).find( '.pp-has-submenu-container' ).removeClass( 'focus' ); 705 $( this.wrapperClass ).find( '.pp-menu-toggle' ).attr( 'aria-expanded', false ); 706 if ( $( this.wrapperClass ).find( '.pp-menu-toggle.focus' ).is( ':visible' ) ) { 707 $( this.wrapperClass ).find( '.pp-menu-toggle.focus' ).delay(100).trigger( 'focus' ); 708 } 709 } 710 }.bind( this ) ); 711 712 }; 713 714 PPAdvancedMenu.prototype = { 715 nodeClass : '', 716 wrapperClass : '', 717 type : '', 718 breakpoints : {}, 719 $submenus : null, 720 fullScreenMenu : null, 721 offCanvasMenu : null, 722 723 /** 724 * Check if the screen size fits a mobile viewport. 725 * 726 * @since 1.6.1 727 * @return bool 728 */ 729 _isMobile: function() { 730 return window.innerWidth <= this.breakpoints.small ? true : false;
731 }, 732 733 /** 734 * Check if the screen size fits a medium viewport. 735 * 736 * @since 1.10.5 737 * @return bool 738 */ 739 _isMedium: function() { 740 return window.innerWidth <= this.breakpoints.medium ? true : false; 741 }, 742 743 /** 744 * Check if the screen size fits a large viewport. 745 * 746 * @since 1.10.5 747 * @return bool 748 */ 749 _isLarge: function() { 750 return window.innerWidth <= this.breakpoints.large ? true : false; 751 }, 752 753 /** 754 * Check if the screen size fits a custom viewport. 755 * 756 * @since 1.10.5 757 * @return bool 758 */ 759 _isCustom: function() { 760 return window.innerWidth <= this.breakpoints.custom ? true : false; 761 }, 762 763 _isTouch: function() { 764 var prefixes = ' -webkit- -moz- -o- -ms- '.split(' '); 765 var mq = function(query) { 766 return window.matchMedia(query).matches; 767 } 768 769 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { 770 return true; 771 } 772 773 // include the 'heartz' as a way to have a non matching MQ to help terminate the join 774 // https://git.io/vznFH 775 var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''); 776 return mq(query); 777 }, 778 779 _isIOS: function() { 780 return [ 781 'iPad Simulator', 782 'iPhone Simulator', 783 'iPod Simulator', 784 'iPad', 785 'iPhone', 786 'iPod' 787 ].includes(navigator.platform) 788 // This explicitly catches modern iPads mimicking desktop Macs: 789 || (navigator.userAgent.includes("Mac") && navigator.maxTouchPoints > 1); 790 }, 791 792 /** 793 * Check if the menu should toggle for the current viewport base on the selected breakpoint 794 * 795 * @see this._isMobile() 796 * @see this._isMedium() 797 * @since 1.10.5 798 * @return bool 799 */ 800 _isMenuToggle: function() { 801 if ( ( 'always' == this.mobileBreakpoint 802 || ( this._isMobile() && 'mobile' == this.mobileBreakpoint ) 803 || ( this._isMedium() && 'medium-mobile' == this.mobileBreakpoint ) 804 || ( this._isCustom() && 'custom' == this.mobileBreakpoint ) 805 ) && ( $( this.nodeClass ).find( '.pp-advanced-menu-mobile-toggle' ).is(':visible') || 'expanded' == this.mobileToggle ) ) { 806 return true; 807 } 808 809 return false; 810 }, 811 812 _bindSettingsFormEvents: function() 813 { 814 // $('body').on( 'change', '.fl-builder-settings select[name="offcanvas_direction"]', function() { 815 // $('html').removeClass('pp-off-canvas-menu-open'); 816 // } ); 817 }, 818 819 /** 820 * Initialize the toggle logic for the menu. 821 * 822 * @see this._isMobile() 823 * @see this._menuOnCLick() 824 * @see this._clickOrHover() 825 * @see this._submenuOnRight() 826 * @see this._submenuRowZindexFix() 827 * @see this._toggleForMobile() 828 * @since 1.6.1 829 * @return void 830 */ 831 _initMenu: function() { 832 if ( this.mobileToggle != 'expanded' ) { 833 this._initOffCanvas(); 834 this._initFullScreen(); 835 } 836 837 this._setupSubmenu(); 838 this._menuOnHover(); 839 this._menuOnFocus(); 840 this._submenuOnClick(); 841 842 if ( $( this.nodeClass ).length && this.type == 'horizontal' ) { 843 this._initMegaMenus(); 844 } 845 846 if ( this.type == 'horizontal' || this.type == 'vertical' ) { 847 var self = this; 848 $( this.wrapperClass ).find('.pp-has-submenu-container').on( 'click', function( e ) { 849 if ( self.mobileMenuType !== 'off-canvas' && self.mobileMenuType !== 'full-screen' ) { 850 if ( self._isTouch() ) { 851 if ( ! $(this).hasClass('first-click') ) { 852 e.preventDefault(); 853 $(this).addClass('first-click'); 854 } 855 } 856 } 857 } ); 858 859 // Keyboard nav support for submenu toggle. 860 $( this.wrapperClass ).on( 'keydown.pp-menu', 'a, .pp-has-submenu-container > .pp-menu-toggle', function(e) { 861 var $current = $(e.target); 862 863 var key = e.key || e.which; 864 865 // Normalize keys 866 var KEYS = { 867 LEFT: 'ArrowLeft', 868 RIGHT: 'ArrowRight', 869 UP: 'ArrowUp', 870 DOWN: 'ArrowDown', 871 ENTER: 'Enter', 872 SPACE: ' ', 873 }; 874 875 function isKey(match) { 876 return key === match || key === { 877 ArrowLeft: 37, 878 ArrowUp: 38, 879 ArrowRight: 39, 880 ArrowDown: 40, 881 Enter: 13, 882 ' ': 32 883 }[match]; 884 } 885 886 var $item = $current.closest('li'); 887 var $parentItem = $current.closest('li.pp-has-submenu'); 888 var $submenu = $current.closest('ul.sub-menu'); 889 var isTopLevel = $current.closest('.sub-menu').length === 0; 890 891 /* ========================= 892 TOGGLE HANDLING 893 ========================= */ 894 895 function toggleSubmenu($el) { 896 var $li = $el.closest('li.pp-has-submenu'); 897 var $btn = $li.find('> .pp-has-submenu-container > .pp-menu-toggle'); 898 899 $li.toggleClass('pp-active'); 900 901 var isOpen = $li.hasClass('pp-active'); 902 903 if ($btn.length) { 904 $btn.attr('aria-expanded', isOpen); 905 } 906 } 907 908 // Button toggle 909 if ($current.hasClass('pp-menu-toggle')) { 910 if (isKey(KEYS.ENTER) || isKey(KEYS.SPACE)) { 911 e.preventDefault(); 912 e.stopPropagation(); 913 toggleSubmenu($current); 914 return; 915 } 916 } 917 918 /* ========================= 919 TOP LEVEL NAV (â â) 920 ========================= */ 921 922 if (isTopLevel && (isKey(KEYS.LEFT) || isKey(KEYS.RIGHT))) { 923 e.preventDefault(); 924 e.stopPropagation(); 925 926 if (isKey(KEYS.LEFT)) { 927 if ( $current.is( '.pp-menu-toggle' ) ) { 928 $current.prev('a').focus(); 929 } else { 930 var $prev = $item.prev(); 931 if ($prev.length) { 932 var $target = $prev.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 933 ($target.length ? $target : $prev.find('a')).first().focus(); 934 } 935 } 936 } 937 938 if (isKey(KEYS.RIGHT)) { 939 if ( $current.next().is( '.pp-menu-toggle:visible' ) ) { 940 $current.next().focus(); 941 } else { 942 var $next = $item.next(); 943 if ($next.length) { 944 $next.find('a').first().focus(); 945 } 946 } 947 } 948 949 return; 950 } 951 952 // NESTED submenu navigation (LEFT / RIGHT) 953 if (!isTopLevel && (isKey(KEYS.RIGHT) || isKey(KEYS.LEFT))) { 954 955 var $parentItem = $current.closest('li.pp-has-submenu'); 956 957 // RIGHT â go into child submenu 958 if (isKey(KEYS.RIGHT)) { 959 var $childSubmenu = $parentItem.children('.sub-menu'); 960 961 if ($childSubmenu.length) { 962 e.preventDefault(); 963 e.stopPropagation(); 964 965 // Ensure open state 966 $parentItem.addClass('pp-active'); 967 968 var $toggle = $parentItem.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 969 if ($toggle.length) { 970 $toggle.attr('aria-expanded', true); 971 } else { 972 $parentItem.find('> .pp-has-submenu-container > a').attr('aria-expanded', true); 973 } 974 975 // Focus first item in child submenu 976 $childSubmenu.find('a, .pp-menu-toggle:visible').first().focus(); 977 } 978 return; 979 } 980 981 // LEFT â go back to parent menu item 982 if (isKey(KEYS.LEFT)) { 983 var $currentSubmenu = $current.closest('ul.sub-menu'); 984 var $parentItem = $currentSubmenu.parent('li'); 985 986 if ($parentItem.length) { 987 e.preventDefault(); 988 e.stopPropagation(); 989 990 // CLOSE submenu 991 $parentItem.removeClass('pp-active'); 992 993 var $toggle = $parentItem.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 994 995 if ($toggle.length) { 996 $toggle.attr('aria-expanded', false); 997 $toggle.focus(); 998 } else { 999 $parentItem.find('> .pp-has-submenu-container > a').attr('aria-expanded', false).focus(); 1000 } 1001 } 1002 return; 1003 } 1004 } 1005 1006 /* ========================= 1007 SUBMENU NAV (â â) 1008 ========================= */ 1009 1010 // DOWN from toggle â first submenu item 1011 if (isKey(KEYS.DOWN) && isTopLevel && $parentItem.length) { 1012 e.preventDefault(); 1013 e.stopPropagation(); 1014 1015 var $submenu = $parentItem.children('.sub-menu'); 1016 1017 if ($submenu.length) { 1018 // ensure open state 1019 if (!$parentItem.hasClass('pp-active')) { 1020 $parentItem.addClass('pp-active'); 1021 1022 var $toggle = $parentItem.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 1023 if ($toggle.length) { 1024 $toggle.attr('aria-expanded', true); 1025 } else { 1026 $parentItem.find('> .pp-has-submenu-container > a').attr('aria-expanded', true); 1027 } 1028 } 1029 1030 // move focus into submenu 1031 $submenu.find('a, .pp-menu-toggle:visible').first().focus(); 1032 } 1033 1034 return; 1035 } 1036 1037 if (!$submenu.length) { 1038 return; 1039 } 1040 1041 var $items = $submenu.find('a, .pp-menu-toggle').filter(':visible'); 1042 var index = $items.index($current); 1043 1044 if (index === -1) return; 1045 1046 // DOWN â 1047 if (isKey(KEYS.DOWN)) { 1048 e.preventDefault(); 1049 e.stopPropagation(); 1050 1051 var next = index + 1; 1052 if (next < $items.length) { 1053 $items.eq(next).focus(); 1054 } 1055 return; 1056 } 1057 1058 // UP â 1059 if (isKey(KEYS.UP)) { 1060 e.preventDefault(); 1061 e.stopPropagation(); 1062 1063 if (index === 0 && ! $current.closest('.sub-menu').parents('.sub-menu').length) { 1064 var $currentSubmenu = $current.closest('ul.sub-menu'); 1065 var $parentItem = $currentSubmenu.parent('li'); 1066 var $toggle = $parentItem.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 1067 if ($toggle.length) { 1068 $toggle.focus(); 1069 } else { 1070 $parentItem.find('> .pp-has-submenu-container > a').focus(); 1071 } 1072 return; 1073 } 1074 1075 // Don't loop back to the last item if we're on the first item of a submenu 1076 if ( index === 0 ) { 1077 $items.eq(index).focus(); 1078 return; 1079 } 1080 1081 $items.eq(index - 1).focus(); 1082 return; 1083 } 1084 1085 }.bind( this ) ); 1086 } 1087 1088 if ( this._isMenuToggle() || this.type == 'accordion' ) { 1089 $( this.wrapperClass ).off( 'mouseenter mouseleave' ); 1090 this._menuOnClick(); 1091 this._clickOrHover(); 1092 } else { 1093 $( this.wrapperClass ).off( 'click' ); 1094 this._submenuOnRight(); 1095 this._submenuRowZindexFix(); 1096 } 1097 1098 if ( this.mobileToggle != 'expanded' ) { 1099 this._toggleForMobile(); 1100 } 1101 1102 $(this.wrapperClass).find('li:not(.menu-item-has-children)').on('click', 'a', function (e) { 1103 if ( $(e.target).closest( '.pp-menu-search-item' ).length > 0 ) { 1104 return; 1105 } 1106 1107 $(this.nodeClass).find('.pp-advanced-menu').removeClass('menu-open'); 1108 $(this.nodeClass).find('.pp-advanced-menu').addClass('menu-close'); 1109 $('html').removeClass('pp-off-canvas-menu-open'); 1110 $('html').removeClass('pp-full-screen-menu-open'); 1111 1112 }.bind( this ) ); 1113 1114 if ( $( this.wrapperClass ).find( '.pp-menu-search-item' ).length ) { 1115 this._toggleMenuSearch(); 1116 } 1117 1118 if ( $( this.wrapperClass ).find( '.pp-menu-cart-item').length ) { 1119 this._wooUpdateParams(); 1120 } 1121 }, 1122 1123 /** 1124 * Initializes submenu dropdowns. 1125 * 1126 * @since 2.33.x 1127 * @return void 1128 */ 1129 _setupSubmenu: function() { 1130 // $( this.wrapperClass + ' ul.sub-menu' ).each( function(){ 1131 // $( this ).closest( 'li' ).attr( 'aria-haspopup', 'true' ); 1132 // }); 1133 }, 1134 1135 _menuOnHover: function() { 1136 $( this.wrapperClass ).on( 'mouseenter', 'li.menu-item', function() { 1137 $(this).addClass( 'hover' ); 1138 } ).on( 'mouseleave', 'li.menu-item', function() { 1139 $(this).removeClass( 'hover' ); 1140 } ); 1141 }, 1142 1143 /** 1144 * Adds a focus class to menu elements similar to be used similar to CSS :hover psuedo event 1145 * 1146 * @since 1.9.0 1147 * @return void 1148 */ 1149 _menuOnFocus: function() { 1150 $( this.nodeClass ).off('focus', 'a').on( 'focus', 'a', function( e ) { 1151 var $menuItem = $( e.target ).parents( '.menu-item' ).first(), 1152 $parents = $( e.target ).parentsUntil( this.wrapperClass ); 1153 1154 $('.pp-advanced-menu .focus:not(.pp-menu-toggle)').removeClass('focus'); 1155 1156 $menuItem.addClass('focus'); 1157 $parents.addClass('focus'); 1158 1159 }.bind( this ) ).on( 'focusout', 'a', function( e ) { 1160 if ( $('.pp-advanced-menu .focus').hasClass('pp-has-submenu') ) { 1161 $( e.target ).parentsUntil( this.wrapperClass ).find('.pp-has-submenu-container').removeClass('first-click'); 1162 } 1163 }.bind( this ) ); 1164 1165 $( this.nodeClass ).off('focus', '.pp-menu-toggle').on( 'focus', '.pp-menu-toggle', function( e ) { 1166 $(e.target).addClass( 'focus' ); 1167 }.bind( this ) ).off('blur', '.pp-menu-toggle').on( 'blur', '.pp-menu-toggle', function( e ) { 1168 if ( $(e.target).parents( 'li.pp-has-submenu.pp-active' ).length === 0 || $(e.target).parents( 'li.pp-has-submenu.pp-active' ).parent( 'ul.menu' ).length === 0 ) { 1169 $(e.target).removeClass( 'focus' ); 1170 } 1171 }.bind( this ) ); 1172 }, 1173 1174 /** 1175 * Logic for submenu toggling on accordions or mobile menus (vertical, horizontal) 1176 * 1177 * @since 1.6.1 1178 * @return void 1179 */ 1180 _menuOnClick: function() { 1181 var self = this; 1182 var $mainItem = ''; 1183 1184 $( this.wrapperClass ) 1185 .off( 'click.pp-advanced-menu keyup', '.pp-has-submenu-container' ) 1186 .on( 'click.pp-advanced-menu keyup', '.pp-has-submenu-container', function( e ) { 1187 var isValidEvent = e.which == 1 || e.which == 13 || e.which == undefined; // click or enter key press. 1188 if ( ! isValidEvent ) { 1189 return; 1190 } 1191 if ( e.which == 13 && ! $(e.target).hasClass( 'pp-menu-toggle' ) ) { // prevent event bubbling. 1192 return; 1193 } 1194 if ( self._isTouch() ) { 1195 if ( ! $(this).hasClass('first-click') ) { 1196 e.preventDefault(); 1197 $(this).addClass('first-click'); 1198 } 1199 } 1200 1201 e.stopPropagation(); 1202 1203 var isMainEl = $(e.target).parents('.menu-item').parent().parent().hasClass('pp-advanced-menu'); 1204 1205 if (isMainEl && $mainItem === '') { 1206 $mainItem = $(e.target).parents('.menu-item'); 1207 } 1208 1209 var $link = $( e.target ).parents( '.pp-has-submenu' ).first(), 1210 $subMenu = $link.children( '.sub-menu' ).first(), 1211 $href = $link.children('.pp-has-submenu-container').first().find('> a').attr('href'), 1212 $subMenuParents = $( e.target ).parents( '.sub-menu' ), 1213 $activeParent = $( e.target ).closest( '.pp-has-submenu.pp-active' ); 1214 1215 if ( $activeParent.length > 0 ) { 1216 $activeParent.find( '.pp-menu-toggle' ).first().attr('aria-expanded', true); 1217 } else { 1218 $activeParent.find( '.pp-menu-toggle' ).first().attr('aria-expanded', false); 1219 } 1220 1221 if( !$subMenu.is(':visible') || $(e.target).hasClass('pp-menu-toggle') 1222 || ($subMenu.is(':visible') && (typeof $href === 'undefined' || $href == '#')) ) { 1223 if ( ! $(this.wrapperClass).hasClass('pp-advanced-menu-accordion-collapse') ) { 1224 e.preventDefault(); 1225 } 1226 if ( $(e.target).hasClass('pp-menu-toggle') ) { 1227 e.stopPropagation(); 1228 e.preventDefault(); 1229 } 1230 } 1231 else { 1232 e.stopPropagation(); 1233 window.location.href = $href; 1234 return; 1235 } 1236 1237 if ($(this.wrapperClass).hasClass('pp-advanced-menu-accordion-collapse')) { 1238 1239 if ( $link.parents('.menu-item').length && !$link.parents('.menu-item').hasClass('pp-active') ) { 1240 $('.menu .pp-active', this.wrapperClass).not($link).removeClass('pp-active'); 1241 } 1242 else if ($link.parents('.menu-item').hasClass('pp-active') && $link.parent('.sub-menu').length) { 1243 $('.menu .pp-active', this.wrapperClass).not($link).not($activeParent).removeClass('pp-active'); 1244 } 1245 1246 $('.sub-menu', this.wrapperClass).not($subMenu).not($subMenuParents).slideUp('normal'); 1247 } 1248 1249 // Parent menu toggle icon was being reversed on collapsing its submenu, 1250 // so here is the workaround to fix this behavior. 1251 if ($(self.wrapperClass).find('.sub-menu:visible').length > 0) { 1252 $(self.wrapperClass).find('.sub-menu:visible').parent().addClass('pp-active'); 1253 } 1254 $subMenu.slideToggle(400, function() { 1255 // Reset previously opened sub-menu toggle icon. 1256 $(e.target).parents('.pp-has-submenu-container').parent().parent().find('> .menu-item.pp-active').removeClass('pp-active'); 1257 1258 if ($mainItem !== '') { 1259 $mainItem.parent().find('.menu-item.pp-active').removeClass('pp-active'); 1260 $(self.wrapperClass).find('.sub-menu').parent().removeClass('pp-active'); 1261 1262 if ($(self.wrapperClass).find('.sub-menu:visible').length > 0) { 1263 $(self.wrapperClass).find('.sub-menu:visible').parent().addClass('pp-active'); 1264 } else { 1265 $link.toggleClass('pp-active'); 1266 $mainItem.removeClass('pp-active'); 1267 } 1268 } else { 1269 $link.toggleClass('pp-active'); 1270 } 1271 if (!$subMenu.is(':visible')) { 1272 $subMenu.parent().removeClass('pp-active'); 1273 $subMenu.parent().find('> .p
1273p-has-submenu-container .pp-menu-toggle').attr('aria-expanded', false); 1274 } else { 1275 $subMenu.parent().find('> .pp-has-submenu-container .pp-menu-toggle').attr('aria-expanded', true); 1276 } 1277 }); 1278 1279 }.bind( this ) ); 1280 1281 }, 1282 1283 /** 1284 * Logic for submenu items click event 1285 * 1286 * @since 1.3.1 1287 * @return void 1288 */ 1289 _submenuOnClick: function(){ 1290 $( 'body' ).off( 'click', this.wrapperClass + ' .sub-menu a' ).on( 'click', this.wrapperClass + ' .sub-menu a', function( e ){ 1291 if ( $( e.target ).parent().hasClass('focus') ) { 1292 $( e.target ).parentsUntil( this.wrapperClass ).removeClass( 'focus' ); 1293 } 1294 }.bind( this ) ); 1295 }, 1296 1297 /** 1298 * Changes general styling and behavior of menus based on mobile / desktop viewport. 1299 * 1300 * @see this._isMobile() 1301 * @since 1.6.1 1302 * @return void 1303 */ 1304 _clickOrHover: function() { 1305 this.$submenus = this.$submenus || $( this.wrapperClass ).find( '.sub-menu' ); 1306 var $wrapper = $( this.wrapperClass ), 1307 $menu = $wrapper.find( '.menu' ); 1308 $li = $wrapper.find( '.pp-has-submenu' ); 1309 1310 if( this._isMenuToggle() ) { 1311 $li.each( function() { 1312 if( !$(this).hasClass('pp-active') ) { 1313 $(this).find( '.sub-menu' ).fadeOut(); 1314 } 1315 } ); 1316 } else { 1317 $li.each( function() { 1318 if( !$(this).hasClass('pp-active') ) { 1319 $(this).find( '.sub-menu' ).css( { 1320 'display' : '', 1321 'opacity' : '' 1322 } ); 1323 } 1324 } ); 1325 } 1326 }, 1327 1328 /** 1329 * Logic to prevent submenus to go outside viewport boundaries. 1330 * 1331 * @since 1.6.1 1332 * @return void 1333 */ 1334 _submenuOnRight: function() { 1335 1336 $( this.wrapperClass ) 1337 .on( 'mouseenter focus', '.pp-has-submenu', function( e ) { 1338 1339 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 1340 return; 1341 } 1342 1343 var $link = $( e.currentTarget ), 1344 $parent = $link.parent(), 1345 $subMenu = $link.find( '.sub-menu' ), 1346 subMenuWidth = $subMenu.width(), 1347 subMenuPos = 0, 1348 winWidth = window.innerWidth; 1349 1350 if( $link.closest( '.pp-menu-submenu-right' ).length !== 0) { 1351 1352 $link.addClass( 'pp-menu-submenu-right' ); 1353 1354 } else if( $( 'body' ).hasClass( 'rtl' ) ) { 1355 1356 subMenuPos = $parent.is( '.sub-menu' ) ? 1357 $parent.offset().left - subMenuWidth: 1358 $link.offset().left - subMenuWidth; 1359 1360 if( subMenuPos <= 0 ) { 1361 $link.addClass( 'pp-menu-submenu-right' ); 1362 } 1363 1364 } else { 1365 1366 subMenuPos = $parent.is( '.sub-menu' ) ? 1367 $parent.offset().left + $parent.width() + subMenuWidth : 1368 $link.offset().left + subMenuWidth; 1369 1370 if( subMenuPos > winWidth ) { 1371 $link.addClass('pp-menu-submenu-right'); 1372 } 1373 } 1374 }.bind( this ) ) 1375 .on( 'mouseleave', '.pp-has-submenu', function( e ) { 1376 $( e.currentTarget ).removeClass( 'pp-menu-submenu-right' ); 1377 }.bind( this ) ); 1378 1379 }, 1380 1381 /** 1382 * Logic to prevent submenus to go behind the next overlay row. 1383 * 1384 * @since 2.2 1385 * @return void 1386 */ 1387 _submenuRowZindexFix: function (e) { 1388 1389 $(this.wrapperClass) 1390 .on('mouseenter', 'ul.menu > .pp-has-submenu', function (e) { 1391 1392 if ($(e.currentTarget).find('.sub-menu').length === 0) { 1393 return; 1394 } 1395 1396 $(this.nodeClass) 1397 .closest('.fl-row') 1398 .find('.fl-row-content') 1399 .css('z-index', '10'); 1400 1401 }.bind( this ) ) 1402 .on('mouseleave', 'ul.menu > .pp-has-submenu', function (e) { 1403 1404 $(this.nodeClass) 1405 .closest('.fl-row') 1406 .find('.fl-row-content') 1407 .css('z-index', ''); 1408 1409 }.bind( this ) ); 1410 }, 1411 1412 /** 1413 * Logic for the mobile menu button. 1414 * 1415 * @since 1.6.1 1416 * @return void 1417 */ 1418 _toggleForMobile: function() { 1419 1420 var $wrapper = null, 1421 $menu = null, 1422 self = this; 1423 1424 if ( this._isMenuToggle() ) { 1425 $wrapper = $(this.wrapperClass); 1426 if ( this._isMobileBelowRowEnabled() ) { 1427 this._placeMobileMenuBelowRow(); 1428 $menu = $(this.nodeClass + '-clone'); 1429 $menu.find('ul.menu').show(); 1430 } else { 1431 $menu = $wrapper.find('.menu'); 1432 } 1433 1434 if( !$wrapper.find( '.pp-advanced-menu-mobile-toggle' ).hasClass( 'pp-active' ) && this.mobileMenuType === 'default' ) { 1435 $menu.css({ display: 'none' }); 1436 } 1437 1438 $wrapper 1439 .off( 'click.pp-mobile-menu-toggle', '.pp-advanced-menu-mobile-toggle' ) 1440 .on( 'click.pp-mobile-menu-toggle', '.pp-advanced-menu-mobile-toggle', function( e ) { 1441 e.stopPropagation(); 1442 $(this).toggleClass( 'pp-active' ); 1443 if ( $(this).hasClass('pp-active') ) { 1444 $(this).attr('aria-expanded', 'true'); 1445 $menu.addClass( 'pp-menu-visible' ); 1446 } else { 1447 $(this).attr('aria-expanded', 'false'); 1448 $menu.removeClass( 'pp-menu-visible' ); 1449 } 1450 $menu.slideToggle(); 1451 } ); 1452 1453 $menu.on( 'click', '.menu-item > a[href*="#"]', function(e) { 1454 var $href = $(this).attr('href'), 1455 $targetID = ''; 1456 1457 if ( $href !== '#' ) { 1458 $targetID = $href.split('#')[1]; 1459 1460 if ( $('body').find('#'+ $targetID).length > 0 ) { 1461 e.preventDefault(); 1462 $( this ).toggleClass( 'pp-active' ); 1463 setTimeout(function() { 1464 $('html, body').animate({ 1465 scrollTop: $('#'+ $targetID).offset().top 1466 }, 1000, function() { 1467 window.location.hash = $targetID; 1468 }); 1469 }, 500); 1470 1471 if ( ! self._isMenuToggle() ) { 1472 $menu.slideToggle(); 1473 } 1474 } 1475 } 1476 }); 1477 } 1478 else { 1479 1480 if ( this._isMobileBelowRowEnabled() ) { 1481 this._removeMenuFromBelowRow(); 1482 } 1483 1484 $wrapper = $( this.wrapperClass ), 1485 $menu = $wrapper.children( '.menu' ); 1486 $wrapper.find( '.pp-advanced-menu-mobile-toggle' ).removeClass( 'pp-active' ); 1487 $menu.css({ display: '' }); 1488 } 1489 }, 1490 1491 /** 1492 * Init any mega menus that exist. 1493 * 1494 * @see this._isMenuToggle() 1495 * @since 1.10.4 1496 * @return void 1497 */ 1498 _initMegaMenus: function() { 1499 1500 var module = $( this.nodeClass ), 1501 rowContent = module.closest( '.fl-row-content' ), 1502 rowWidth = rowContent.width(), 1503 megas = module.find( '.mega-menu' ), 1504 disabled = module.find( '.mega-menu-disabled' ), 1505 isToggle = this._isMenuToggle(); 1506 1507 if ( isToggle ) { 1508 megas.removeClass( 'mega-menu' ).addClass( 'mega-menu-disabled' ); 1509 module.find( 'li.mega-menu-disabled > ul.sub-menu' ).css( 'width', '' ); 1510 rowContent.css( 'position', '' ); 1511 } else { 1512 disabled.removeClass( 'mega-menu-disabled' ).addClass( 'mega-menu' ); 1513 module.find( 'li.mega-menu > ul.sub-menu' ).css( 'width', rowWidth + 'px' ); 1514 rowContent.css( 'position', 'relative' ); 1515 } 1516 }, 1517 1518 /** 1519 * Init off-canvas menu. 1520 * 1521 * @since 1.2.8 1522 * @return void 1523 */ 1524 _initOffCanvas: function() { 1525 if ( this.mobileMenuType !== 'off-canvas' ) { 1526 return; 1527 } 1528 $('html').addClass('pp-off-canvas-menu-module'); 1529 $('html').addClass('pp-off-canvas-menu-' + this.offCanvasDirection); 1530 1531 if ( $(this.nodeClass).find( '#pp-menu-' + this.settingsId ).length === 0 ) { 1532 return; 1533 } 1534 1535 var menuHTML = $(this.nodeClass).find( '#pp-menu-' + this.settingsId ).html(); 1536 1537 if ( null === this.offCanvasMenu ) {
1538 this.offCanvasMenu = $('<div id="pp-advanced-menu-off-canvas-'+this.settingsId+'" class="fl-node-'+this.settingsId+' pp-menu-off-canvas" />').html( menuHTML ); 1539 } 1540 if ( $('#pp-advanced-menu-off-canvas-'+this.settingsId).length === 0 && null !== this.offCanvasMenu && ! this.isBuilderActive ) { 1541 this.offCanvasMenu.appendTo( 'body' ); 1542 } 1543 1544 $(this.nodeClass).trigger('pp-advanced-menu-off-canvas-init', [this.offCanvasMenu]); 1545 1546 this._toggleMenu(); 1547 }, 1548 1549 /** 1550 * Init full-screen overlay menu. 1551 * 1552 * @since 1.2.8 1553 * @return void 1554 */ 1555 _initFullScreen: function() { 1556 if ( this.mobileMenuType !== 'full-screen' ) { 1557 return; 1558 } 1559 1560 $('html').addClass('pp-full-screen-menu-module'); 1561 1562 if ( $(this.nodeClass).find( '#pp-menu-' + this.settingsId ).length === 0 ) { 1563 return; 1564 } 1565 1566 var menuHTML = $(this.nodeClass).find( '#pp-menu-' + this.settingsId ).html(); 1567 1568 if ( null === this.fullScreenMenu ) { 1569 this.fullScreenMenu = $('<div id="pp-advanced-menu-full-screen-'+this.settingsId+'" class="fl-node-'+this.settingsId+' pp-menu-full-screen" />').html( menuHTML ); 1570 } 1571 if ( $('#pp-advanced-menu-full-screen-'+this.settingsId).length === 0 && null !== this.fullScreenMenu && ! this.isBuilderActive ) { 1572 this.fullScreenMenu.appendTo( 'body' ); 1573 } 1574 1575 $(this.nodeClass).trigger('pp-advanced-menu-full-screen-init', [this.fullScreenMenu]); 1576 1577 this._toggleMenu(); 1578 }, 1579 1580 /** 1581 * Trigger the toggle event for off-canvas 1582 * and full-screen overlay menus. 1583 * 1584 * @since 1.2.8 1585 * @return void 1586 */ 1587 _toggleMenu: function() { 1588 var self = this; 1589 var singleInstance = true; 1590 if( self.mobileMenuType === 'full-screen' ) { 1591 var winHeight = window.innerHeight; 1592 $(self.nodeClass).find('.pp-menu-overlay').css('height', winHeight + 'px'); 1593 $(window).on('resize', function() { 1594 winHeight = window.innerHeight; 1595 $(self.nodeClass).find('.pp-menu-overlay').css('height', winHeight + 'px'); 1596 }); 1597 } 1598 1599 // Toggle Click 1600 var toggleEvent = ('ontouchend' in window) && this._isIOS() ? 'touchend' : 'click'; 1601 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle' ).off(toggleEvent).on( toggleEvent, function() { 1602 if ( singleInstance ) { 1603 if ( $('.pp-advanced-menu.menu-open').length > 0 ) { 1604 $('.pp-advanced-menu').removeClass('menu-open'); 1605 $('html').removeClass('pp-full-screen-menu-open'); 1606 } 1607 } 1608 if( $(self.nodeClass).find('.pp-advanced-menu').hasClass('menu-open') ) { 1609 $(self.nodeClass).find('.pp-advanced-menu').removeClass('menu-open'); 1610 $(self.nodeClass).find('.pp-advanced-menu').addClass('menu-close'); 1611 $('html').removeClass('pp-off-canvas-menu-open'); 1612 $('html').removeClass('pp-full-screen-menu-open'); 1613 } else { 1614 $(self.nodeClass).find('.pp-advanced-menu').addClass('menu-open'); 1615 if( self.mobileMenuType === 'off-canvas' ) { 1616 $('html').addClass('pp-off-canvas-menu-open'); 1617 self.offCanvasMenu.find('nav').attr('tabindex', '0').trigger( 'focus' ); 1618 $(this).attr( 'tabindex', '-1' ).trigger( 'blur' ); 1619 } 1620 if( self.mobileMenuType === 'full-screen' ) { 1621 $('html').addClass('pp-full-screen-menu-open'); 1622 self.fullScreenMenu.find('nav').attr('tabindex', '0').trigger( 'focus' ); 1623 $(this).attr( 'tabindex', '-1' ).trigger( 'blur' ); 1624 } 1625 } 1626 1627 if ( '0' == $(this).attr('tabindex') ) { 1628 $(this).attr('aria-expanded', 'false'); 1629 } else { 1630 $(this).attr('aria-expanded', 'true'); 1631 } 1632 } ); 1633 1634 // iOS Safari "hover" fix. 1635 // This is needed to ensure the click event works properly on iOS devices since they treat the first tap as a hover event, 1636 // which can interfere with the intended toggle behavior of the menu. 1637 // $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle' ).on( 'touchstart', function(e) { 1638 // e.preventDefault(); 1639 // e.stopPropagation(); 1640 // $(this).trigger('click'); 1641 // } ); 1642 1643 // Keyboard navigation. 1644 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle').on('keyup', function(e) { 1645 if ( 13 === e.keyCode || 13 === e.which ) { 1646 $(this).trigger('click'); 1647 } 1648 }); 1649 1650 // Close button click 1651 $(self.nodeClass).find('.pp-advanced-menu .pp-menu-close-btn, .pp-clear').on( 'click', function() { 1652 $(self.nodeClass).find('.pp-advanced-menu').removeClass('menu-open'); 1653 $(self.nodeClass).find('.pp-advanced-menu').addClass('menu-close'); 1654 $('html').removeClass('pp-off-canvas-menu-open'); 1655 $('html').removeClass('pp-full-screen-menu-open'); 1656 1657 if ( $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle' ).is( ':visible' ) ) { 1658 setTimeout(function() { 1659 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle' ) 1660 .attr( 'tabindex', 0 ) 1661 .attr( 'aria-expanded', 'false' ) 1662 .trigger( 'focus' ); 1663 }, 120); 1664 } 1665 1666 if ( self.offCanvasMenu && self.offCanvasMenu.length > 0 ) { 1667 self.offCanvasMenu.find('nav').attr('tabindex', '-1').trigger( 'blur' ); 1668 } 1669 if ( self.fullScreenMenu && self.fullScreenMenu.length > 0 ) { 1670 self.fullScreenMenu.find('nav').attr('tabindex', '-1').trigger( 'blur' ); 1671 } 1672 } ); 1673 1674 if ( this.isBuilderActive ) { 1675 setTimeout(function() {
1676 if ( $('.fl-builder-settings[data-node="'+self.settingsId+'"]').length > 0 ) { 1677 $('.pp-advanced-menu').removeClass('menu-open'); 1678 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle').trigger('click'); 1679 } 1680 }, 600); 1681 1682 FLBuilder.addHook('settings-form-init', function() { 1683 if ( ! $('.fl-builder-settings[data-node="'+self.settingsId+'"]').length > 0 ) { 1684 return; 1685 } 1686 if ( ! $(self.nodeClass).find('.pp-advanced-menu').hasClass('menu-open') ) { 1687 $('.pp-advanced-menu').removeClass('menu-open'); 1688 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle').trigger('click'); 1689 } 1690 }); 1691 1692 if ( $('html').hasClass('pp-full-screen-menu-open') && ! $(self.nodeClass).find('.pp-advanced-menu').hasClass('menu-open') ) { 1693 $('html').removeClass('pp-full-screen-menu-open'); 1694 } 1695 if ( $('html').hasClass('pp-off-canvas-menu-open') && ! $(self.nodeClass).find('.pp-advanced-menu').hasClass('menu-open') ) { 1696 $('html').removeClass('pp-off-canvas-menu-open'); 1697 } 1698 } 1699 }, 1700 1701 /** 1702 * Check to see if Below Row should be enabled. 1703 * 1704 * @since 2.8.0 1705 * @return boolean 1706 */ 1707 _isMobileBelowRowEnabled: function() { 1708 if (this.mobileMenuType === 'default') { 1709 return this.mobileBelowRow && $( this.nodeClass ).closest( '.fl-col' ).length; 1710 } 1711 return false; 1712 }, 1713 1714 /** 1715 * Logic for putting the mobile menu below the menu's 1716 * column so it spans the full width of the page. 1717 * 1718 * @since 2.2 1719 * @return void 1720 */ 1721 _placeMobileMenuBelowRow: function () { 1722 1723 if ($(this.nodeClass + '-clone').length) { 1724 return; 1725 } 1726 // if ( $('html').hasClass( 'fl-builder-edit' ) ) { 1727 // return; 1728 // } 1729 1730 var module = $(this.nodeClass), 1731 clone = null, 1732 row = module.closest('.fl-row-content'); 1733 1734 if ( module.length < 1 ) { 1735 return; 1736 } 1737 1738 clone = ( module.length > 1 ) ? $( module[0] ).clone() : module.clone(); 1739 module.find('.pp-menu-nav').remove(); 1740 clone.addClass((this.nodeClass + '-clone').replace('.', '')); 1741 clone.addClass('pp-menu-mobile-clone'); 1742 clone.find('.pp-advanced-menu-mobile').remove(); 1743 row.append(clone); 1744 1745 // Removes animation when enabled. 1746 if ( module.hasClass( 'fl-animation' ) ) { 1747 clone.removeClass( 'fl-animation' ); 1748 } 1749 1750 this._menuOnClick(); 1751 }, 1752 1753 /** 1754 * Logic for removing the mobile menu from below the menu's 1755 * column and putting it back in the main wrapper. 1756 * 1757 * @since 2.2 1758 * @return void 1759 */ 1760 _removeMenuFromBelowRow: function () { 1761 1762 if (!$(this.nodeClass + '-clone').length) { 1763 return; 1764 } 1765 1766 var module = $(this.nodeClass), 1767 clone = $(this.nodeClass + '-clone'), 1768 menu = clone.find('.pp-menu-nav'); 1769 1770 module.find('.pp-advanced-menu-mobile').after(menu); 1771 module.find('.pp-advanced-menu-mobile-toggle').attr( 'aria-expanded', false ); 1772 clone.remove(); 1773 }, 1774 1775 _toggleMenuSearch: function() { 1776 var items = $( this.wrapperClass ).find( '.pp-menu-search-item' ), 1777 self = this; 1778 1779 items.each( function() { 1780 var item = $(this); 1781 var button = item.find( '> a' ), 1782 form = item.find( '.pp-search-form' ), 1783 input = item.find('.pp-search-form__input'); 1784 1785 button.on( 'click', function(e) { 1786 e.preventDefault(); 1787 item.toggleClass( 'pp-search-active' ); 1788 if ( item.hasClass( 'pp-search-active' ) ) { 1789 setTimeout( function() { 1790 input.focus(); 1791 self._focusMenuSearch( input ); 1792 }, 100 ); 1793 } 1794 1795 $('body').on( 'click.pp-menu-search', self._hideMenuSearch.bind( self ) ); 1796 } ); 1797 1798 input.on( 'focus', function() { 1799 form.addClass( 'pp-search-form--focus' ); 1800 } ).on( 'blur', function() { 1801 form.removeClass( 'pp-search-form--focus' ); 1802 } ); 1803 1804 // Close search form on ESC key press. 1805 input.on( 'keyup', function(e) { 1806 if ( e.key === 'Escape' || e.keyCode === 27 ) { 1807 item.removeClass( 'pp-search-active' ); 1808 $('body').off('click.pp-menu-search'); 1809 button.delay(100).focus(); 1810 } 1811 } ); 1812 } ); 1813 }, 1814 1815 _hideMenuSearch: function(e) { 1816 if (e !== undefined) { 1817 if ($(e.target).closest('.pp-menu-search-item').length > 0) { 1818 return; 1819 } 1820 } 1821 1822 $( this.wrapperClass ).find( '.pp-menu-search-item' ).removeClass( 'pp-search-active' ); 1823 $('body').off('click.pp-menu-search'); 1824 }, 1825 1826 _focusMenuSearch: function( $el ) { 1827 // If this function exists... (IE 9+) 1828 if ( $el[0].setSelectionRange ) { 1829 // Double the length because Opera is inconsistent about whether a carriage return is one character or tw
1829o. 1830 var len = $el.val().length * 2; 1831 1832 // Timeout seems to be required for Blink 1833 setTimeout(function() { 1834 $el[0].setSelectionRange( len, len ); 1835 }, 1); 1836 } else { 1837 // As a fallback, replace the contents with itself 1838 // Doesn't work in Chrome, but Chrome supports setSelectionRange 1839 $el.val( $el.val() ); 1840 } 1841 }, 1842 1843 /** 1844 * Adds menu node and post ID to WooCommerce ajax URL requests. 1845 * 1846 * @since 2.20 1847 * @return void 1848 */ 1849 _wooUpdateParams: function() { 1850 if ( 'undefined' !== typeof wc_cart_fragments_params ) { 1851 wc_cart_fragments_params.wc_ajax_url += '&pp-advanced-menu-node='+ this.settingsId +'&post-id='+ this.postId; 1852 } 1853 if ( 'undefined' !== typeof wc_add_to_cart_params ) { 1854 wc_add_to_cart_params.wc_ajax_url += '&pp-advanced-menu-node='+ this.settingsId +'&post-id='+ this.postId; 1855 } 1856 }, 1857 1858 _validClick: function(e) { 1859 return (e.which == 1 || e.which == 13 || e.which == 32 || e.which == undefined) ? true : false; 1860 } 1861 1862 }; 1863 1864})(jQuery); 1865 1866var pp_menu_5c5816cad1308; 1867(function($) { 1868 1869 pp_menu_5c5816cad1308 = new PPAdvancedMenu({ 1870 id: '5c5816cad1308', 1871 type: 'horizontal', 1872 mobile: 'hamburger', 1873 menuPosition: 'below', 1874 breakpoints: { 1875 large: 1200, 1876 medium: 1024, 1877 small: 750, 1878 custom: 768 }, 1879 mobileBreakpoint: 'medium-mobile', 1880 mediaBreakpoint: '1024', 1881 mobileMenuType: 'off-canvas', 1882 offCanvasDirection: 'left', 1883 fullScreenAnimation: '', 1884 isBuilderActive: false }); 1885 1886})(jQuery); 1887jQuery(function($) { 1888 1889 $(function() { 1890 $( '.fl-node-5c5816d338e2a .fl-photo-img' ) 1891 .on( 'mouseenter', function( e ) { 1892 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 1893 } ) 1894 .on( 'mouseleave', function( e ){ 1895 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 1896 } ); 1897 }); 1898 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 1899}); 1900 1901;/** 1902 * This file should contain frontend logic for 1903 * all module instances. 1904 */ 1905/* Start Layout Custom JS */ 1906 1907/* End Layout Custom JS */ 1908 1909(function($){ 1910 1911 /** 1912 * Helper class for header layout logic. 1913 * 1914 * @since 1.0 1915 * @class FLThemeBuilderHeaderLayout 1916 */ 1917 FLThemeBuilderHeaderLayout = { 1918 1919 /** 1920 * A reference to the window object for this page. 1921 * 1922 * @since 1.0 1923 * @property {Object} win 1924 */ 1925 win : null, 1926 1927 /** 1928 * A reference to the body object for this page. 1929 * 1930 * @since 1.0 1931 * @property {Object} body 1932 */ 1933 body : null, 1934 1935 /** 1936 * A reference to the header object for this page. 1937 * 1938 * @since 1.0 1939 * @property {Object} header 1940 */ 1941 header : null, 1942 1943 /** 1944 * Whether this header overlays the content or not. 1945 * 1946 * @since 1.0 1947 * @property {Boolean} overlay 1948 */ 1949 overlay : false, 1950 1951 /** 1952 * Whether the page has the WP admin bar or not. 1953 * 1954 * @since 1.0 1955 * @property {Boolean} hasAdminBar 1956 */ 1957 hasAdminBar : false, 1958 1959 /** 1960 * Breakpoint for when the sticky header should apply. 1961 * 1962 * @since 1.4 1963 * @property {String} stickyOn 1964 */ 1965 stickyOn: '', 1966 1967 /** 1968 * A reference of the sticky and shrink header breakpoint. 1969 * 1970 * @since 1.2.5 1971 * @property {Number} breakpointWidth 1972 */ 1973 breakpointWidth: 0, 1974 1975 /** 1976 * Whether this header can be pinned from page load. 1977 * 1978 * @since 1.6.1 1979 * @property {Boolean} pinnable 1980 */ 1981 pinnable : false, 1982 1983 /** 1984 * Initializes header layout logic. 1985 * 1986 * @since 1.0 1987 * @method init 1988 */ 1989 init: function() 1990 { 1991 var editing = $( 'html.fl-builder-edit' ).length, 1992 header = $( '.fl-builder-content[data-type=header]' ), 1993 menuModule = header.find( '.fl-module-menu' ), 1994 breakpoint = null, 1995 adminBarHeight = 0; 1996 1997 if ( ! editing && header.length ) { 1998 1999 header.imagesLoaded( $.proxy( function() { 2000 2001 this.win = $( window ); 2002 this.body = $( 'body' ); 2003 this.header = header.eq( 0 ); 2004 this.overlay = !! Number( header.attr( 'data-overlay' ) ); 2005 this.hasAdminBar = !! $( 'body.admin-bar' ).length; 2006 this.stickyOn = this.header.data( 'sticky-on' ); 2007 breakpoint = this.header.data( 'sticky-breakpoint' ); 2008 2009 if ( '' == this.stickyOn ) { 2010 if ( typeof FLBuilderLayoutConfig.breakpoints[ breakpoint ] !== undefined ) { 2011 this.breakpointWidth = FLBuilderLayoutConfig.breakpoints[ breakpoint ]; 2012 } 2013 else { 2014 this.breakpointWidth = FLBuilderLayoutConfig.breakpoints.medium; 2015 } 2016 } 2017 2018 if ( Number( header.attr( 'data-sticky' ) ) ) { 2019 2020 this.header.data( 'original-top', this.header.offset().top ); 2021 2022 // The pin decision is made once here, while the header offset and the admin bar height are read from the same layout. 2023 adminBarHeight = $( '#wpadminbar' ).length ? $( '#wpadminbar' ).outerHeight() : 0; 2024 this.pinnable = this.overlay && this.header.data( 'original-top' ) <= adminBarHeight; 2025 2026 this.win.on( 'resize', $.throttle( 500, $.proxy( this._initSticky, this ) ) ); 2027 this._initSticky(); 2028 2029 } 2030 2031 }, this ) ); 2032 } 2033 }, 2034 2035 /** 2036 * Initializes sticky logic for a header. 2037 * 2038 * @since 1.0 2039 * @access private 2040 * @method _initSticky 2041 */ 2042 _initSticky: function( e ) 2043 {
2044 var header = $('.fl-builder-content[data-type=header]'), 2045 windowSize = this.win.width(), 2046 makeSticky = false; 2047 2048 makeSticky = this._makeWindowSticky( windowSize ); 2049 if ( makeSticky || ( this.breakpointWidth > 0 && windowSize >= this.breakpointWidth ) ) { 2050 this.win.on( 'scroll.fl-theme-builder-header-sticky', $.proxy( this._doSticky, this ) ); 2051 this._initPin(); 2052 2053 // Apply the sticky state on initial load when the page is 2054 // already scrolled past the header â e.g. when the browser 2055 // restores the scroll position on refresh. Overlay headers are 2056 // out of scope here; this mirrors the shrink-on-load behavior 2057 // in _initShrink(). 2058 if ( ! e && ! this.overlay && ! this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 2059 var loadWinTop = this.win.scrollTop(), 2060 loadHeaderTop = Math.floor( this.header.data( 'original-top' ) ); 2061 2062 if ( this.hasAdminBar && windowSize > 600 ) { 2063 loadWinTop += Math.floor( $( '#wpadminbar' ).outerHeight() ); 2064 } 2065 2066 if ( loadWinTop > loadHeaderTop ) { 2067 this.header.addClass( 'fl-theme-builder-header-sticky' ); 2068 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 2069 this._adjustHeaderHeight(); 2070 this._adjustStickyHeaderWidth(); 2071 } 2072 } 2073 2074 // 2075 // Check if Event Type is 'resize' then invoke this._doSticky() 2076 // only if the 'fl-theme-builder-header-sticky' class is already present. 2077 // 2078 if ( e && 'resize' === e.type ) { 2079 if ( this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 2080 this._doSticky( e ); 2081 } 2082 this._adjustStickyHeaderWidth(); 2083 } 2084 2085 if ( Number( header.attr( 'data-shrink' ) ) ) { 2086 this.header.data( 'original-height', this.header.outerHeight() ); 2087 this.win.on( 'resize', $.throttle( 500, $.proxy( this._initShrink, this ) ) ); 2088 this._initShrink(); 2089 } 2090 2091 this._initFlyoutMenuFix( e ); 2092 } else { 2093 this.win.off( 'scroll.fl-theme-builder-header-sticky' ); 2094 this.win.off( 'resize.fl-theme-builder-header-sticky' ); 2095 2096 this.header.removeClass( 'fl-theme-builder-header-sticky' ); 2097 this.header.removeClass( 'fl-theme-builder-header-pinned' ); 2098 this.header.removeAttr( 'style' ); 2099 this.header.parent().css( 'padding-top', '0' ); 2100 } 2101 }, 2102 2103 /** 2104 * Pins an overlay header with fixed positioning from page load, avoiding a position change that a scroll handler cannot apply before the compositor paints. 2105 * 2106 * @since 1.6.1 2107 * @access private 2108 * @method _initPin 2109 */ 2110 _initPin: function() 2111 { 2112 this.header.toggleClass( 'fl-theme-builder-header-pinned', this.pinnable ); 2113 2114 if ( ! this.pinnable ) { 2115 return; 2116 } 2117 2118 // Fixed positioning resolves the width against the viewport, so boxed layouts require their maximum width immediately. 2119 this._adjustStickyHeaderWidth(); 2120 2121 // The header is visible from the first paint, so the scrolled state must reflect any restored scroll position. 2122 if ( this.win.scrollTop() > Math.floor( this.header.data( 'original-top' ) ) ) { 2123 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 2124 } 2125 }, 2126 2127 /** 2128 * Check if Header should be sticky at a particular Window size. 2129 * 2130 * @since 1.4 2131 * @access private 2132 * @param widowSize 2133 * @method _makeWindowSticky 2134 */ 2135 _makeWindowSticky: function ( windowSize ) 2136 { 2137 var makeSticky = false; 2138 2139 switch (this.stickyOn) { 2140 case 'xl': 2141 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['large']; 2142 break; 2143 case '': // Default 2144 case 'desktop': 2145 makeSticky = windowSize >= FLBuilderLayoutConfig.breakpoints['medium']; 2146 break; 2147 case 'desktop-medium': 2148 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small']; 2149 break; 2150 case 'large': 2151 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['medium'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large']; 2152 break; 2153 case 'large-medium': 2154 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large']; 2155 break; 2156 case 'medium': 2157 makeSticky = ( windowSize <= FLBuilderLayoutConfig.breakpoints['medium'] && windowSize > FLBuilderLayoutConfig.breakpoints['small'] ); 2158 break; 2159 case 'medium-mobile':
2160 makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['medium']); 2161 break; 2162 case 'mobile': 2163 makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['small']); 2164 break; 2165 case 'all': 2166 makeSticky = true; 2167 break; 2168 } 2169 2170 return makeSticky; 2171 }, 2172 2173 /** 2174 * Sticks the header when the page is scrolled. 2175 * 2176 * @since 1.0 2177 * @access private 2178 * @method _doSticky 2179 */ 2180 _doSticky: function( e ) 2181 { 2182 var winTop = Math.floor( this.win.scrollTop() ), 2183 headerTop = Math.floor( this.header.data( 'original-top' ) ), 2184 hasStickyClass = this.header.hasClass( 'fl-theme-builder-header-sticky' ), 2185 hasScrolledClass = this.header.hasClass( 'fl-theme-builder-header-scrolled' ), 2186 beforeHeader = this.header.prevAll( '.fl-builder-content' ), 2187 bodyTopPadding = parseInt( jQuery('body').css('padding-top') ), 2188 winBarHeight = $('#wpadminbar').length ? $('#wpadminbar').outerHeight() : 0, 2189 headerHeight = 0; 2190 2191 if ( isNaN( bodyTopPadding ) ) { 2192 bodyTopPadding = 0; 2193 } 2194 2195 if ( this.hasAdminBar && this.win.width() > 600 ) { 2196 winTop += Math.floor( winBarHeight ); 2197 } 2198 2199 if ( winTop > headerTop ) { 2200 if ( ! hasStickyClass ) { 2201 if ( e && ( 'scroll' === e.type || 'smartscroll' === e.type ) ) { 2202 this.header.addClass( 'fl-theme-builder-header-sticky' ); 2203 if ( this.overlay && beforeHeader.length ) { 2204 this.header.css( 'top', winBarHeight); 2205 } 2206 } 2207 2208 if ( ! this.overlay ) { 2209 this._adjustHeaderHeight(); 2210 } 2211 } 2212 } 2213 else if ( hasStickyClass ) { 2214 this.header.removeClass( 'fl-theme-builder-header-sticky' ); 2215 this.header.removeAttr( 'style' ); 2216 this.header.parent().css( 'padding-top', '0' ); 2217 } 2218 2219 this._adjustStickyHeaderWidth(); 2220 2221 if ( winTop > headerTop ) { 2222 if ( ! hasScrolledClass ) { 2223 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 2224 } 2225 } else if ( hasScrolledClass ) { 2226 this.header.removeClass( 'fl-theme-builder-header-scrolled' ); 2227 } 2228 2229 this._flyoutMenuFix( e ); 2230 }, 2231 2232 /** 2233 * Initializes flyout menu fixes on sticky header. 2234 * 2235 * @since 1.4.1 2236 * @method _initFlyoutMenuFix 2237 */ 2238 _initFlyoutMenuFix: function( e ) { 2239 var header = this.header, 2240 menuModule = header.closest( '.fl-menu' ), 2241 flyoutMenu = menuModule.find( '.fl-menu-mobile-flyout' ), 2242 isPushMenu = menuModule.hasClass( 'fl-menu-responsive-flyout-push' ) || menuModule.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 2243 isOverlay = menuModule.hasClass( 'fl-menu-responsive-flyout-overlay' ), 2244 flyoutPos = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 2245 flyoutParent = header.parent().is( 'header' ) ? header.parent().parent() : header.parent(); 2246 isFullWidth = this.win.width() === header.width(), 2247 flyoutLayout = '', 2248 activePos = 250, 2249 headerPos = 0; 2250 2251 if ( ! flyoutMenu.length ) { 2252 return; 2253 } 2254 2255 if ( this.win.width() > header.parent().width() ) { 2256 headerPos = ( this.win.width() - header.width() ) / 2; 2257 } 2258 2259 if ( isOverlay ) { 2260 activePos = headerPos; 2261 } 2262 else if ( isPushMenu ) { 2263 activePos = activePos + headerPos; 2264 } 2265 flyoutMenu.data( 'activePos', activePos ); 2266 2267 if ( isPushMenu ) { 2268 flyoutLayout = 'push-' + flyoutPos; 2269 } 2270 else if ( isOverlay ) { 2271 flyoutLayout = 'overlay-' + flyoutPos; 2272 } 2273 2274 if ( isPushMenu && ! $( 'html' ).hasClass( 'fl-theme-builder-has-flyout-menu' ) ) { 2275 $( 'html' ).addClass( 'fl-theme-builder-has-flyout-menu' ); 2276 } 2277 2278 if ( ! flyoutParent.hasClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ) ) { 2279 flyoutParent.addClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ); 2280 } 2281 2282 if ( ! header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && isOverlay ) { 2283 header.addClass( 'fl-theme-builder-flyout-menu-overlay' ); 2284 } 2285 2286 if ( ! header.hasClass( 'fl-theme-builder-header-full-width' ) && isFullWidth ) { 2287 header.addClass( 'fl-theme-builder-header-full-width' ); 2288 } 2289 else if ( ! isFullWidth ) { 2290 header.removeClass( 'fl-theme-builder-header-full-width' ); 2291 } 2292 2293 menuModule.on( 'click', '.fl-menu-mobile-toggle', $.proxy( function( event ){ 2294 if ( menuModule.find( '.fl-menu-mobile-toggle.fl-active' ).length ) {
2295 $( 'html' ).addClass( 'fl-theme-builder-flyout-menu-active' ); 2296 event.stopImmediatePropagation(); 2297 } 2298 else { 2299 $( 'html' ).removeClass( 'fl-theme-builder-flyout-menu-active' ); 2300 } 2301 2302 this._flyoutMenuFix( event ); 2303 }, this ) ); 2304 }, 2305 2306 /** 2307 * Fix flyout menu inside the sticky header. 2308 * 2309 * @since 1.4.1 2310 * @method _flyoutMenuFix 2311 */ 2312 _flyoutMenuFix: function( e ){ 2313 var header = this.header, 2314 menuModule = $( e.target ).closest( '.fl-menu' ), 2315 flyoutMenu = menuModule.find( '.fl-menu-mobile-flyout' ), 2316 flyoutPos = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 2317 menuOpacity = menuModule.find( '.fl-menu-mobile-opacity' ), 2318 isScroll = 'undefined' !== typeof e && 'scroll' === e.handleObj.type, 2319 activePos = 'undefined' !== typeof flyoutMenu.data( 'activePos' ) ? flyoutMenu.data( 'activePos' ) : 0, 2320 headerPos = ( this.win.width() - header.width() ) / 2, 2321 inactivePos = headerPos > 0 ? activePos + 4 : 254; 2322 2323 if ( ! flyoutMenu.length ) { 2324 return; 2325 } 2326 2327 if ( this.overlay ) { 2328 return; 2329 } 2330 2331 if( $( '.fl-theme-builder-flyout-menu-active' ).length ) { 2332 2333 if ( isScroll && ! flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) { 2334 flyoutMenu.addClass( 'fl-menu-disable-transition' ); 2335 } 2336 2337 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 2338 if ( ! isScroll ) { 2339 setTimeout( $.proxy( function(){ 2340 flyoutMenu.css( flyoutPos, '-' + activePos + 'px' ); 2341 }, this ), 1 ); 2342 } 2343 else { 2344 flyoutMenu.css( flyoutPos, '-' + activePos + 'px' ); 2345 } 2346 } 2347 else { 2348 flyoutMenu.css( flyoutPos, '0px' ); 2349 } 2350 } 2351 else { 2352 if ( flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) { 2353 flyoutMenu.removeClass( 'fl-menu-disable-transition' ); 2354 } 2355 2356 if ( header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && headerPos > 0 && headerPos < 250 ) { 2357 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 2358 inactivePos = headerPos + 254; 2359 } 2360 else { 2361 inactivePos = 254; 2362 } 2363 } 2364 2365 if ( e && e.type === 'resize' ) { 2366 inactivePos = headerPos + 254; 2367 } 2368 2369 flyoutMenu.css( flyoutPos, '-' + inactivePos + 'px' ); 2370 } 2371 2372 if ( e && menuModule.is('.fl-menu-responsive-flyout-overlay') && $.infinitescroll ) { 2373 e.stopImmediatePropagation(); 2374 } 2375 2376 if( menuOpacity.length ) { 2377 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 2378 if ( '0px' === menuOpacity.css( 'left' ) ) { 2379 menuOpacity.css( 'left', '-' + headerPos + 'px' ); 2380 } 2381 } 2382 else { 2383 menuOpacity.css( 'left', '' ); 2384 } 2385 } 2386 }, 2387 2388 /** 2389 * Adjust sticky header width if BB Theme Boxed Layout is used. 2390 * 2391 * @since 1.4 2392 * @access private 2393 * @method _adjustStickyHeaderWidth 2394 */ 2395 _adjustStickyHeaderWidth: function () { 2396 if ( $('body').hasClass( 'fl-fixed-width' ) ) { 2397 var parentWidth = this.header.parent().width(); 2398 2399 // Better if this is set in the stylesheet file. 2400 if ( this.win.width() >= 992 ) { 2401 this.header.css({ 2402 'margin': '0 auto', 2403 'max-width': parentWidth, 2404 }); 2405 } 2406 else { 2407 this.header.css({ 2408 'margin': '', 2409 'max-width': '', 2410 }); 2411 } 2412 } 2413 }, 2414 2415 /** 2416 * Adjust Sticky Header Height 2417 * 2418 * @since 1.4 2419 * @access private 2420 * @method _adjustHeaderHeight 2421 */ 2422 _adjustHeaderHeight: function () { 2423 var beforeHeader = this.header.prevAll('.fl-builder-content'), 2424 beforeHeaderHeight = 0, 2425 beforeHeaderFix = 0, 2426 headerHeight = Math.floor( this.header.outerHeight() ), 2427 bodyTopPadding = parseInt( $( 'body' ).css( 'padding-top' ) ), 2428 wpAdminBarHeight = 0, 2429 totalHeaderHeight = 0; 2430 2431 if ( isNaN( bodyTopPadding ) ) { 2432 bodyTopPadding = 0; 2433 } 2434 2435 if ( beforeHeader.length ) { 2436 $.each( beforeHeader, function() { 2437 beforeHeaderHeight += Math.floor( $(this).outerHeight() ); 2438 }); 2439 // Subtract this value from the header parent's top padding. 2440 beforeHeaderFix = 2; 2441 } 2442 2443 if ( this.hasAdminBar && this.win.width() <= 600 ) { 2444 wpAdminBarHeight = Math.floor( $('#wpadminbar').outerHeight() ); 2445 } 2446 2447 totalHeaderHeight = Math.floor( beforeHeaderHeight + headerHeight); 2448 2449 if ( headerHeight > 0 ) { 2450 var headerParent = this.header.parent(), 2451 headerParentTopPadding = 0; 2452 2453 // If the header's parent container is the BODY tag ignore its top padding. 2454 if ( $( headerParent ).is('body') ) { 2455 headerParentTopPadding = Math.floor( headerHeight - wpAdminBarHeight ); 2456 } else { 2457 headerParentTopPadding = Math.floor( headerHeight - bodyTopPadding - wpAdminBarHeight ); 2458 } 2459 2460 $( headerParent ).css( 'padding-top', ( headerParentTopPadding - beforeHeaderFix ) + 'px' ); 2461 2462 this.header.css({ 2463 '-webkit-transform': 'translate(0px, -' + totalHeaderHeight + 'px)', 2464 '-ms-transform': 'translate(0px, -' + totalHeaderHeight + 'px)', 2465 'transform': 'translate(0px, -' + totalHeaderHeight + 'px)' 2466 }); 2467 2468 } 2469 2470 }, 2471 2472 /** 2473 * Initializes shrink logic for a header. 2474 * 2475 * @since 1.0 2476 * @access private 2477 * @method _initShrink 2478 */ 2479 _initShrink: function( e ) 2480 { 2481 if ( this.win.width() >= this.breakpointWidth ) {
2482 this.win.on( 'scroll.fl-theme-builder-header-shrink', $.proxy( this._doShrink, this ) ); 2483 this._setImageMaxHeight(); 2484 2485 if ( this.win.scrollTop() > 0 ){ 2486 this._doShrink(); 2487 } 2488 2489 } else { 2490 this.header.parent().css( 'padding-top', '0' ); 2491 this.win.off( 'scroll.fl-theme-builder-header-shrink' ); 2492 this._removeShrink(); 2493 this._removeImageMaxHeight(); 2494 } 2495 }, 2496 2497 /** 2498 * Shrinks the header when the page is scrolled. 2499 * 2500 * @since 1.0 2501 * @access private 2502 * @method _doShrink 2503 */ 2504 _doShrink: function( e ) 2505 { 2506 var winTop = this.win.scrollTop(), 2507 headerTop = this.header.data('original-top'), 2508 headerHeight = this.header.data('original-height'), 2509 shrinkImageHeight = this.header.data('shrink-image-height'), 2510 windowSize = this.win.width(), 2511 makeSticky = this._makeWindowSticky( windowSize ), 2512 hasClass = this.header.hasClass( 'fl-theme-builder-header-shrink' ); 2513 2514 2515 if ( this.hasAdminBar ) { 2516 winTop += 32; 2517 } 2518 2519 if ( makeSticky && ( winTop > headerTop + headerHeight ) ) { 2520 if ( ! hasClass ) { 2521 2522 this.header.addClass( 'fl-theme-builder-header-shrink' ); 2523 2524 // Shrink images but don't include lightbox and menu images. 2525 this.header.find('img').each( function( i ) { 2526 var image = $( this ), 2527 maxMegaMenu = image.closest( '.max-mega-menu' ).length, 2528 imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length, 2529 imageInNavMenu = image.closest( 'li.menu-item' ).length; 2530 2531 if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) { 2532 image.css( 'max-height', shrinkImageHeight ); 2533 } 2534 2535 }); 2536 2537 this.header.find( '.fl-row-content-wrap' ).each( function() { 2538 2539 var row = $( this ); 2540 2541 if ( parseInt( row.css( 'padding-bottom' ) ) > 5 ) { 2542 row.addClass( 'fl-theme-builder-header-shrink-row-bottom' ); 2543 } 2544 2545 if ( parseInt( row.css( 'padding-top' ) ) > 5 ) { 2546 row.addClass( 'fl-theme-builder-header-shrink-row-top' ); 2547 } 2548 } ); 2549 2550 this.header.find( '.fl-module' ).each( function() { 2551 2552 var module = $( this ).find( '.fl-module-content' ).length ? $( this ).find( '.fl-module-content' ) : $( this ); 2553 2554 if ( parseInt( module.css( 'margin-bottom' ) ) > 5 ) { 2555 module.addClass( 'fl-theme-builder-header-shrink-module-bottom' ); 2556 } 2557 2558 if ( parseInt( module.css( 'margin-top' ) ) > 5 ) { 2559 module.addClass( 'fl-theme-builder-header-shrink-module-top' ); 2560 } 2561 } ); 2562 } 2563 } else if (hasClass) { 2564 this.header.find( 'img' ).css( 'max-height', '' ); 2565 this._removeShrink(); 2566 } 2567 2568 // Fixes Shrink header issue with BB Theme when window is scrolled then resized and back. 2569 if ( 'undefined' === typeof( e ) && $('body').hasClass( 'fl-fixed-width' ) ) { 2570 if ( ! this.overlay ) { 2571 this._adjustHeaderHeight(); 2572 } 2573 } 2574 2575 }, 2576 2577 /** 2578 * Removes the header shrink effect. 2579 * 2580 * @since 1.0 2581 * @access private 2582 * @method _removeShrink 2583 */ 2584 _removeShrink: function() 2585 { 2586 var rows = this.header.find( '.fl-row-content-wrap' ), 2587 modules = this.header.find('.fl-module, .fl-module-content'); 2588 2589 rows.removeClass( 'fl-theme-builder-header-shrink-row-bottom' ); 2590 rows.removeClass( 'fl-theme-builder-header-shrink-row-top' ); 2591 modules.removeClass( 'fl-theme-builder-header-shrink-module-bottom' ); 2592 modules.removeClass( 'fl-theme-builder-header-shrink-module-top' ); 2593 this.header.removeClass( 'fl-theme-builder-header-shrink' ); 2594 }, 2595 2596 /** 2597 * Adds max height to images in modules for smooth scrolling. 2598 * 2599 * @since 1.1.1 2600 * @access private 2601 * @method _setImageMaxHeight 2602 */ 2603 _setImageMaxHeight: function() 2604 { 2605 var head = $( 'head' ), 2606 stylesId = 'fl-header-styles-' + this.header.data( 'post-id' ), 2607 styles = '', 2608 images = this.header.find( '.fl-module img' ); 2609 2610 if ( $( '#' + stylesId ).length ) { 2611 return; 2612 } 2613 2614 images.each( function( i ) { 2615 var image = $( this ), 2616 height = image.height(), 2617 node = image.closest( '.fl-module' ).data( 'node' ), 2618 className = 'fl-node-' + node + '-img-' + i, 2619 maxMegaMenu = image.closest( '.max-mega-menu' ).length, 2620 imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length, 2621 imageInNavMenu = image.closest( 'li.menu-item' ).length; 2622 2623 if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) { 2624 image.addClass( className ); 2625 styles += '.' + className + ' { max-height: ' + ( height ? height : image[0].height ) + 'px }'; 2626 } 2627 2628 } ); 2629
2630 if ( '' !== styles ) { 2631 head.append( '<style id="' + stylesId + '">' + styles + '</style>' ); 2632 } 2633 }, 2634 2635 /** 2636 * Removes max height on images in modules for smooth scrolling. 2637 * 2638 * @since 1.1.1 2639 * @access private 2640 * @method _removeImageMaxHeight 2641 */ 2642 _removeImageMaxHeight: function() 2643 { 2644 $( '#fl-header-styles-' + this.header.data( 'post-id' ) ).remove(); 2645 }, 2646 }; 2647 2648 $( function() { FLThemeBuilderHeaderLayout.init(); } ); 2649 2650})(jQuery); 2651 2652/*! 2653 * Bowser - a browser detector 2654 * https://github.com/ded/bowser 2655 * MIT License | (c) Dustin Diaz 2015 2656 */ 2657 2658!function (name, definition) { 2659 if (typeof module != 'undefined' && module.exports) module.exports = definition() 2660 else if (typeof define == 'function' && define.amd) define(name, definition) 2661 else this[name] = definition() 2662}('bowser', function () { 2663 /** 2664 * See useragents.js for examples of navigator.userAgent 2665 */ 2666 2667 var t = true 2668 2669 function detect(ua) { 2670 2671 function getFirstMatch(regex) { 2672 var match = ua.match(regex); 2673 return (match && match.length > 1 && match[1]) || ''; 2674 } 2675 2676 function getSecondMatch(regex) { 2677 var match = ua.match(regex); 2678 return (match && match.length > 1 && match[2]) || ''; 2679 } 2680 2681 var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase() 2682 , likeAndroid = /like android/i.test(ua) 2683 , android = !likeAndroid && /android/i.test(ua) 2684 , nexusMobile = /nexus\s*[0-6]\s*/i.test(ua) 2685 , nexusTablet = !nexusMobile && /nexus\s*[0-9]+/i.test(ua) 2686 , chromeos = /CrOS/.test(ua) 2687 , silk = /silk/i.test(ua) 2688 , sailfish = /sailfish/i.test(ua) 2689 , tizen = /tizen/i.test(ua) 2690 , webos = /(web|hpw)os/i.test(ua) 2691 , windowsphone = /windows phone/i.test(ua) 2692 , windows = !windowsphone && /windows/i.test(ua) 2693 , mac = !iosdevice && !silk && /macintosh/i.test(ua) 2694 , linux = !android && !sailfish && !tizen && !webos && /linux/i.test(ua) 2695 , edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i) 2696 , versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i) 2697 , tablet = /tablet/i.test(ua) 2698 , mobile = !tablet && /[^-]mobi/i.test(ua) 2699 , xbox = /xbox/i.test(ua) 2700 , result 2701 2702 if (/opera|opr|opios/i.test(ua)) { 2703 result = { 2704 name: 'Opera' 2705 , opera: t 2706 , version: versionIdentifier || getFirstMatch(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i) 2707 } 2708 } 2709 else if (/coast/i.test(ua)) { 2710 result = { 2711 name: 'Opera Coast' 2712 , coast: t 2713 , version: versionIdentifier || getFirstMatch(/(?:coast)[\s\/](\d+(\.\d+)?)/i) 2714 } 2715 } 2716 else if (/yabrowser/i.test(ua)) { 2717 result = { 2718 name: 'Yandex Browser' 2719 , yandexbrowser: t 2720 , version: versionIdentifier || getFirstMatch(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i) 2721 } 2722 } 2723 else if (/ucbrowser/i.test(ua)) { 2724 result = { 2725 name: 'UC Browser' 2726 , ucbrowser: t 2727 , version: getFirstMatch(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i) 2728 } 2729 } 2730 else if (/mxios/i.test(ua)) { 2731 result = { 2732 name: 'Maxthon' 2733 , maxthon: t 2734 , version: getFirstMatch(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i) 2735 } 2736 } 2737 else if (/epiphany/i.test(ua)) { 2738 result = { 2739 name: 'Epiphany' 2740 , epiphany: t 2741 , version: getFirstMatch(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i) 2742 } 2743 } 2744 else if (/puffin/i.test(ua)) { 2745 result = { 2746 name: 'Puffin' 2747 , puffin: t 2748 , version: getFirstMatch(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i) 2749 } 2750 } 2751 else if (/sleipnir/i.test(ua)) { 2752 result = { 2753 name: 'Sleipnir' 2754 , sleipnir: t 2755 , version: getFirstMatch(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i) 2756 } 2757 } 2758 else if (/k-meleon/i.test(ua)) { 2759 result = { 2760 name: 'K-Meleon' 2761 , kMeleon: t 2762 , version: getFirstMatch(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i) 2763 } 2764 } 2765 else if (windowsphone) { 2766 result = { 2767 name: 'Windows Phone' 2768 , windowsphone: t 2769 } 2770 if (edgeVersion) { 2771 result.msedge = t 2772 result.version = edgeVersion 2773 } 2774 else { 2775 result.msie = t 2776 result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i) 2777 } 2778 } 2779 else if (/msie|trident/i.test(ua)) { 2780 result = { 2781 name: 'Internet Explorer' 2782 , msie: t 2783 , version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i) 2784 } 2785 } else if (chromeos) { 2786 result = { 2787 name: 'Chrome' 2788 , chromeos: t 2789 , chromeBook: t 2790 , chrome: t 2791 , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 2792 } 2793 } else if (/chrome.+? edge/i.test(ua)) { 2794 result = { 2795 name: 'Microsoft Edge' 2796 , msedge: t 2797 , version: edgeVersion 2798 } 2799 } 2800 else if (/vivaldi/i.test(ua)) { 2801 result = { 2802 name: 'Vivaldi' 2803 , vivaldi: t 2804 , version: getFirstMatch(/vivaldi\/(\d+(\.\d+)?)/i) || versionIdentifier 2805 } 2806 } 2807 else if (sailfish) { 2808 result = { 2809 name: 'Sailfish' 2810 , sailfish: t 2811 , version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i) 2812 } 2813 } 2814 else if (/seamonkey\//i.test(ua)) { 2815 result = { 2816 name: 'SeaMonkey' 2817 , seamonkey: t 2818 , version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i) 2819 } 2820 } 2821 else if (/firefox|iceweasel|fxios/i.test(ua)) { 2822 result = { 2823 name: 'Firefox' 2824 , firefox: t 2825 , version: getFirstMatch(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i) 2826 } 2827 if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) { 2828 result.firefoxos = t 2829 } 2830 } 2831 else if (silk) { 2832 result = { 2833 name: 'Amazon Silk' 2834 , silk: t 2835 , version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i) 2836 } 2837 } 2838 else if (/phantom/i.test(ua)) { 2839 result = { 2840 name: 'PhantomJS' 2841 , phantom: t 2842 , version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i) 2843 } 2844 } 2845 else if (/slimerjs/i.test(ua)) { 2846 result = { 2847 name: 'SlimerJS' 2848 , slimer: t 2849 , version: getFirstMatch(/slimerjs\/(\d+(\.\d+)?)/i) 2850 } 2851 } 2852 else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) { 2853 result = { 2854 name: 'BlackBerry' 2855 , blackberry: t 2856 , version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i) 2857 } 2858 } 2859 else if (webos) { 2860 result = { 2861 name: 'WebOS' 2862 , webos: t 2863 , version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i) 2864 }; 2865 if( /touchpad\//i.test(ua) ){ 2866 result.touchpad = t; 2867 } 2868 } 2869 else if (/bada/i.test(ua)) { 2870 result = { 2871 name: 'Bada' 2872 , bada: t 2873 , version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i) 2874 }; 2875 } 2876 else if (tizen) { 2877 result = { 2878 name: 'Tizen' 2879 , tizen: t 2880 , version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier 2881 }; 2882 } 2883 else if (/qupzilla/i.test(ua)) { 2884 result = { 2885 name: 'QupZilla' 2886 , qupzilla: t 2887 , version: getFirstMatch(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i) || versionIdentifier 2888 } 2889 } 2890 else if (/chromium/i.test(ua)) { 2891 result = { 2892 name: 'Chromium' 2893 , chromium: t 2894 , version: getFirstMatch(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i) || versionIdentifier 2895 } 2896 } 2897 else if (/chrome|crios|crmo/i.test(ua)) { 2898 result = { 2899 name: 'Chrome' 2900 , chrome: t 2901 , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 2902 } 2903 } 2904 else if (android) { 2905 result = { 2906 name: 'Android' 2907 , version: versionIdentifier 2908 } 2909 } 2910 else if (/safari|applewebkit/i.test(ua)) { 2911 result = { 2912 name: 'Safari' 2913 , safari: t 2914 } 2915 if (versionIdentifier) { 2916 result.version = versionIdentifier 2917 } 2918 } 2919 else if (iosdevice) { 2920 result = { 2921 name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod' 2922 } 2923 // WTF: version is not part of user agent in web apps 2924 if (versionIdentifier) { 2925 result.version = versionIdentifier 2926 } 2927 } 2928 else if(/googlebot/i.test(ua)) { 2929 result = { 2930 name: 'Googlebot' 2931 , googlebot: t 2932 , version: getFirstMatch(/googlebot\/(\d+(\.\d+))/i) || versionIdentifier 2933 } 2934 } 2935 else { 2936 result = { 2937 name: getFirstMatch(/^(.*)\/(.*) /), 2938 version: getSecondMatch(/^(.*)\/(.*) /) 2939 }; 2940 } 2941 2942 // set webkit or gecko flag for browsers based on these engines 2943 if (!result.msedge && /(apple)?webkit/i.test(ua)) { 2944 if (/(apple)?webkit\/537\.36/i.test(ua)) { 2945 result.name = result.name || "Blink" 2946 result.blink = t 2947 } else { 2948 result.name = result.name || "Webkit" 2949 result.webkit = t 2950 } 2951 if (!result.version && versionIdentifier) { 2952 result.version = versionIdentifier 2953 } 2954 } else if (!result.opera && /gecko\//i.test(ua)) { 2955 result.name = result.name || "Gecko" 2956 result.gecko = t 2957 result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i) 2958 } 2959 2960 // set OS flags for platforms that have multiple browsers 2961 if (!result.msedge && (android || result.silk)) { 2962 result.android = t 2963 } else if (iosdevice) { 2964 result[iosdevice] = t 2965 result.ios = t 2966 } else if (mac) { 2967 result.mac = t 2968 } else if (xbox) { 2969 result.xbox = t 2970 } else if (windows) { 2971 result.windows = t 2972 } else if (linux) { 2973 result.linux = t 2974 } 2975 2976 // OS version extraction 2977 var osVersion = ''; 2978 if (result.windowsphone) { 2979 osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i); 2980 } else if (iosdevice) { 2981 osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i); 2982 osVersion = osVersion.replace(/[_\s]/g, '.'); 2983 } else if (android) { 2984 osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i); 2985 } else if (result.webos) { 2986 osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i); 2987 } else if (result.blackberry) { 2988 osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i); 2989 } else if (result.bada) { 2990 osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i); 2991 } else if (result.tizen) { 2992 osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i); 2993 } 2994 if (osVersion) { 2995 result.osversion = osVersion; 2996 } 2997 2998 // device type extraction 2999 var osMajorVersion = osVersion.split('.')[0]; 3000 if ( 3001 tablet 3002 || nexusTablet 3003 || iosdevice == 'ipad' 3004 || (android && (osMajorVersion == 3 || (osMajorVersion >= 4 && !mobile))) 3005 || result.silk 3006 ) { 3007 result.tablet = t 3008 } else if ( 3009 mobile 3010 || iosdevice == 'iphone' 3011 || iosdevice == 'ipod' 3012 || android 3013 || nexusMobile 3014 || result.blackberry 3015 || result.webos 3016 || result.bada 3017 ) { 3018 result.mobile = t 3019 } 3020 3021 // Graded Browser Support
vendor: 4,367 bytes, lines 3022-3164
3022 // http://developer.yahoo.com/yui/articles/gbs 3023 if (result.msedge || 3024 (result.msie && result.version >= 10) || 3025 (result.yandexbrowser && result.version >= 15) || 3026 (result.vivaldi && result.version >= 1.0) || 3027 (result.chrome && result.version >= 20) || 3028 (result.firefox && result.version >= 20.0) || 3029 (result.safari && result.version >= 6) || 3030 (result.opera && result.version >= 10.0) || 3031 (result.ios && result.osversion && result.osversion.split(".")[0] >= 6) || 3032 (result.blackberry && result.version >= 10.1) 3033 || (result.chromium && result.version >= 20) 3034 ) { 3035 result.a = t; 3036 } 3037 else if ((result.msie && result.version < 10) || 3038 (result.chrome && result.version < 20) || 3039 (result.firefox && result.version < 20.0) || 3040 (result.safari && result.version < 6) || 3041 (result.opera && result.version < 10.0) || 3042 (result.ios && result.osversion && result.osversion.split(".")[0] < 6) 3043 || (result.chromium && result.version < 20) 3044 ) { 3045 result.c = t 3046 } else result.x = t 3047 3048 return result 3049 } 3050 3051 var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '') 3052 3053 bowser.test = function (browserList) { 3054 for (var i = 0; i < browserList.length; ++i) { 3055 var browserItem = browserList[i]; 3056 if (typeof browserItem=== 'string') { 3057 if (browserItem in bowser) { 3058 return true; 3059 } 3060 } 3061 } 3062 return false; 3063 } 3064 3065 /** 3066 * Get version precisions count 3067 * 3068 * @example 3069 * getVersionPrecision("1.10.3") // 3 3070 * 3071 * @param {string} version 3072 * @return {number} 3073 */ 3074 function getVersionPrecision(version) { 3075 return version.split(".").length; 3076 } 3077 3078 /** 3079 * Array::map polyfill 3080 * 3081 * @param {Array} arr 3082 * @param {Function} iterator 3083 * @return {Array} 3084 */ 3085 function map(arr, iterator) { 3086 var result = [], i; 3087 if (Array.prototype.map) { 3088 return Array.prototype.map.call(arr, iterator); 3089 } 3090 for (i = 0; i < arr.length; i++) { 3091 result.push(iterator(arr[i])); 3092 } 3093 return result; 3094 } 3095 3096 /** 3097 * Calculate browser version weight 3098 * 3099 * @example 3100 * compareVersions(['1.10.2.1', '1.8.2.1.90']) // 1 3101 * compareVersions(['1.010.2.1', '1.09.2.1.90']); // 1 3102 * compareVersions(['1.10.2.1', '1.10.2.1']); // 0 3103 * compareVersions(['1.10.2.1', '1.0800.2']); // -1 3104 * 3105 * @param {Array<String>} versions versions to compare 3106 * @return {Number} comparison result 3107 */ 3108 function compareVersions(versions) { 3109 // 1) get common precision for both versions, for example for "10.0" and "9" it should be 2 3110 var precision = Math.max(getVersionPrecision(versions[0]), getVersionPrecision(versions[1])); 3111 var chunks = map(versions, function (version) { 3112 var delta = precision - getVersionPrecision(version); 3113 3114 // 2) "9" -> "9.0" (for precision = 2) 3115 version = version + new Array(delta + 1).join(".0"); 3116 3117 // 3) "9.0" -> ["000000000"", "000000009"] 3118 return map(version.split("."), function (chunk) { 3119 return new Array(20 - chunk.length).join("0") + chunk; 3120 }).reverse(); 3121 }); 3122 3123 // iterate in reverse order by reversed chunks array 3124 while (--precision >= 0) { 3125 // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) 3126 if (chunks[0][precision] > chunks[1][precision]) { 3127 return 1; 3128 } 3129 else if (chunks[0][precision] === chunks[1][precision]) { 3130 if (precision === 0) { 3131 // all version chunks are same 3132 return 0; 3133 } 3134 } 3135 else { 3136 return -1; 3137 } 3138 } 3139 } 3140 3141 /** 3142 * Check if browser is unsupported 3143 * 3144 * @example 3145 * bowser.isUnsupportedBrowser({ 3146 * msie: "10", 3147 * firefox: "23", 3148 * chrome: "29", 3149 * safari: "5.1", 3150 * opera: "16", 3151 * phantom: "534" 3152 * }); 3153 * 3154 * @param {Object} minVersions map of minimal version to browser 3155 * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map 3156 * @param {String} [ua] user agent string 3157 * @return {Boolean} 3158 */ 3159 function isUnsupportedBrowser(minVersions, strictMode, ua) { 3160 var _bowser = bowser; 3161 3162 // make strictMode param optional with ua param usage 3163 if (typeof strictMode === 'string') { 3164 ua = strictMode;
3165 strictMode = void(0); 3166 } 3167 3168 if (strictMode === void(0)) { 3169 strictMode = false; 3170 } 3171 if (ua) { 3172 _bowser = detect(ua); 3173 } 3174 3175 var version = "" + _bowser.version; 3176 for (var browser in minVersions) { 3177 if (minVersions.hasOwnProperty(browser)) { 3178 if (_bowser[browser]) { 3179 // browser version and min supported version. 3180 return compareVersions([version, minVersions[browser]]) < 0; 3181 } 3182 } 3183 } 3184 3185 return strictMode; // not found 3186 } 3187 3188 /** 3189 * Check if browser is supported 3190 * 3191 * @param {Object} minVersions map of minimal version to browser 3192 * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map 3193 * @param {String} [ua] user agent string 3194 * @return {Boolean} 3195 */ 3196 function check(minVersions, strictMode, ua) { 3197 return !isUnsupportedBrowser(minVersions, strictMode, ua); 3198 } 3199 3200 bowser.isUnsupportedBrowser = isUnsupportedBrowser; 3201 bowser.compareVersions = compareVersions; 3202 bowser.check = check; 3203 3204 /* 3205 * Set our detect method to the main bowser object so we can 3206 * reuse it to test other user agents. 3207 * This is needed to implement future tests. 3208 */ 3209 bowser._detect = detect; 3210 3211 return bowser 3212}); 3213 3214(function($){ 3215 UABBTrigger = { 3216 3217 /** 3218 * Trigger a hook. 3219 * 3220 * @since 1.1.0.3 3221 * @method triggerHook 3222 * @param {String} hook The hook to trigger. 3223 * @param {Array} args An array of args to pass to the hook. 3224 */ 3225 triggerHook: function( hook, args ) 3226 { 3227 $( 'body' ).trigger( 'uabb-trigger.' + hook, args ); 3228 }, 3229 3230 /** 3231 * Add a hook. 3232 * 3233 * @since 1.1.0.3 3234 * @method addHook 3235 * @param {String} hook The hook to add. 3236 * @param {Function} callback A function to call when the hook is triggered. 3237 */ 3238 addHook: function( hook, callback ) 3239 { 3240 $( 'body' ).on( 'uabb-trigger.' + hook, callback ); 3241 }, 3242 3243 /** 3244 * Remove a hook. 3245 * 3246 * @since 1.1.0.3 3247 * @method removeHook 3248 * @param {String} hook The hook to remove. 3249 * @param {Function} callback The callback function to remove. 3250 */ 3251 removeHook: function( hook, callback ) 3252 { 3253 $( 'body' ).off( 'uabb-trigger.' + hook, callback ); 3254 }, 3255 }; 3256})(jQuery); 3257 3258jQuery(document).ready(function( $ ) { 3259 3260 if( typeof bowser !== 'undefined' && bowser !== null ) { 3261 3262 var uabb_browser = bowser.name, 3263 uabb_browser_v = bowser.version, 3264 uabb_browser_class = uabb_browser.replace(/\s+/g, '-').toLowerCase(), 3265 uabb_browser_v_class = uabb_browser_class + parseInt( uabb_browser_v ); 3266 3267 $('html').addClass(uabb_browser_class).addClass(uabb_browser_v_class); 3268 3269 } 3270 3271 $('.uabb-row-separator').parents('html').css('overflow-x', 'hidden'); 3272}); 3273jQuery(function($) { 3274 3275 $(function() { 3276 $( '.fl-node-5c5aca54d6db4 .fl-photo-img' ) 3277 .on( 'mouseenter', function( e ) { 3278 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 3279 } ) 3280 .on( 'mouseleave', function( e ){ 3281 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 3282 } ); 3283 }); 3284 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 3285}); 3286 3287;/* eslint-disable no-undef */ 3288(function($) { 3289 3290 /** 3291 * Class for Menu Module 3292 * 3293 * @since 1.6.1 3294 */ 3295 FLBuilderMenu = function( settings ){ 3296 3297 // set params 3298 this.nodeId = settings.id; 3299 this.nodeClass = '.fl-node-' + settings.id; 3300 this.wrapperClass = this.nodeClass + ' .fl-menu'; 3301 this.type = settings.type; 3302 this.mobileToggle = settings.mobile; 3303 this.mobileBelowRow = settings.mobileBelowRow; 3304 this.mobileFlyout = settings.mobileFlyout; 3305 this.breakPoints = settings.breakPoints; 3306 this.mobileBreakpoint = settings.mobileBreakpoint; 3307 this.currentBrowserWidth = $( window ).width(); 3308 this.postId = settings.postId; 3309 this.mobileStacked = settings.mobileStacked; 3310 this.submenuIcon = settings.submenuIcon; 3311 this.flyoutWidth = settings.flyoutWidth; 3312 3313 // initialize the menu 3314 this._initMenu(); 3315 3316 // check if viewport is resizing 3317 $( window ).on( 'resize', $.proxy( function() { 3318 3319 var width = $( window ).width(); 3320 3321 // if screen width is resized, reload the menu 3322 if( width != this.currentBrowserWidth ){ 3323 3324 this.currentBrowserWidth = width; 3325 this._initMenu( true ); 3326 this._clickOrHover( true ); 3327 } 3328 3329 this._resizeFlyoutMenuPanel(); 3330 }, this ) ); 3331 3332 $( window ).on( 'scroll', $.proxy( function() { 3333 this._resizeFlyoutMenuPanel(); 3334 }, this ) ); 3335 3336 // Move focus to the first menu item if the layout is set to BelowRow 3337 $( this.wrapperClass ).on( 'keydown', '.fl-menu-mobile-toggle, .menu-item:first a:first', $.proxy( function ( event ) { 3338 // Make sure it is a tab key with both the menu toggle enabled & below row layout set 3339 if ( event.key !== 'Tab' || ! this._isMenuToggle() || ! this._isMobileBelowRowEnabled() ) { 3340 return; 3341 } 3342 // Trigger focus on the mobile toggle button if the user is shift tabbing from the first menu item 3343 if ( event.shiftKey && $( event.currentTarget ).is( 'a' ) ) { 3344 event.preventDefault(); 3345 $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).trigger( 'focus' ); 3346 } 3347 // Trigger focus on the first menu item if the user is tabbing from the mobile toggle button 3348 else if ( ! event.shiftKey && $( event.currentTarget ).hasClass( 'fl-menu-mobile-toggle' ) && $( event.currentTarget ).hasClass( 'fl-active' ) ) { 3349 event.preventDefault(); 3350 $( this.wrapperClass ).find( '.menu-item' ).first().find( 'a' ).first().trigger( 'focus' ); 3351 } 3352 }, this ) ); 3353 3354 // Close mobile menu or accordion when tabbing out from the first or last menu item 3355 $( this.wrapperClass ).on( 'focusout', $.proxy( function ( event ) { 3356 if ( $( this.wrapperClass + ' nav' ).has( $( event.relatedTarget ) ).length === 0 ) { 3357 if ( this.type === 'accordion' ) { 3358 this._toggleSubmenu( $( event.target ).parents( '.fl-has-submenu' ).last(), false ); 3359 } 3360 else { 3361 this._clickOrHover( true ); 3362 } 3363 const mobileToggle = $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ); 3364 if ( this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) && ! $( event.relatedTarget ).is( mobileToggle ) && 'expanded' !== this.mobileToggle ) { 3365 mobileToggle.trigger( 'click' ); 3366 } 3367 } 3368 }, this ) ); 3369 3370 }; 3371 3372 FLBuilderMenu.prototype = { 3373 nodeClass : '', 3374 wrapperClass: '', 3375 type : '', 3376 breakPoints : {}, 3377 $submenus : null, 3378 3379 /** 3380 * Check if the screen size fits a mobile viewport. 3381 * 3382 * @since 1.6.1 3383 * @return bool 3384 */ 3385 _isMobile: function(){ 3386 return this.currentBrowserWidth <= this.breakPoints.small ? true : false;
3387 }, 3388 3389 /** 3390 * Check if the device is connected to a mouse. 3391 * 3392 * @since 2.9.0 3393 * @return bool 3394 */ 3395 _isMouseAvailable: function(){ 3396 return window.matchMedia("(pointer: fine) and (hover: hover)").matches; 3397 }, 3398 3399 /** 3400 * Check if the screen size fits a medium viewport. 3401 * 3402 * @since 1.10.5 3403 * @return bool 3404 */ 3405 _isMedium: function(){ 3406 return this.currentBrowserWidth <= this.breakPoints.medium ? true : false; 3407 }, 3408 3409 /** 3410 * Check if the screen size fits a large viewport. 3411 * 3412 * @since 1.10.5 3413 * @return bool 3414 */ 3415 _isLarge: function(){ 3416 return this.currentBrowserWidth <= this.breakPoints.large ? true : false; 3417 }, 3418 3419 /** 3420 * Check if the menu should toggle for the current viewport base on the selected breakpoint. 3421 * 3422 * @see this._isMobile() 3423 * @see this._isMedium() 3424 * @since 1.10.5 3425 * @return bool 3426 */ 3427 _isMenuToggle: function(){ 3428 if ( ( 'always' == this.mobileBreakpoint 3429 || ( this._isMobile() && 'mobile' == this.mobileBreakpoint ) 3430 || ( this._isMedium() && 'medium-mobile' == this.mobileBreakpoint ) 3431 || ( this._isLarge() && 'large-mobile' == this.mobileBreakpoint ) 3432 ) && ( $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).is(':visible') || 'expanded' == this.mobileToggle ) ) { 3433 return true; 3434 } 3435 3436 return false; 3437 }, 3438 3439 /** 3440 * Initialize the toggle logic for the menu. 3441 * 3442 * @see this._isMenuToggle() 3443 * @see this._menuOnCLick() 3444 * @see this._clickOrHover() 3445 * @see this._submenuOnRight() 3446 * @see this._submenuRowZindexFix() 3447 * @see this._toggleForMobile() 3448 * @since 1.6.1 3449 * @return void 3450 */ 3451 _initMenu: function( resized = false ){ 3452 this._setupSubmenu(); 3453 if ( ! resized ) { 3454 this._menuOnFocus(); 3455 this._menuOnClick(); 3456 this._menuOnEscape(); 3457 } 3458 if ( $( this.nodeClass ).length && this.type == 'horizontal' ) { 3459 this._initMegaMenus(); 3460 } 3461 3462 if( this._isMenuToggle() || this.type == 'accordion' ){ 3463 3464 $( this.wrapperClass ).off( 'mouseenter mouseleave' ); 3465 this._clickOrHover(); 3466 3467 } else { 3468 this._submenuOnRight(); 3469 this._submenuRowZindexFix(); 3470 } 3471 3472 if( this.mobileToggle != 'expanded' ){ 3473 this._toggleForMobile(); 3474 } 3475 3476 if( $( this.wrapperClass ).find( '.fl-menu-search-item' ).length ){ 3477 this._toggleMenuSearch(); 3478 } 3479 3480 if( $( this.wrapperClass ).find( '.fl-menu-cart-item').length ){ 3481 this._wooUpdateParams(); 3482 } 3483 }, 3484 3485 /** 3486 * Whether the toggle behavior for submenus is through hovering or not. 3487 * 3488 * @since 2.5 3489 * @return void 3490 */ 3491 _setupSubmenu: function() { 3492 if ( ! this._isMouseAvailable() || this._isMenuToggle() || this.type === 'accordion' ) { 3493 $( this.wrapperClass ).addClass( 'no-hover' ); 3494 } 3495 else { 3496 $( this.wrapperClass ).removeClass( 'no-hover' ); 3497 } 3498 }, 3499 3500 /** 3501 * Logic for menu items when focused. 3502 * 3503 * @since 1.9.0 3504 * @return void 3505 */ 3506 _menuOnFocus: function(){ 3507 $( this.wrapperClass ).on( 'focus', 'a:not(.fl-button), .fl-menu-toggle', $.proxy( function( event ) { 3508 const focusedMenuItem = $( event.currentTarget ).closest( '.menu-item' ); 3509 const blurredMenuItem = $( event.relatedTarget ).closest( '.menu-item' ); 3510 // In case the blurred & focused items are siblings 3511 if ( focusedMenuItem.closest( 'ul' ).is( blurredMenuItem.closest( 'ul' ) ) ) { 3512 // Check if the focus event is not between the link & submenu icon of the same menu item 3513 if ( ! focusedMenuItem.is( blurredMenuItem ) ) { 3514 this._toggleSubmenu( blurredMenuItem, false ); 3515 } 3516 } 3517 // In case neither items are child & parent nor vice versa 3518 else if ( focusedMenuItem.has( blurredMenuItem ).length === blurredMenuItem.has( focusedMenuItem ).length ) { 3519 // Get the blurred item parent & is the sibling of the focused item 3520 blurredMenuItem.parents( '.fl-has-submenu' ).each( ( _, parent ) => { 3521 if ( focusedMenuItem.closest( 'ul' ).is( $( parent ).closest( 'ul' ) ) ) { 3522 this._toggleSubmenu( $( parent ), false ); 3523 return false; 3524 } 3525 } ); 3526 } 3527 // In case the blurred item is a child of the focused item
3528 else if ( focusedMenuItem.has( blurredMenuItem ).length ) { 3529 if ( this.type !== 'accordion' && this.submenuIcon === 'none' ) { 3530 this._toggleSubmenu( blurredMenuItem, false ); 3531 } 3532 } 3533 }, this ) ); 3534 }, 3535 3536 /** 3537 * Logic for menu items when Escape key is pressed. 3538 * 3539 * @since 2.7.1 3540 * @return void 3541 */ 3542 _menuOnEscape: function(){ 3543 $( this.wrapperClass ).on( 'keydown', $.proxy( function( event ){ 3544 if ( event.key !== 'Escape' ) return; 3545 const menuItem = $( event.target ).closest( '.menu-item' ); 3546 const mobileToggle = $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ); 3547 // In case there is a focused menu item 3548 if ( menuItem.length || $( event.target ).hasClass( 'fl-menu-mobile-close' ) ) { 3549 // Close the search form if it is open 3550 if ( menuItem.hasClass( 'fl-menu-search-item' ) && $( this.wrapperClass ).find('.fl-search-form-input-wrap').is( ':visible' ) ) { 3551 $( this.wrapperClass ).find('.fl-menu-search-item .fl-button:is(a, button:not([type="submit"]))').trigger( 'focus' ); 3552 } 3553 // Close all the submenus of the focused menu item 3554 else if ( menuItem.hasClass( 'fl-has-submenu' ) && menuItem.find( '.sub-menu' ).first().is( ':visible' ) ) { 3555 this._toggleSubmenu( menuItem, false ); 3556 } 3557 else { 3558 // Shift focus to the parent while closing all its submenus 3559 const parentMenuItem = menuItem.parents( '.fl-has-submenu' ).not( '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading' ).first(); 3560 // Close the mobile menu if there is no parent menu item and the mobile toggle is active 3561 if ( parentMenuItem.length === 0 && this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) ) { 3562 // Blur to trigger the focus-out event for closing the menu 3563 mobileToggle.trigger( 'blur' ).trigger( 'focus' ); 3564 } 3565 // Close the parent submenu and shift focus to its link 3566 else if ( parentMenuItem.length !== 0 ) { 3567 this._toggleSubmenu( parentMenuItem, false ); 3568 parentMenuItem.find( 'a' ).first().trigger( 'focus' ); 3569 } 3570 } 3571 } 3572 // Close the mobile menu if the mobile toggle is active 3573 else if ( $( event.target ).hasClass( 'fl-menu-mobile-toggle' ) && mobileToggle.hasClass( 'fl-active' ) ) { 3574 // Blur to trigger the focus-out event for closing the menu 3575 mobileToggle.trigger( 'blur' ).trigger( 'focus' ); 3576 } 3577 }, this ) ); 3578 }, 3579 3580 /** 3581 * Logic for menu items when clicked. 3582 * 3583 * @since 1.6.1 3584 * @return void 3585 */ 3586 _menuOnClick: function(){ 3587 // Fallback for span elements and fake links to interact with the keyboard 3588 $( this.wrapperClass ).on( 'keydown', 'a:not(.fl-button, [href]), span.fl-menu-toggle', $.proxy( function( event ) { 3589 if ( event.key === 'Enter' || event.key === ' ' ) { 3590 event.preventDefault(); 3591 $( event.currentTarget ).trigger( 'click' ); 3592 } 3593 }, this ) ); 3594 $( this.wrapperClass ).on( 'click', 'a, .fl-menu-toggle', $.proxy( function( event ) { 3595 // Only allow mouse clicks with accordion & mobile menus 3596 if ( this._isMouseAvailable() && ! this._isMenuToggle() && event.detail && this.type !== 'accordion' ) return; 3597 // Links only open & do not toggle submenus if there is either a submenu icon or an accordion layout 3598 if ( $( event.currentTarget ).is( 'a' ) && ( this.submenuIcon !== 'none' || this.type === 'accordion' ) ) return; 3599 const menuItem = $( event.currentTarget ).closest( '.menu-item, .fl-menu-logo' ); 3600 const menuLink = menuItem.find( 'a' ).first().attr( 'href' ); 3601 const submenuHidden = menuItem.find( '.sub-menu' ).first().is( ':hidden' ); 3602 if ( typeof menuLink === 'undefined' || menuLink === '#' || submenuHidden ) { 3603 event.preventDefault(); 3604 } 3605 if ( $( event.currentTarget ).hasClass( 'fl-menu-toggle' ) || submenuHidden ) { 3606 this._toggleSubmenu( menuItem, submenuHidden ); 3607 } 3608 }, this ) ); 3609 }, 3610 3611 /** 3612 * Controls toggling the visibility of all submenu items for desktop & mobile. 3613 * 3614 * @since 2.10 3615 * @return void 3616 */ 3617 _toggleSubmenu: function ( menuItem, opened ) { 3618 const togglingClass = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus'; 3619 const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle'; 3620 const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading'; 3621 if ( opened && menuItem.hasClass( 'fl-has-submenu' ) && ! menuItem.is( hiddenMenu ) ) { 3622 menuItem.addClass( togglingClass ); 3623 menuItem.find( toggleElement ).first().attr( 'aria-expanded', true ); 3624 if ( this._isMenuToggle() || this.type === 'accordion' ) { 3625 menuItem.find( '.sub-menu' ).first().filter( ':hidden' ).slideDown(); 3626 } 3627 } 3628 else { 3629 menuItem.parent().find( '.menu-item' ).removeClass( togglingClass ); 3630 menuItem.parent().find( '.fl-has-submenu' ).not( hiddenMenu ).find( toggleElement ).attr( 'aria-expanded', false ); 3631 if ( this._isMenuToggle() || this.type === 'accordion' ) {
3632 menuItem.find( '.sub-menu' ).filter( ':visible' ).slideUp(); 3633 } 3634 } 3635 }, 3636 3637 /** 3638 * Changes general styling and behavior of menus based on mobile / desktop viewport. 3639 * 3640 * @see this._isMenuToggle() 3641 * @since 1.6.1 3642 * @return void 3643 */ 3644 _clickOrHover: function( clear = false ){ 3645 const selector = this._isMobileBelowRowEnabled() ? this.nodeClass + '-clone' : this.nodeClass; 3646 this.$submenus = this.$submenus || $( selector ).find( '.sub-menu' ); 3647 3648 const className = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus'; 3649 const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle'; 3650 const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading'; 3651 $( selector ).find( '.fl-has-submenu' ).not( hiddenMenu ).each( function() { 3652 if( clear || ! $ ( this ).hasClass( className ) ){ 3653 if ( clear ) $( this ).removeClass( className ); 3654 $( this ).find( toggleElement ).first().attr( 'aria-expanded', false ); 3655 if ( className === 'fl-active' ) { 3656 $( this ).find( '.sub-menu' ).fadeOut(); 3657 } else if ( className === 'focus' ) { 3658 $( this ).find( '.sub-menu' ).css( { 3659 'display' : '', 3660 'opacity' : '' 3661 } ); 3662 } 3663 } 3664 } ); 3665 }, 3666 3667 /** 3668 * Logic to prevent submenus to go outside viewport boundaries. 3669 * 3670 * @since 1.6.1 3671 * @return void 3672 */ 3673 _submenuOnRight: function(){ 3674 3675 $( this.wrapperClass ) 3676 .on( 'mouseenter focus', '.fl-has-submenu', $.proxy( function( e ){ 3677 3678 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 3679 return; 3680 } 3681 3682 var $link = $( e.currentTarget ), 3683 $parent = $link.parent(), 3684 $subMenu = $link.find( '.sub-menu' ), 3685 subMenuWidth = $subMenu.width(), 3686 subMenuPos = 0, 3687 bodyWidth = $( 'body' ).width(); 3688 3689 if( $link.closest( '.fl-menu-submenu-right' ).length !== 0) { 3690 3691 $link.addClass( 'fl-menu-submenu-right' ); 3692 3693 } else if( $( 'body' ).hasClass( 'rtl' ) ) { 3694 3695 subMenuPos = $parent.is( '.sub-menu' ) ? 3696 $parent.offset().left - subMenuWidth: 3697 $link.offset().left - $link.width() - subMenuWidth; 3698 3699 if( subMenuPos <= 0 ) { 3700 $link.addClass( 'fl-menu-submenu-right' ); 3701 } 3702 3703 } else { 3704 3705 subMenuPos = $parent.is( '.sub-menu' ) ? 3706 $parent.offset().left + $parent.width() + subMenuWidth : 3707 $link.offset().left + $link.width() + subMenuWidth; 3708 3709 if( subMenuPos > bodyWidth ) { 3710 $link.addClass('fl-menu-submenu-right'); 3711 } 3712 } 3713 }, this ) ) 3714 .on( 'mouseleave', '.fl-has-submenu', $.proxy( function( e ){ 3715 $( e.currentTarget ).removeClass( 'fl-menu-submenu-right' ); 3716 }, this ) ); 3717 3718 }, 3719 3720 /** 3721 * Logic to prevent submenus to go behind the next overlay row. 3722 * 3723 * @since 1.10.9 3724 * @return void 3725 */ 3726 _submenuRowZindexFix: function(){ 3727 3728 $( this.wrapperClass ) 3729 .on( 'mouseenter', 'ul.menu > .fl-has-submenu', $.proxy( function( e ){ 3730 3731 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 3732 return; 3733 } 3734 3735 $( this.nodeClass ) 3736 .closest( '.fl-row' ) 3737 .find( '.fl-row-content' ) 3738 .css( 'z-index', '10' ); 3739 3740 }, this ) ) 3741 .on( 'mouseleave', 'ul.menu > .fl-has-submenu', $.proxy( function(){ 3742 3743 $( this.nodeClass ) 3744 .closest( '.fl-row' ) 3745 .find( '.fl-row-content' ) 3746 .css( 'z-index', '' ); 3747 3748 }, this ) ); 3749 }, 3750 3751 /** 3752 * Logic for the mobile menu button. 3753 * 3754 * @since 1.6.1 3755 * @return void 3756 */ 3757 _toggleForMobile: function(){ 3758 3759 var $wrapper = null, 3760 $menu = null, 3761 self = this; 3762 3763 $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).attr('aria-controls', $( this.wrapperClass ).find( 'ul.menu' ).attr('id')); 3764 3765 if( this._isMenuToggle() ){ 3766 3767 if ( this._isMobileBelowRowEnabled() ) { 3768 this._placeMobileMenuBelowRow(); 3769 $wrapper = $( this.wrapperClass ); 3770 $menu = $( this.nodeClass + '-clone' ); 3771 $menu.find( 'ul.menu' ).show(); 3772 } 3773 else { 3774 $wrapper = $( this.wrapperClass ); 3775 $menu = $wrapper.find( '.menu' ); 3776 } 3777 3778 if( !$wrapper.find( '.fl-menu-mobile-toggle' ).hasClass( 'fl-active' ) && ! self.mobileFlyout ){ 3779 $menu.css({ display: 'none' }); 3780 } 3781 3782 // Flayout Menu 3783 if ( self.mobileFlyout ) { 3784 this._initFlyoutMenu(); 3785 } 3786 3787 $wrapper.on( 'click', '.fl-menu-mobile-toggle', function( e ){ 3788 e.stopImmediatePropagation(); 3789 3790 $( this ).toggleClass( 'fl-active' ); 3791 3792 if ( self.mobileFlyout ) { 3793 self._toggleFlyoutMenu(); 3794 const flyoutWrapper = $( '.fl-menu-mobile-flyout' ); 3795 if ( $( this ).hasClass( 'fl-active' ) ) { 3796 flyoutWrapper.attr( 'aria-hidden', false ); 3797 flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex="-1"]' ).attr( 'tabindex', 0 ); 3798 } 3799 else { 3800 flyoutWrapper.attr( 'aria-hidden', true ); 3801 flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not
3801([tabindex="-1"])' ).attr( 'tabindex', -1 ); 3802 } 3803 } 3804 else { 3805 var targetMenu = null; 3806 3807 if ( self.mobileBelowRow ) { 3808 var $closestCol = $( this ).parents( '.fl-col, .fl-module-box' ), 3809 $closestColGroup = $closestCol.length ? $closestCol.parent( '.fl-col-group' ) : null; 3810 targetMenu = $closestCol.length ? $closestCol.last().next( '.fl-menu-mobile-clone' ) : null; 3811 3812 if ( $closestColGroup.length ) { 3813 if ( $closestColGroup.hasClass( 'fl-col-group-responsive-reversed' ) ) { 3814 $closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', -1 ); 3815 } else if ( $closestColGroup ) { 3816 $closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', 2 ); 3817 } 3818 } 3819 } else { 3820 targetMenu = $( this ).closest( '.fl-menu' ).find( 'ul.menu' ); 3821 } 3822 3823 if ( targetMenu.length ) { 3824 $menu = $( targetMenu ); 3825 } 3826 3827 $menu.slideToggle(); 3828 } 3829 3830 e.stopPropagation(); 3831 } ); 3832 3833 // Hide active menu when click on anchor link ID that exists on a page 3834 $menu.off().on( 'click', '.menu-item > a[href*="#"]:not([href="#"])', function(){ 3835 var $href = $(this).attr('href'), 3836 $targetID = $href.split('#')[1], 3837 element = $('#' + $targetID); 3838 if ( $('body').find(element).length > 0 ) { 3839 $( this ).toggleClass( 'fl-active' ); 3840 FLBuilderLayout._scrollToElement( element ); 3841 if ( ! self._isMenuToggle() ) { 3842 $menu.slideToggle(); 3843 } 3844 } 3845 }); 3846 } 3847 else { 3848 3849 if ( this._isMobileBelowRowEnabled() ) { 3850 this._removeMenuFromBelowRow(); 3851 } 3852 3853 $wrapper = $( this.wrapperClass ), 3854 $menu = $wrapper.find( 'ul.menu' ); 3855 $wrapper.find( '.fl-menu-mobile-toggle' ).removeClass( 'fl-active' ); 3856 $menu.css({ display: '' }); 3857 3858 if ( ! this._isMobileBelowRowEnabled() ) { 3859 $menu.off( 'click', '.menu-item > a[href*="#"]:not([href="#"])' ); 3860 } 3861 3862 if ( this.mobileFlyout && $wrapper.find( '.fl-menu-mobile-flyout' ).length > 0 ) { 3863 $( 'body' ).css( 'margin', '' ); 3864 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' ); 3865 $menu.unwrap(); 3866 $wrapper.find( '.fl-menu-mobile-close' ).remove(); 3867 $wrapper.find( '.fl-menu-mobile-opacity' ).remove(); 3868 } 3869 } 3870 }, 3871 3872 /** 3873 * Init any mega menus that exist. 3874 * 3875 * @see this._isMenuToggle() 3876 * @since 1.10.4 3877 * @return void 3878 */ 3879 _initMegaMenus: function(){ 3880 3881 var module = $( this.nodeClass ), 3882 rowContent = module.closest( '.fl-row-content' ), 3883 rowWidth = rowContent.width(), 3884 megas = module.find( '.mega-menu' ), 3885 disabled = module.find( '.mega-menu-disabled' ), 3886 isToggle = this._isMenuToggle(); 3887 3888 if ( isToggle ) { 3889 megas.removeClass( 'mega-menu' ).addClass( 'mega-menu-disabled' ); 3890 module.find( 'li.mega-menu-disabled > ul.sub-menu' ).css( 'width', '' ); 3891 rowContent.css( 'position', '' ); 3892 } else { 3893 disabled.removeClass( 'mega-menu-disabled' ).addClass( 'mega-menu' ); 3894 module.find( 'li.mega-menu > ul.sub-menu' ).css( 'width', rowWidth + 'px' ); 3895 rowContent.css( 'position', 'relative' ); 3896 } 3897 }, 3898 3899 /** 3900 * Check to see if Below Row should be enabled. 3901 * 3902 * @since 1.11 3903 * @return boolean 3904 */ 3905 _isMobileBelowRowEnabled: function() { 3906 return this.mobileBelowRow && ( $( this.nodeClass ).parents( '.fl-col, .fl-module-box' ).length ); 3907 }, 3908 3909 /** 3910 * Logic for putting the mobile menu below the menu's 3911 * column so it spans the full width of the page. 3912 * 3913 * @since 1.10 3914 * @return void 3915 */ 3916 _placeMobileMenuBelowRow: function(){ 3917 3918 if ( $( this.nodeClass + '-clone' ).length ) { 3919 return; 3920 } 3921 3922 var module = $( this.nodeClass ), 3923 clone = null, 3924 col = module.parents( '.fl-col, .fl-module-box' ).last(); 3925 3926 if ( module.length < 1 ) { 3927 return; 3928 } 3929 3930 clone = ( module.length > 1 ) ? $( module[0] ).clone() : module.clone(); 3931 module.find( 'ul.menu' ).remove(); 3932 clone.addClass( ( this.nodeClass + '-clone' ).replace( '.', '' ) ); 3933 clone.addClass( 'fl-menu-mobile-clone' ); 3934 clone.find( '.fl-menu-mobile-toggle' ).remove(); 3935 col.after( clone ); 3936 3937 // Removes animation when enabled 3938 if ( module.hasClass( 'fl-animation' ) ) { 3939 clone.removeClass( 'fl-animation' ); 3940 } 3941 3942 this._menuOnFocus(); 3943 this._menuOnClick(); 3944 this._menuOnEscape(); 3945 }, 3946 3947 /** 3948 * Logic for removing the mobile menu from below the menu's 3949 * column and putting it back in the main wrapper. 3950 * 3951 * @since 1.10 3952 * @return void 3953 */ 3954 _removeMenuFromBelowRow: function(){ 3955 3956 if ( ! $( this.nodeClass + '-clone' ).length ) { 3957 return; 3958 } 3959 3960 var module = $( this.nodeClass ), 3961 clone = $( this.nodeClass + '-clone' ), 3962 menu = clone.find( 'ul.menu' ), 3963 nav = module.find( 'nav' ); 3964
3965 if ( nav.length ) { 3966 nav.append( menu ); 3967 } else { 3968 module.find( '.fl-menu-mobile-toggle' ).after( menu ); 3969 } 3970 clone.remove(); 3971 menu.find( 'a' ).each( FLBuilderLayout._initAnchorLink ); 3972 }, 3973 3974 /** 3975 * Logic for Flyout responsive menu. 3976 * 3977 * @since 2.2 3978 * @return void 3979 */ 3980 _initFlyoutMenu: function(){ 3981 var wrapper = $( this.wrapperClass ), 3982 menu = wrapper.find( 'ul.menu' ), 3983 button = wrapper.find( '.fl-menu-mobile-toggle' ); 3984 3985 if ( 0 === wrapper.find( '.fl-menu-mobile-flyout' ).length ) { 3986 menu.wrap( '<div class="fl-menu-mobile-flyout" aria-hidden="true"></div>' ); 3987 } 3988 3989 if ( 0 === wrapper.find( '.fl-menu-mobile-close' ).length ) { 3990 var close = window.fl_responsive_close || 'Close' 3991 wrapper.find( '.fl-menu-mobile-flyout' ).prepend( '<button class="fl-menu-mobile-close fl-content-ui-button" aria-label="' + close + '"><i class="fas fa-times"></i></button>' ); 3992 } 3993 3994 // Push with opacity 3995 if ( wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ) && 0 === wrapper.find( '.fl-menu-mobile-opacity' ).length ) { 3996 wrapper.append( '<div class="fl-menu-mobile-opacity"></div>' ); 3997 } 3998 3999 wrapper.off( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close' ).on( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close', function(e){ 4000 button.trigger('focus').trigger( 'click' ); 4001 e.stopPropagation(); 4002 }); 4003 4004 if ( 'undefined' !== typeof FLBuilder ) { 4005 FLBuilder.addHook('restartEditingSession', function(){ 4006 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' ); 4007 4008 // Toggle active menu 4009 if ( button.hasClass( 'fl-active' ) ) { 4010 button.trigger( 'click' ); 4011 } 4012 }); 4013 } 4014 $( '.fl-menu-mobile-flyout' ).find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not([tabindex="-1"])' ).attr( 'tabindex', -1 ); 4015 }, 4016 4017 /** 4018 * Logic to enable/disable the Flyout menu on button click. 4019 * 4020 * @since 2.2 4021 * @return void 4022 */ 4023 _toggleFlyoutMenu: function(){ 4024 var wrapper = $( this.wrapperClass ), 4025 button = wrapper.find( '.fl-menu-mobile-toggle' ), 4026 position = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 4027 pushMenu = wrapper.hasClass( 'fl-menu-responsive-flyout-push' ) || wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 4028 opacity = wrapper.find( '.fl-menu-mobile-opacity' ), 4029 marginPos = {}, 4030 fixedPos = {}, 4031 fixedHeader = $('header, header > div'); 4032 4033 this._resizeFlyoutMenuPanel(); 4034 4035 // Fix the push menu when builder ui panel is pinned 4036 if ( $( '.fl-builder-ui-pinned-content-transform' ).length > 0 && ! $( 'body' ).hasClass( 'fl-builder-edit' ) ) { 4037 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', 'none' ); 4038 } 4039 4040 if ( pushMenu ) { 4041 marginPos[ 'margin-' + position ] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px'; 4042 $( 'body' ).animate( marginPos, 200); 4043 4044 // Fixed header 4045 if ( fixedHeader.length > 0 ) { 4046 fixedPos[ position] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px'; 4047 fixedHeader.each(function(){ 4048 if ( 'fixed' == $( this ).css( 'position' ) ) { 4049 $( this ).css({ 'transition' : 'none' }); 4050 $( this ).animate( fixedPos, 200 ); 4051 } 4052 }); 4053 } 4054 } 4055 4056 if ( opacity.length > 0 && button.hasClass( 'fl-active' ) ) { 4057 opacity.show(); 4058 } 4059 else { 4060 opacity.hide(); 4061 } 4062 }, 4063 4064 /** 4065 * Resize or reposition the Flyout Menu Panel. 4066 * 4067 * @since 2.8.1 4068 * @return void 4069 */ 4070 _resizeFlyoutMenuPanel: function(){ 4071 const wrapper = $( this.wrapperClass ); 4072 const wrapFlyout = wrapper.find( '.fl-menu-mobile-flyout' ); 4073 4074 if ( wrapFlyout.length > 0 ) { 4075 wrapFlyout.css( this._getFlyoutMenuPanelPosition() ); 4076 } 4077 }, 4078 4079 /** 4080 * Compute the Flyout Menu Panel's position on the screen. 4081 * 4082 * @since 2.8.1 4083 * @return object 4084 */ 4085 _getFlyoutMenuPanelPosition: function() { 4086 var wrapper = $( this.wrapperClass ), 4087 button = wrapper.find( '.fl-menu-mobile-toggle' ), 4088 side = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 4089 winHeight = $(window).outerHeight(), 4090 winTop = $(window).scrollTop(), 4091 adminBarHeight = $( '#wpadminbar' ).length ? $( '#wpadminbar' ).height() : 0, 4092 flyoutPosition = {}; 4093 4094 flyoutPosition[ side ] = '-' + ( parseInt( this.flyoutWidth ) + 15 ) + 'px'; 4095 if ( ! button.hasClass( 'fl-active' ) ) { 4096 return flyoutPosition; 4097 } 4098 4099 flyoutPosition[ side ] = '0px'; 4100 flyoutPosition[ 'height' ] = winHeight + 'px'; 4101 flyoutPosition[ 'top' ] = '0px'; 4102 4103 if ( adminBarHeight > 0 ) { 4104 const diff = adminBarHeight - winTop; 4105 flyoutPosition[ 'top' ] = diff <= 0 ? '0px' : (diff) + 'px'; 4106 } 4107 4108 return flyoutPosition; 4109 }, 4110 4111 /** 4112 * Shows or hides the nav search form. 4113 * 4114 * @since 2.5 4115 * @method _toggleMenuSearch 4116 */ 4117 _toggleMenuSearch: function(){ 4118 const form = $( this.wrapperClass ).find('.fl-menu-search-item .fl-search-form-input-wrap');
4119 const button = $( this.wrapperClass ).find('.fl-menu-search-item .fl-button:is(a, button:not([type="submit"]))'); 4120 form.on('submit', () => form.stop().fadeToggle('fast')); 4121 // Close the search form when focus is lost 4122 form.on('focusout', (event) => { 4123 if (form.is(':visible') && form.has($(event.relatedTarget)).length === 0) { 4124 button.trigger('click'); 4125 } 4126 }); 4127 button.attr('aria-expanded', false); 4128 // Close other open submenus when focusing on the search button 4129 button.on('focus', (event) => { 4130 const parentMenus = $(event.relatedTarget).parents('.menu-item.fl-has-submenu'); 4131 if (event.relatedTarget && parentMenus.length) { 4132 this._toggleSubmenu(parentMenus, false); 4133 } 4134 }); 4135 button.on('click', (event) => { 4136 // Prevent toggling when clicking with mouse while the form is already open 4137 if (event.detail && event.type === 'click' && form.is(':visible')) return; 4138 form.stop().fadeToggle('fast', () => { 4139 button.attr('aria-expanded', form.is(':visible')); 4140 if(form.is(':visible')) { 4141 form.find('.fl-search-text').focus(); 4142 } 4143 }); 4144 }); 4145 }, 4146 4147 /** 4148 * Adds menu node and post ID to WooCommerce ajax URL requests. 4149 * 4150 * @since 2.5 4151 * @return void 4152 */ 4153 _wooUpdateParams: function() { 4154 if ( 'undefined' !== typeof wc_cart_fragments_params ) { 4155 wc_cart_fragments_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId; 4156 } 4157 if ( 'undefined' !== typeof wc_add_to_cart_params ) { 4158 wc_add_to_cart_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId; 4159 } 4160 }, 4161 }; 4162 4163})(jQuery); 4164 4165(function($) { 4166 4167 $(function() { 4168 4169 new FLBuilderMenu({ 4170 id: '5cbecd6eb2e4a', 4171 type: 'vertical', 4172 mobile: 'expanded', 4173 mobileBelowRow: false, 4174 mobileFlyout: false, 4175 breakPoints: { 4176 large: 1200, 4177 medium: 1024, 4178 small: 750 }, 4179 mobileBreakpoint: 'mobile', 4180 postId : '75', 4181 mobileStacked: true, 4182 submenuIcon: 'none', 4183 flyoutWidth: '250', 4184 }); 4185 4186 }); 4187 4188})(jQuery); 4189 4190/* Start Layout Custom JS */ 4191 4192/* End Layout Custom JS */ 4193 4194
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.