1/** 2 * Bybit Exact Menu JavaScript 3 * ТоÑÐ½Ð°Ñ ÑÑнкÑионалÑноÑÑÑ Ð¼ÐµÐ½Ñ ÐºÐ°Ðº на Bybit.com 4 */ 5 6(function($) { 7 'use strict'; 8 9 if (typeof $ === 'undefined' || typeof jQuery === 'undefined') { 10 return; 11 } 12 13 function setCssIfChanged($element, property, value) { 14 if (!$element || !$element.length) { 15 return; 16 } 17 18 if ($element.css(property) !== value) { 19 $element.css(property, value); 20 } 21 } 22 23 function initializeMenu() { 24 try { 25 initBybitMenu(); 26 27 setTimeout(function() { 28 const $toggle = $('.bybit-navbar__mobile-toggle'); 29 const $mobileMenu = $('.bybit-navbar__mobile-menu'); 30 31 if ($toggle.length > 0 && $mobileMenu.length > 0) { 32 try { 33 const events = $._data($toggle[0], 'events'); 34 if (!events || !events.click || !events.click.some(function(handler) { 35 return handler.namespace === 'bybitMobileMenu' || handler.namespace === 'bybitMobileMenuDirect'; 36 })) { 37 initMobileMenu(); 38 } 39 } catch (error) { 40 initMobileMenu(); 41 } 42 } else { 43 setTimeout(function() { 44 if ($('.bybit-navbar__mobile-toggle').length > 0 && $('.bybit-navbar__mobile-menu').length > 0) { 45 initMobileMenu(); 46 } 47 }, 1000); 48 } 49 }, 500); 50 } catch (error) { 51 return; 52 } 53 } 54 55 if (document.readyState === 'loading') { 56 $(document).ready(initializeMenu); 57 } else { 58 initializeMenu(); 59 } 60 61 function initBybitMenu() { 62 try { 63 adjustForAdminBar(); 64 initMobileMenu(); 65 initSearch(); 66 initDropdowns(); 67 initUserMenu(); 68 initAuthControls(); 69 initLanguageSelector(); 70 initOverflowMenu(); 71 handleScroll(); 72 } catch (error) { 73 return; 74 } 75 76 $(window).on('resize', function() { 77 setTimeout(adjustForAdminBar, 100); 78 initOverflowMenu(); 79 }); 80 81 let checkCount = 0; 82 const checkInterval = setInterval(function() { 83 adjustForAdminBar(); 84 checkCount++; 85 if (checkCount >= 3) { 86 clearInterval(checkInterval); 87 } 88 }, 500); 89 } 90 91 // v2.17.940: Create auth controls in the browser so crawlers do not receive login links in HTML. 92 function initAuthControls() { 93 $('[data-auth-control]').each(function() { 94 const placeholder = this; 95 const label = placeholder.getAttribute('data-auth-label') || 'Log In'; 96 const mode = placeholder.getAttribute('data-auth-control') || 'desktop'; 97 const authUrl = buildAuthUrl(); 98 99 if (!authUrl) { 100 return; 101 } 102 103 const button = document.createElement('button'); 104 button.type = 'button'; 105 button.className = mode === 'mobile' ? 'bybit-navbar__mobile-login' : 'bybit-navbar__login-btn'; 106 button.textContent = label; 107 button.addEventListener('click', function() { 108 window.location.href = authUrl; 109 }); 110 111 placeholder.replaceWith(button); 112 }); 113 } 114 115 // v1: language prefix of the current URL ('/de'), '' on the default-language root 116 function getLanguagePrefix() { 117 const match = (window.location.pathname || '/').match(/^\/(en|ru|de|ar|lv)(?:\/|$)/); 118 return match ? '/' + match[1] : ''; 119 } 120 121 // v2: prefix taken from the current URL, no language is assumed to be the default 122 function buildAuthUrl() { 123 return window.location.origin + getLanguagePrefix() + '/traders-access/?redirect_to=' + encodeURIComponent(window.location.href); 124 } 125 126 function adjustForAdminBar() { 127 let adminBar = $('#wpadminbar'); 128 if (adminBar.length === 0) { 129 adminBar = $('.admin-bar #wpadminbar'); 130 } 131 if (adminBar.length === 0) { 132 adminBar = $('body.admin-bar').find('#wpadminbar'); 133 } 134 135 const $navbar = $('.bybit-navbar'); 136 const $mobileMenu = $('.bybit-navbar__mobile-menu'); 137 const $body = $('body'); 138 139 if (adminBar.length > 0 && adminBar.is(':visible')) { 140 const adminBarHeight = adminBar.outerHeight() || 32; 141 const menuHeight = $navbar.outerHeight() || 64; 142 const totalOffset = adminBarHeight + menuHeight; 143 144 setCssIfChanged($navbar, 'top', adminBarHeight + 'px'); 145 setCssIfChanged($navbar, 'z-index', '99999'); 146 setCssIfChanged($body, 'padding-top', totalOffset + 'px'); 147 setCssIfChanged($mobileMenu, 'top', adminBarHeight + 'px'); 148 $body.addClass('bybit-admin-bar-detected'); 149 } else { 150 const isMobile = $(window).width() <= 768; 151 const menuOffset = isMobile ? '56px' : '64px'; 152 setCssIfChanged($navbar, 'top', '0px'); 153 setCssIfChanged($navbar, 'z-index', '999'); 154 setCssIfChanged($body, 'padding-top', menuOffset); 155 setCssIfChanged($mobileMenu, 'top', '0px'); 156 $body.removeClass('bybit-admin-bar-detected'); 157 } 158 } 159 160 // Mobile Menu 161 // v2.18: mobile drawer with overlay, focus trap and scroll lock. 162 function initMobileMenu() { 163 const toggle = document.querySelector('.bybit-navbar__mobile-toggle'); 164 const drawer = document.querySelector('.bybit-navbar__mobile-menu'); 165 166 if (!toggle || !drawer) { 167 return; 168 } 169 170 if (toggle.dataset.drawerReady === '1') { 171 return; 172 } 173 toggle.dataset.drawerReady = '1'; 174 175 const navbar = document.querySelector('.bybit-navbar'); 176 const closeBtn = drawer.querySelector('.bybit-navbar__mobile-close');
177 const overlay = document.querySelector('[data-menu-overlay]'); 178 const openLabel = toggle.getAttribute('aria-label') || 'Open menu'; 179 const closeLabel = closeBtn ? (closeBtn.getAttribute('aria-label') || 'Close menu') : 'Close menu'; 180 const focusableSelector = 'a[href], button:not([disabled]), input:not([disabled]), select, textarea, [tabindex]:not([tabindex="-1"])'; 181 182 let lastFocused = null; 183 let scrollbarCompensation = 0; 184 185 function isOpen() { 186 return drawer.classList.contains('active'); 187 } 188 189 function visibleFocusables() { 190 return Array.prototype.filter.call( 191 drawer.querySelectorAll(focusableSelector), 192 function(el) { 193 return el.offsetWidth > 0 || el.offsetHeight > 0 || el === document.activeElement; 194 } 195 ); 196 } 197 198 function lockScroll() { 199 scrollbarCompensation = window.innerWidth - document.documentElement.clientWidth; 200 document.body.classList.add('bybit-menu-open'); 201 if (scrollbarCompensation > 0) { 202 document.body.style.paddingRight = scrollbarCompensation + 'px'; 203 } 204 } 205 206 function unlockScroll() { 207 document.body.classList.remove('bybit-menu-open'); 208 document.body.style.paddingRight = ''; 209 } 210 211 function openDrawer() { 212 if (isOpen()) { 213 return; 214 } 215 216 lastFocused = document.activeElement; 217 218 if (overlay) { 219 overlay.hidden = false; 220 // force reflow so the fade-in actually runs 221 void overlay.offsetWidth; 222 overlay.classList.add('active'); 223 } 224 225 drawer.classList.add('active'); 226 toggle.classList.add('active'); 227 toggle.setAttribute('aria-expanded', 'true'); 228 toggle.setAttribute('aria-label', closeLabel); 229 lockScroll(); 230 231 const focusTarget = closeBtn || visibleFocusables()[0]; 232 if (focusTarget) { 233 window.setTimeout(function() { focusTarget.focus(); }, 60); 234 } 235 } 236 237 function closeDrawer(returnFocus) { 238 if (!isOpen()) { 239 return; 240 } 241 242 drawer.classList.remove('active'); 243 toggle.classList.remove('active'); 244 toggle.setAttribute('aria-expanded', 'false'); 245 toggle.setAttribute('aria-label', openLabel); 246 247 if (overlay) { 248 overlay.classList.remove('active'); 249 window.setTimeout(function() { 250 if (!isOpen()) { 251 overlay.hidden = true; 252 } 253 }, 260); 254 } 255 256 unlockScroll(); 257 258 drawer.querySelectorAll('.bybit-navbar__mobile-item.expanded').forEach(function(item) { 259 item.classList.remove('expanded'); 260 const btn = item.querySelector('.bybit-navbar__mobile-toggle-btn'); 261 if (btn) { 262 btn.setAttribute('aria-expanded', 'false'); 263 } 264 }); 265 266 if (returnFocus !== false && lastFocused && typeof lastFocused.focus === 'function') { 267 lastFocused.focus(); 268 } 269 } 270 271 toggle.addEventListener('click', function(event) { 272 event.preventDefault(); 273 event.stopPropagation(); 274 if (isOpen()) { 275 closeDrawer(); 276 } else { 277 openDrawer(); 278 } 279 }); 280 281 if (closeBtn) { 282 closeBtn.addEventListener('click', function(event) { 283 event.preventDefault(); 284 closeDrawer(); 285 }); 286 } 287 288 if (overlay) { 289 overlay.addEventListener('click', function() { 290 closeDrawer(); 291 }); 292 } 293 294 document.addEventListener('click', function(event) { 295 if (!isOpen()) { 296 return; 297 } 298 if (drawer.contains(event.target) || (navbar && navbar.contains(event.target))) { 299 return; 300 } 301 closeDrawer(false); 302 }); 303 304 // Navigating away from the drawer should not leave it open behind the new page 305 drawer.addEventListener('click', function(event) { 306 const link = event.target.closest('a[href]'); 307 if (link && !link.classList.contains('bybit-navbar__language-option')) { 308 closeDrawer(false); 309 } 310 }); 311 312 document.addEventListener('keydown', function(event) { 313 if (!isOpen()) { 314 return; 315 } 316 317 if (event.key === 'Escape') { 318 event.preventDefault(); 319 closeDrawer(); 320 return; 321 } 322 323 if (event.key !== 'Tab') { 324 return; 325 } 326 327 const focusables = visibleFocusables(); 328 if (!focusables.length) { 329 return; 330 } 331 332 const first = focusables[0]; 333 const last = focusables[focusables.length - 1]; 334 335 if (event.shiftKey && document.activeElement === first) { 336 event.preventDefault(); 337 last.focus(); 338 } else if (!event.shiftKey && document.activeElement === last) { 339 event.preventDefault(); 340 first.focus(); 341 } else if (!drawer.contains(document.activeElement)) { 342 event.preventDefault(); 343 first.focus(); 344 } 345 }); 346 347 window.addEventListener('resize', function() { 348 if (window.innerWidth >= 900 && isOpen()) { 349 closeDrawer(false); 350 } 351 }); 352 353 // Accordion disclosure 354 drawer.querySelectorAll('.bybit-navbar__mobile-toggle-btn').forEach(function(btn
354) { 355 btn.addEventListener('click', function(event) { 356 event.preventDefault(); 357 event.stopPropagation(); 358 359 const item = btn.closest('.bybit-navbar__mobile-item'); 360 if (!item) { 361 return; 362 } 363 364 const willExpand = !item.classList.contains('expanded'); 365 366 drawer.querySelectorAll('.bybit-navbar__mobile-item.expanded').forEach(function(other) { 367 if (other === item) { 368 return; 369 } 370 other.classList.remove('expanded'); 371 const otherBtn = other.querySelector('.bybit-navbar__mobile-toggle-btn'); 372 if (otherBtn) { 373 otherBtn.setAttribute('aria-expanded', 'false'); 374 } 375 }); 376 377 item.classList.toggle('expanded', willExpand); 378 btn.setAttribute('aria-expanded', willExpand ? 'true' : 'false'); 379 }); 380 }); 381 } 382 383 // Search Functionality 384 function initSearch() { 385 const $searchBtn = $('.bybit-navbar__search-btn'); 386 const $searchDropdown = $('.bybit-navbar__search-dropdown'); 387 const $searchInput = $('.bybit-navbar__search-input'); 388 const $mobileSearchInput = $('.bybit-navbar__mobile-search-input'); 389 390 $searchBtn.on('click', function(e) { 391 e.preventDefault(); 392 e.stopPropagation(); 393 394 const isActive = $searchDropdown.hasClass('active'); 395 396 if (isActive) { 397 closeSearch(); 398 } else { 399 openSearch(); 400 } 401 }); 402 403 // Close on outside click 404 $(document).on('click', function(e) { 405 if (!$(e.target).closest('.bybit-navbar__search').length && $searchDropdown.hasClass('active')) { 406 closeSearch(); 407 } 408 }); 409 410 // Close on escape 411 $(document).on('keydown', function(e) { 412 if (e.keyCode === 27 && $searchDropdown.hasClass('active')) { 413 closeSearch(); 414 } 415 }); 416 417 // Handle search input (desktop) 418 $searchInput.on('keydown', function(e) { 419 if (e.keyCode === 13) { // Enter 420 e.preventDefault(); 421 performSearch($(this).val()); 422 } 423 }); 424 425 // Handle mobile search input 426 $mobileSearchInput.on('keydown', function(e) { 427 if (e.keyCode === 13) { // Enter 428 e.preventDefault(); 429 performSearch($(this).val()); 430 } 431 }); 432 433 function openSearch() { 434 $searchDropdown.addClass('active'); 435 setTimeout(() => { 436 $searchInput.focus(); 437 }, 100); 438 } 439 440 function closeSearch() { 441 $searchDropdown.removeClass('active'); 442 $searchInput.val(''); 443 } 444 445 // v2: keep whatever language prefix the current URL has 446 function performSearch(query) { 447 if (query.trim()) { 448 window.location.href = getLanguagePrefix() + '/?s=' + encodeURIComponent(query.trim()); 449 } 450 } 451 } 452 453 // Dropdown Menus 454 function initDropdowns() { 455 const $menuItems = $('.bybit-navbar__menu-item.has-dropdown'); 456 let hoverTimeout; 457 458 $menuItems.each(function() { 459 const $item = $(this); 460 const $dropdown = $item.find('.bybit-navbar__dropdown'); 461 462 $item.on('mouseenter', function() { 463 clearTimeout(hoverTimeout); 464 $dropdown.addClass('show'); 465 }); 466 467 $item.on('mouseleave', function() { 468 hoverTimeout = setTimeout(() => { 469 $dropdown.removeClass('show'); 470 }, 150); 471 }); 472 473 // Handle keyboard navigation 474 $item.find('a').first().on('keydown', function(e) { 475 if (e.keyCode === 40) { // Arrow down 476 e.preventDefault(); 477 $dropdown.addClass('show'); 478 $dropdown.find('a').first().focus(); 479 } 480 }); 481 482 $dropdown.find('a').on('keydown', function(e) { 483 const $links = $dropdown.find('a'); 484 const currentIndex = $links.index(this); 485 486 if (e.keyCode === 38) { // Arrow up 487 e.preventDefault(); 488 if (currentIndex > 0) { 489 $links.eq(currentIndex - 1).focus(); 490 } else { 491 $item.find('a').first().focus(); 492 $dropdown.removeClass('show'); 493 } 494 } else if (e.keyCode === 40) { // Arrow down 495 e.preventDefault(); 496 if (currentIndex < $links.length - 1) { 497 $links.eq(currentIndex + 1).focus(); 498 } 499 } else if (e.keyCode === 27) { // Escape 500 e.preventDefault(); 501 $dropdown.removeClass('show'); 502 $item.find('a').first().focus(); 503 } 504 }); 505 506}); 507 508 // Close dropdowns on outside click 509 $(document).on('click', function(e) { 510 if (!$(e.target).closest('.bybit-navbar__menu-item').length) { 511 $('.bybit-navbar__dropdown').removeClass('show'); 512 } 513 }); 514 } 515 516 // User Menu 517 function initUserMenu() { 518 const $userMenu = $('.bybit-navbar__user-menu'); 519 const $userDropdown = $('.bybit-navbar__user-dropdown'); 520 let userHoverTimeout; 521 522 $userMenu.on('mouseenter', function() { 523 clearTimeout(userHoverTimeout); 524 $userDropdown.addClass('show'); 525 }); 526 527 $userMenu.on('mouseleave', function() { 528 userHoverTimeout = setTimeout(() => { 529 $userDropdown.removeClass('show'); 530 }, 150); 531 }); 532 533 // Close on outside click 534 $(document).on('click', function(e) { 535 if (!$(e.target).closest('.bybit-navbar__user-menu').length) { 536 $userDropdown.removeClass('show'); 537 } 538 }); 539 } 540 541 // Language Selector 542 function initLanguageSelector() { 543 $('.bybit-navbar__language-toggle').off('click.languageSwitch'); 544 $('.bybit-navbar__language-option').off('click.languageSwitch'); 545 $(document).off('click.languageSwitch'); 546 $(document).off('keydown.languageSwitch'); 547 548 function closeLanguageMenus() { 549 $('.bybit-navbar__language.is-open, .bybit-navbar__mobile-language.is-open').removeClass('is-open'); 550 $('.bybit-navbar__language-toggle').attr('aria-expanded', 'false'); 551 } 552 553 $('.bybit-navbar__language-toggle').on('click.languageSwitch', function(e) { 554 e.preventDefault(); 555 e.stopPropagation(); 556 557 const $wrap = $(this).closest('.bybit-navbar__language, .bybit-navbar__mobile-language'); 558 const isOpen = $wrap.hasClass('is-open'); 559 560 closeLanguageMenus(); 561 562 if (!isOpen) { 563 $wrap.addClass('is-open'); 564 $(this).attr('aria-expanded', 'true'); 565 } 566 }); 567 568 $('.bybit-navbar__language-option.is-current').on('click.languageSwitch', function(e) { 569 e.preventDefault(); 570 closeLanguageMenus(); 571 }); 572 573 $(document).on('click.languageSwitch', function(e) { 574 if (!$(e.target).closest('.bybit-navbar__language, .bybit-navbar__mobile-language').length) { 575 closeLanguageMenus(); 576 } 577 }); 578 579 $(document).on('keydown.languageSwitch', function(e) { 580 if (e.key === 'Escape' || e.keyCode === 27) { 581 closeLanguageMenus(); 582 } 583 }); 584 } 585 586 // Scroll handling 587 function handleScroll() { 588 const $navbar = $('.bybit-navbar'); 589 let isScrolled = false;
590 591 $(window).on('scroll', function() { 592 const scrollTop = $(window).scrollTop(); 593 594 // Get admin bar height if exists 595 const adminBarHeight = $('body').hasClass('admin-bar') ? 596 ($(window).width() > 782 ? 32 : 46) : 0; 597 598 if (scrollTop > adminBarHeight && !isScrolled) { 599 $navbar.addClass('scrolled'); 600 isScrolled = true; 601 } else if (scrollTop <= adminBarHeight && isScrolled) { 602 $navbar.removeClass('scrolled'); 603 isScrolled = false; 604 } 605 }); 606 } 607 608 // Add smooth scrolling for anchor links 609 $('a[href^="#"]').on('click', function(e) { 610 const target = $(this.hash); 611 if (target.length) { 612 e.preventDefault(); 613 614 // Calculate offset based on admin bar and menu height 615 let offset = 64; // Default menu height 616 617 // Check for admin bar 618 if ($('body').hasClass('admin-bar')) { 619 const adminBarHeight = $(window).width() > 782 ? 32 : 46; 620 offset += adminBarHeight; 621 } 622 623 // Adjust for mobile 624 if ($(window).width() <= 768) { 625 offset = $('body').hasClass('admin-bar') ? 102 : 56; 626 } 627 628 $('html, body').animate({ 629 scrollTop: target.offset().top - offset 630 }, 600); 631 } 632 }); 633 634 // Prevent body scroll when mobile menu is open 635 const style = document.createElement('style'); 636 style.textContent = ` 637 body.bybit-menu-open { 638 overflow: hidden; 639 position: fixed; 640 width: 100%; 641 } 642 `; 643 document.head.appendChild(style); 644 645 // Horizontal progress bar under logo with unique class 646 $(window).on('beforeunload', function() { 647 $('.bybit-navbar').addClass('bybit-logo-progress'); 648 setTimeout(function() { 649 $('.bybit-navbar').removeClass('bybit-logo-progress'); 650 }, 2200); 651 }); 652 653 // Aggressively remove old spinners on initialization 654 $(document).ready(function() { 655 // Remove all potential conflicting spinners 656 $('.nav_wrap.loading').removeClass('loading'); 657 $('.loadingform').removeClass('loadingform'); 658 $('.arcticmodal-loading, .owl-loading').hide(); 659 660 // Hide any spinners that might appear in navbar 661 $('.bybit-navbar').find('.spinner, .loader, .spinner-wrap, .loader-wrap, [class*="spinner"], [class*="loader"]').hide().remove(); 662 663 // Prevent future conflicts by intercepting old loading additions 664 var originalAddClass = $.fn.addClass; 665 $.fn.addClass = function(className) { 666 if (this.hasClass('bybit-navbar') && className === 'loading') { 667 return this; // Prevent adding 'loading' to bybit-navbar, only allow 'bybit-logo-progress' 668 } 669 return originalAddClass.call(this, className); 670 }; 671 }); 672 673 // v2.18: priority+ navigation. Items that do not fit the row move into "More". 674 function initOverflowMenu() { 675 const nav = document.querySelector('.bybit-navbar__nav'); 676 const menu = nav ? nav.querySelector('.bybit-navbar__menu') : null; 677 const overflowMenu = nav ? nav.querySelector('.bybit-navbar__overflow-menu') : null; 678 const dropdown = overflowMenu ? overflowMenu.querySelector('.bybit-navbar__overflow-dropdown') : null; 679 const toggle = overflowMenu ? overflowMenu.querySelector('.bybit-navbar__overflow-toggle') : null; 680 681 if (!nav || !menu || !overflowMenu || !dropdown || !toggle) { 682 return; 683 } 684 685 if (nav.dataset.overflowReady === '1') { 686 if (typeof nav._ftOverflowLayout === 'function') { 687 nav._ftOverflowLayout(); 688 } 689 return; 690 } 691 nav.dataset.overflowReady = '1'; 692 693 const items = Array.prototype.slice.call(menu.querySelectorAll('.bybit-navbar__menu-item')); 694 if (!items.length) { 695 return; 696 } 697 698 let metrics = null; 699 let lastVisibleCount = -1; 700 let frame = null; 701 702 function measureKey() { 703 const link = items[0].querySelector('.bybit-navbar__menu-link'); 704 if (!link) { 705 return 'na'; 706 } 707 const style = window.getComputedStyle(link); 708 return style.fontSize + '|' + style.paddingLeft; 709 } 710 711 function measure() { 712 const restore = items.map(function(item) { return item.hidden; }); 713 const overflowWasHidden = overflowMenu.hidden; 714
715 items.forEach(function(item) { item.hidden = false; }); 716 overflowMenu.hidden = false; 717 718 const widths = items.map(function(item) { 719 return Math.ceil(item.getBoundingClientRect().width); 720 }); 721 const toggleWidth = Math.ceil(overflowMenu.getBoundingClientRect().width); 722 const gap = parseFloat(window.getComputedStyle(menu).columnGap) || 0; 723 724 items.forEach(function(item, index) { item.hidden = restore[index]; }); 725 overflowMenu.hidden = overflowWasHidden; 726 727 return { widths: widths, toggleWidth: toggleWidth, gap: gap, key: measureKey() }; 728 } 729 730 function getMetrics() { 731 if (!metrics || metrics.key !== measureKey() || !metrics.widths.length) { 732 metrics = measure(); 733 } 734 return metrics; 735 } 736 737 function buildDropdown(hiddenItems) { 738 const fragment = document.createDocumentFragment(); 739 740 hiddenItems.forEach(function(item) { 741 const group = document.createElement('div'); 742 group.className = 'bybit-navbar__overflow-group'; 743 744 const link = item.querySelector('.bybit-navbar__menu-link'); 745 if (link) { 746 const parentLink = document.createElement('a'); 747 parentLink.className = 'bybit-navbar__overflow-link bybit-navbar__overflow-link--parent'; 748 parentLink.href = link.getAttribute('href') || '#'; 749 parentLink.textContent = link.textContent.trim(); 750 group.appendChild(parentLink); 751 } 752 753 item.querySelectorAll('.bybit-navbar__dropdown-link').forEach(function(sub) { 754 const childLink = document.createElement('a'); 755 childLink.className = 'bybit-navbar__overflow-link bybit-navbar__overflow-link--child'; 756 childLink.href = sub.getAttribute('href') || '#'; 757 childLink.textContent = sub.textContent.trim(); 758 group.appendChild(childLink); 759 }); 760 761 fragment.appendChild(group); 762 }); 763 764 dropdown.innerHTML = ''; 765 dropdown.appendChild(fragment); 766 } 767 768 function closeOverflow() { 769 overflowMenu.classList.remove('is-open'); 770 toggle.setAttribute('aria-expanded', 'false'); 771 } 772 773 function apply(visibleCount) { 774 if (visibleCount === lastVisibleCount) { 775 return; 776 } 777 lastVisibleCount = visibleCount; 778 779 items.forEach(function(item, index) { 780 item.hidden = index >= visibleCount; 781 }); 782 783 const hiddenItems = items.slice(visibleCount); 784 if (!hiddenItems.length) { 785 overflowMenu.hidden = true; 786 dropdown.innerHTML = ''; 787 closeOverflow(); 788 return; 789 } 790 791 overflowMenu.hidden = false; 792 buildDropdown(hiddenItems); 793 } 794 795 function layout() { 796 frame = null; 797 798 const available = nav.clientWidth; 799 if (!available) { 800 // Nav is hidden (drawer range): force a recalculation when it returns. 801 lastVisibleCount = -1; 802 return; 803 } 804 805 const data = getMetrics(); 806 const totalAll = data.widths.reduce(function(sum, width) { return sum + width; }, 0) 807 + data.gap * Math.max(items.length - 1, 0); 808 809 if (totalAll <= available) { 810 apply(items.length); 811 return; 812 } 813 814 const budget = available - data.toggleWidth - data.gap; 815 let used = 0; 816 let visibleCount = 0; 817 818 for (let i = 0; i < items.length; i++) { 819 const width = data.widths[i] + (i > 0 ? data.gap : 0); 820 if (used + width > budget) { 821 break; 822 } 823 used += width; 824 visibleCount++; 825 } 826 827 apply(Math.max(visibleCount, 1)); 828 } 829 830 function scheduleLayout() { 831 if (frame) { 832 return; 833 } 834 frame = window.requestAnimationFrame(layout); 835 } 836 837 toggle.addEventListener('click', function(event) { 838 event.preventDefault(); 839 event.stopPropagation(); 840 const isOpen = overflowMenu.classList.toggle('is-open'); 841 toggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); 842 }); 843 844 document.addEventListener('click', function(event) { 845 if (!overflowMenu.contains(event.target)) { 846 closeOverflow(); 847 } 848 }); 849 850 document.addEventListener('keydown', function(event) { 851 if (event.key === 'Escape' && overflowMenu.classList.contains('is-open')) { 852 closeOverflow(); 853 toggle.focus(); 854 } 855 }); 856 857 if (typeof ResizeObserver !== 'undefined') { 858 new ResizeObserver(scheduleLayout).observe(nav); 859 } 860 window.addEventListener('resize', scheduleLayout); 861 862 if (document.fonts && document.fonts.ready) { 863 document.fonts.ready.then(function() { 864 metrics = null; 865 lastVisibleCount = -1; 866 scheduleLayout(); 867 }); 868 } 869 870 nav._ftOverflowLayout = scheduleLayout; 871 scheduleLayout(); 872 } 873 874})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.