1// Build the submenu (Desktop and Mobile) 2 3// TODO: 4// Hide h2:after on Desktop 5// Mobile behavior: add .toggled class and show hidden child(link-section-links) when h2 is clicked 6 7// setTimeout before display:none so fade animation can run 8// fade animation run on blur BG as well, so it fades before disappearing 9 10let menuJSON = null; 11let submenuJSON = null; 12let submenuContent; 13let submenu; 14let content; 15let elementsCache = {}; 16let menuIsHovered; 17let cbData = null; 18let istimer = false; 19let continuityBar; 20 21addEventListener('DOMContentLoaded', (event) => { 22// Check if the custom element is already defined 23 if (!customElements.get('continuity-bar')) { 24 // Define the custom element 25 customElements.define('continuity-bar', ContinuityBar); 26 } 27 28 if (!document.querySelector('continuity-bar')) { 29 continuityBar = document.createElement('continuity-bar'); 30 document.body.insertBefore(continuityBar, document.body.firstChild); 31 } 32 33 // TODO: 34 // All Courses Layout 35 // Spec layout 36 // Add 'all blah blah blah' links at bottom 37 // Add ability to switch between lists & cards with a key (it's just an if/else with the builder functions) 38 // Which layouts are no longer used? 39 // Just need 3 and 4. We'll call that 2 and 3 now. 40 41 submenu = document.getElementById('main-menu'); 42 submenuContent = document.getElementById('nasm-submenu'); 43 44 // Get JSON data here. Assume Tabs is an array. 45 // DON'T fetch nasm-submenu.json until the user mouses over a menu item 46 // Menu options (not submenu) are their own, much smaller, file 47 48 checkLayout(); 49 window.addEventListener('resize', checkLayout); 50}); 51 52function buildSubmenu(isMobile) { 53 // submenuContent.innerHTML = ''; 54 55 if (menuJSON == null) { 56 if ($('.continuity-bar-nav')) { 57 // Find and remove any existing continuity-bar-nav 58 $('.continuity-bar-nav').remove(); 59 } 60 61 // fetch menu JSON (only once) 62 $.getJSON('/docs/nasmlibraries/json/nasm-menu.json', (data) => { 63 $.getJSON('https://www.nasm.org/docs/nasmlibraries/json/nasm-continuity-bar.json', (data2) => { 64 // Get the JSON for the Continuity Bar and build it out, only if the initial menuJSON was null 65 66 if (data.timer == true) { 67 istimer = true; 68 } 69 70 // buildContinuityBar(data2, "continuity", data["timer"]); 71 // const intervalID = setInterval(function() {runSlickForNav(intervalID)}, 200); 72 // Passing key in manually to avoid cycling through all keys again 73 // Clear out any pre-existing Continuity Bar in case resizing window. Must remove completely. 74 // Also important to strip out the placeholder 75 // Then rebuild it 76 77 if (!customElements.get('continuity-bar')) { 78 // Define the custom element 79 customElements.define('continuity-bar', ContinuityBar); 80 } 81 82 if (!document.querySelector('continuity-bar')) { 83 continuityBar = document.createElement('continuity-bar'); 84 document.body.insertBefore(continuityBar, document.body.firstChild); 85 } 86 87 cbData = data2; 88 }); 89 90 menuJSON = data; 91 92 createElements(isMobile, menuJSON, submenu); 93 }); 94 } else { 95 createElements(isMobile, menuJSON, submenu); 96 // buildContinuityBar(cbData, "continuity", istimer); 97 98 if (!customElements.get('continuity-bar')) { 99 // Define the custom element 100 customElements.define('continuity-bar', ContinuityBar); 101 } 102 103 if (!document.querySelector('continuity-bar')) { 104 continuityBar = document.createElement('continuity-bar'); 105 document.body.insertBefore(continuityBar, document.body.firstChild); 106 } 107 } 108} 109 110function createElements(isMobile, menuJSON, submenu) { 111 const searchDropdown = document.getElementById('search-dropdown'); 112 113 searchDropdown.addEventListener('mouseleave', () => { 114 setTimeout(() => { 115 // setTimeout to avoid feeling of a "hair trigger" 116 117 document.getElementById('nav_bg_overlay').style.width = '100%'; 118 document.getElementById('nav_bg_overlay').style.height = '0'; 119 // Close search bar and set blur div height to 0 to remove blur 120 // when mouse pointer leaves search bar 121 122 $('.search-dropdown-hide').toggle(); 123 $('.search-wrapper').toggle(); 124 // Hide search bar, as well 125 126 // TODO: very fast, slight fade 127 }, 300); 128 }); 129 130 const div1 = document.querySelector('#navWrapper'); 131 const div2 = document.querySelector('#nasm-submenu'); 132 133 div1.addEventListener('mouseleave', checkCloseSubmenu); 134 div2.addEventListener('mouseleave', checkCloseSubmenu); 135 136 function checkCloseSubmenu() { 137 const isDiv1Hovered = div1.matches(':hover'); 138 const isDiv2Hovered = div2.matches(':hover'); 139 140 if (!isDiv1Hovered && !isDiv2Hovered) { 141 hideSubmenu(); 142 } 143 } 144 145 if (!document.querySelector('.option')) { 146 // Only build the menu if the menu options don't exist 147 // No need to rebuild or re-attach event listeners 148 149 optionContainer = document.createElement('ul'); 150 151 menuJSON.menu.forEach((option, index) => { 152 let optionElement; 153 154 if (option.visible == true) { 155 optionElement = document.createElement('li'); 156 // Only populate with menu items that are intended to be visible 157 158 optionElement.className = 'option'; 159 optionElement.classList.add(`blueMouseover-${index}`); 160 optionElement.textContent = option.title; 161 optionElement.dataset.index = index; 162 optionContainer.appendChild(optionElement); 163 164 if (window.innerWidth < 1440) { 165 optionElement.removeEventListener('click', buildDesktopSubmenu.bind(this, optionElement, index, isClick = true)); 166 // Could use a curried function, but don't feel up to that level of refactoring at the moment 167 // .bind will do 168 // Remember the first two arguments before your params 169 // Remove Desktop event listener, if it existed 170 171 // TODO: fetch & cache submenu JSON only on first click 172 optionElement.addEventListener('click', buildMobileSubmenu.bind(this, optionElement)); 173 } else { 174 const hideOnDesktop = document.querySelector('#hideOnDesktop'); 175 hideOnDesktop.style = ''; 176 177 const slideoutSearch = document.querySelector('.slideout-search'); 178 slideoutSearch.style = ''; 179 180 const sideNav = document.querySelector('#mySidenav'); 181 sideNav.style = ''; 182 183 const mainMenu = document.querySelector('#main-menu'); 184 mainMenu.style = ''; 185 186 optionElement.removeEventListener('click', buildMobileSubmenu.bind(this, optionElement)); 187 // Remove mobile event listener, if it existed 188 189 optionElement.addEventListener('mouseenter', buildDesktopSubmenu.bind(this, optionElement, index, isClick = false)); 190 optionElement.addEventListener('click', buildDesktopSubmenu.bind(this, optionElement, index, isClick = true)); 191 } 192 } 193 }); 194 submenu.appendChild(optionContainer); 195 } else if (window.innerWidth >= 1440) { 196 // On desktop, we may have resized from mobile 197 // Options may be there, but styles need to be reset 198 199 const sideNav = document.getElementById('mySidenav'); 200 sideNav.style = ''; 201 202 const search = document.querySelector('.search-wrapper-mobile'); 203 search.style = ''; 204 205 const slideoutSearch = document.querySelector('.slideout-search'); 206 slideoutSearch.style = ''; 207 208 const mobileHelpDiv = document.getElementById('hideOnDesktop'); 209 mobileHelpDiv.style = ''; 210 211 submenu.style = ''; 212 213 const options = document.querySelectorAll('.option'); 214 215 options.forEach((optionElement, index) => { 216 optionElement.removeEventListener('click', buildMobileSubmenu); 217 optionElement.addEventListener('mouseenter', buildDesktopSubmenu.bind(this, optionElement, index, isClick = false)); 218 optionElement.addEventListener('click', buildDesktopSubmenu.bind(this, optionElement, index, isClick = true)); 219 }); 220 } 221 222 // const submenu = document.getElementById("main-menu"); 223} 224 225function buildCards(content) { 226 let allCardsDiv = '<div class="submenu-cards">'; 227 228 // Create the beginning of this div. Doing it with string concat 229 // allows us to avoid creating elements/appendChild 230 231 content.cards.forEach((card) => { 232 const { badges } = card; 233 234 if (badges !== undefined) { 235 const badgeDivs = badges.map((badge) => 236 // Map the badge content to individual divs 237 238 `<div class="product-badge">${badge}</div>`).join(''); 239 240 const currentCardDiv = `<a href=${card.url}><div class="nav__mobile--slideout--cardHeader"> 241 <div class="product-badges">${badgeDivs}</div> 242 <div class="slideout--highlight slideout--highlight--item1 slideout--highlight-padding"><div>${card.promoText}</div></div> 243 </div> 244 <div>${card.header}</div></a>`; 245 allCardsDiv += currentCardDiv; 246 // Add the generated card div to the div containing all of the cards 247 } else { 248 currentCardDiv = `<a href="${card.url}"><div> 249 <h4>${card.title}</h4> 250 <p>${card.copy}</p> 251 </div></a>`; 252 allCardsDiv += currentCardDiv; 253 } 254 }); 255 256 if (content.layout == '2') { 257 allCardsDiv += `<p class="more-courses-link-wrapper"> 258 <a class="more-courses-link" href="${content['more-courses-link']}">${content['more-courses-link-text']}</a> 259 </p>`; 260 } 261 262 allCardsDiv += '</div>'; 263 // Close up the div containing all of the cards 264 265 return allCardsDiv; 266} 267 268function addCachedElement() { 269 270} 271 272function renderTabContent(tab, index) { 273 return new Promise((resolve) => { 274 let submenuContent; 275 276 if (window.innerWidth >= 1440) { 277 // Attach direction to submenu div if on Desktop 278 submenuContent = document.getElementById('nasm-submenu'); 279 280 for (const child of submenuContent.children) { 281 if (child.id != `${tab.id}-tab`) { 282 child.style.display = 'none'; 283 } 284 } 285 } else { 286 submenuContent = document.getElementById('main-menu'); 287 } 288 289 if (elementsCache[`${tab.id}-tab`] != undefined && document.getElementById(`${tab.id}-tab`) !== undefined) {
290 // Will rebuild completely for mobile for now - we have to change where it's appended to anyway 291 292 // If the element already exists in cache, use that 293 294 const newTab = document.getElementById(`${tab.id}-tab`); 295 296 newTab.style.display = 'block'; 297 // tab-# is a convention to avoid confusion, could use the number 298 // as a string, but don't want it confused for an array 299 // at first glance 300 } else { 301 // Element has not been buld - build it and cache it 302 let html = ''; 303 304 switch (tab.layout) { 305 case '1': 306 html = renderLayout1(tab, index); 307 308 break; 309 case '2': 310 html = renderLayout2(tab, index); 311 break; 312 case '3': 313 314 html = renderLayout3(tab, index); 315 316 break; 317 case '4': 318 319 html = renderLayout4(tab, index); 320 break; 321 default: 322 html = ''; 323 } 324 325 elementsCache[`${tab.id}-tab`] = html; 326 // add HTML to cache object at 'tab-index' 327 328 if (window.innerWidth < 1440) { 329 submenuContent.innerHTML = html; 330 } else { 331 submenuContent.innerHTML += html; 332 } 333 334 resolve(); 335 toggleMobileOptions(); 336 } 337 }); 338} 339 340function buildSubmenuTab(optionElement, submenuJSON) { 341 if (submenuJSON == null) { 342 // Fallback just in case... make sure JSON is not null 343 344 $.getJSON('/docs/nasmlibraries/json/nasm-submenu.json', (submenudata) => { 345 submenuJSON = submenudata; 346 const thisIndex = optionElement.getAttribute('data-index'); 347 348 renderTabContent(submenudata.tabs[`${thisIndex}`], thisIndex) 349 .then(() => { 350 // Code to run after rendering is complete 351 352 const matchingTab = document.querySelectorAll(`.blueMouseover-${thisIndex}`)[1]; 353 354 const navigationEvent = new CustomEvent(`item${thisIndex}`, { detail: `item${thisIndex}-tab` }); 355 356 if (matchingTab) { 357 matchingTab.addEventListener('mouseenter', (e) => { 358 optionElement.style.borderBottom = '3px solid var(--brand-color-turquoise)'; 359 }); 360 361 matchingTab.addEventListener('mouseleave', (e) => { 362 optionElement.style.borderBottom = '3px solid var(--ui-color-light)'; 363 364 // Remove the border if they leave the tab 365 }); 366 } 367 368 document.dispatchEvent(navigationEvent); 369 }) 370 .catch((error) => { 371 372 }); 373 }); 374 } else { 375 const thisIndex = optionElement.getAttribute('data-index'); 376 377 renderTabContent(submenuJSON.tabs[`${thisIndex}`], thisIndex) 378 .then(() => { 379 // Code to run after rendering is complete 380 381 const navigationEvent = new CustomEvent(`item${thisIndex}`, { detail: `item${thisIndex}-tab` }); 382 // const submenuWrapper = document.getElementById("nasm-submenu"); 383 384 const matchingTab = document.querySelectorAll(`.blueMouseover-${thisIndex}`)[1]; 385 386 if (matchingTab) { 387 // Stop looking for the tab 388 matchingTab.addEventListener('mouseenter', (e) => { 389 optionElement.style.borderBottom = '3px solid var(--brand-color-turquoise)'; 390 }); 391 392 matchingTab.addEventListener('mouseleave', (e) => { 393 optionElement.style.borderBottom = '3px solid var(--ui-color-light)'; 394 // Remove the border if they leave the tab 395 }); 396 } 397 398 document.dispatchEvent(navigationEvent); 399 400 // TO LISTEN FOR THIS EVENT: 401 // const submenuWrapper = document.getElementById("nasm-submenu"); 402 // submenuWrapper.addEventListener("tabRendered", 403 // (e) => { 404 // /* âââ¬Ã¦ */ 405 // }); 406 // then check the detail to see which tab it was, and run code accordingly 407 }) 408 .catch((error) => { 409 console.error('Error occurred during rendering:', error); 410 }); 411 } 412} 413 414function buildList(content) { 415 let linkListDiv = '<div class="submenu-sections">'; 416 417 if (content.learn !== undefined) { 418 const links = content.learn.map((link) => 419 // Map the links to paragraph tags containing links 420 `<p><a href="${link.url}">${link.copy}</a></p>`).join(''); 421 422 linkListDiv += links; 423 // Add the links to the div 424 425 // // Close up the div 426 linkListDiv += '</div>'; 427 // Close up the div 428 429 return linkListDiv; 430 } 431 const linkColumns = content['link-sections']; 432 // Grab the content for the columns 433 434 linkColumns.forEach((column) => { 435 // Create the column and its heading 436 437 let linkColumn = `<div class="link-section"> 438 <h2>${column['heading-copy']}</h2>`; 439 links = column.links.map((link) => `<a href="${link.url}">${link.copy}</a>`).join(''); 440 // Create the links 441 linkColumn += `<div class="link-section-links">${links}</div>`; 442 linkColumn += '</div>'; 443 444 linkListDiv += linkColumn; 445 }); 446 447 linkListDiv += '</div>'; 448 // Close up the div 449 450 return linkListDiv; 451 // Add the column to the div containing the columns 452}
452 453 454function checkLayout() { 455 // Helper function to rebuild menu for smaller breakpoints 456 const blurOverlay = document.getElementById('nav_bg_overlay'); 457 blurOverlay.style = ''; 458 // Remove the blur overlay if it was active 459 460 const searchDropdown = document.querySelector('#search-dropdown'); 461 searchDropdown.style.display = 'none'; 462 // Remove the search dropdown if it's open 463 464 const isMobile = window.innerWidth < 1440; 465 466 if (window.innerWidth < 1440) { 467 if (submenuContent.innerHTML != '') { 468 // If coming from Desktop with an open menu, close it 469 document.getElementById('mySidenav').style.left = '-90%'; 470 471 // If coming from Desktop, reset the blur 472 blurOverlay.style.height = '0'; 473 474 // Reset search display for mobile 475 $('.search-wrapper-mobile').css('display') == 'block'; 476 } 477 478 submenu = document.getElementById('main-menu'); 479 submenu.innerHTML = ''; 480 submenuContent = document.getElementById('nasm-submenu'); 481 submenuContent.innerHTML = ''; 482 483 elementsCache = {}; 484 // for (const child of submenuContent.children) { 485 // child.innerHTML = ''; 486 // child.style.display = "none"; 487 // } 488 489 // Clear existing innerHTML for mobile and reset styles 490 491 if (document.querySelector('.submenu-panels') == null || document.querySelector('.slideout-close-button-mobile') !== null) { 492 // Make sure we haven't just changed to a different tab on mobile 493 // by checking for a div that exists only on tabs 494 495 buildSubmenu(window.innerWidth < 1440); 496 } 497 } else { 498 submenu = document.getElementById('main-menu'); 499 submenu.innerHTML = ''; 500 submenuContent = document.getElementById('nasm-submenu'); 501 submenuContent.innerHTML = ''; 502 elementsCache = {}; 503 buildSubmenu(window.innerWidth < 1440); 504 505 // Just build it on desktop 506 } 507} 508 509//* ************ LAYOUTS ***************/ 510function renderLayout1(content, index) { 511 // Create the HTML for submenu layout 1 512 // Drop in the content 513 // TODO: correct the notation for the form of the content that's passed in 514 515 const allCardsDiv = buildCards(content); 516 517 const linkListDiv = buildList(content); 518 519 const submenuHTML = ` 520 <div id="${content.id}-tab" class="blueMouseover-${index}" data-index="${index}"> 521 <div class="mobile-close-controls"> 522 <p class="slideout-close-button-mobile" onClick="closeSideMenu()">Back</p> 523 <div class="close-nav-desktop" onClick="hideSubmenu()">X</div> 524 </div> 525 526 <section> 527 <h2 class="mobile-nav-header fade-in hideOnDesktop">${content['promoHeader-mobile']}</h2> 528 <p class="mobile-nav-header fade-in hideOnDesktop">${content['promoCopy-mobile']}</p> 529 <a class="mobile-nav-header fade-in hideOnDesktop" href="${content['learn-more-link']}">${content['learn-more-copy-mobile']}</a> 530 <div class="submenu-panels fade-in"> 531 532 <div id="submenu-cards" class="${content.id}-cards"> 533 <h2>${content.title}</h2> 534 ${allCardsDiv} 535 <p class="more-courses-link-wrapper"> 536 <a class="more-courses-link" href="${content['more-courses-link']}">${content['more-courses-link-text']}</a> 537 </p> 538 </div> 539 <div id="submenu-links" class="${content.id}-links"> 540 <h2>${content.title2}</h2> 541 ${linkListDiv} 542 </div> 543 <div id="submenu-image" class="${content.id}-image"> 544 <img src="${content.image}" /> 545 </div> 546 <section class="nav__mobile--slideout--header"> 547 <h2 class="hideOnMobile">${content['promoHeader-desktop']}</h2> 548 <p class="hideOnMobile">${content['promoCopy-desktop']}</p> 549 <a class="hideOnMobile" href="${content['learn-more-link']}">${content['learn-more-copy-desktop']}</a> 550 </section> 551 </div> 552 </section> 553 554 </div> 555 `; 556 return submenuHTML; 557} 558 559function renderLayout2(content, index) { 560 // Create the HTML for submenu layout 2 561 // This used to be Layout 3 562 // Maybe a slightly different card building function, since the cards have different c
562ontent 563 // OR if it has no .badges key (result is undefined), we know it's a different card 564 565 const allCardsDiv = buildCards(content); 566 567 const submenuHTML = ` 568 <div id="${content.id}-tab" class="blueMouseover-${index}" data-index="${index}"> 569 <div class="mobile-close-controls"> 570 <p class="slideout-close-button-mobile" onClick="closeSideMenu()"Back</p> 571 <div class="close-nav-desktop" onClick="hideSubmenu()">X</div> 572 </div> 573 574 <section> 575 <h2 class="mobile-nav-header hideOnDesktop">${content['promoHeader-mobile']}</h2> 576 <p class="mobile-nav-header hideOnDesktop">${content['promoCopy-mobile']}</p> 577 <a class="mobile-nav-header hideOnDesktop" href="${content['learn-more-link']}">${content['learn-more-copy-mobile']}</a> 578 <div class="submenu-panels fade-in"> 579 580 <div id="submenu-cards" class="${content.id}-cards"> 581 <h2>${content.title}</h2> 582 <div class="allCardsDiv-${index}">${allCardsDiv}</div> 583 </div> 584 585 <div id="submenu-image" class="${content.id}-image"> 586 <img src="${content.image}" /> 587 </div> 588 <section class="nav__mobile--slideout--header"> 589 <h2 class="hideOnMobile">${content['promoHeader-desktop']}</h2> 590 <p class="hideOnMobile">${content['promoCopy-desktop']}</p> 591 <a class="hideOnMobile" href="${content['learn-more-link']}">${content['learn-more-copy-desktop']}</a> 592 </section> 593 </div> 594 </section> 595 596 </div> 597 `; 598 599 return submenuHTML; 600} 601 602function renderLayout3(content, index) { 603 // Create the HTML for submenu layout 3 604 // Resources tab 605 606 const linkListDiv = buildList(content); 607 608 const submenuHTML = ` 609 <div id="${content.id}-tab" class="blueMouseover-${index}" data-index="${index}"> 610 <div class="mobile-close-controls"> 611 <p class="slideout-close-button-mobile" onClick="closeSideMenu()">Back</p> 612 <div class="close-nav-desktop" onClick="hideSubmenu()">X</div> 613 </div> 614 615 <section id="submenu-cards"> 616 <h2 class="mobile-nav-header hideOnDesktop">${content['promoHeader-mobile']}</h2> 617 <p class="mobile-nav-header hideOnDesktop">${content['promoCopy-mobile']}</p> 618 <a class="mobile-nav-header hideOnDesktop" href="${content['learn-more-link']}">${content['learn-more-copy-mobile']}</a> 619 <div class="submenu-panels"> 620 621 <div class="link-section-columns">${linkListDiv}</div> 622 </div> 623 </section> 624 625 </div> 626 `; 627 return submenuHTML; 628} 629 630function renderLayout4(content, index) { 631 // Create the HTML for submenu layout 4 632 // SINGLE LINK layout, NO submenu 633 // Drop in the content 634 635 const submenuHTML3 = ''; 636 637 // TODO: Add anchor tag around the menu item 638} 639 640function buildMobileSubmenu(optionElement) { 641 if (window.innerWidth < 1440) { 642 document.querySelector('.slideout-search').style.display = 'none'; 643 const needHelp = document.getElementById('hideOnDesktop'); 644 // Need to hide the "Need Help?" section 645 needHelp.classList.add('fade-out'); 646 647 setTimeout(() => { 648 needHelp.style.display = 'none'; 649 needHelp.classList.remove('fade-out'); 650 }); 651 652 if (submenuJSON == null) { 653 $.getJSON('/docs/nasmlibraries/json/nasm-submenu.json', (submenudata) => { 654 submenuJSON = submenudata; 655 buildSubmenuTab(optionElement, submenuJSON); 656 }); 657 } else { 658 submenu = document.getElementById('main-menu'); 659 submenu.innerHTML = ''; 660 // Temp: clear innerHTML 661 // TODO: Replace with appropriate animation 662 buildSubmenuTab(optionElement, submenuJSON); 663 } 664 } 665} 666 667function buildDesktopSubmenu(optionElement, index, isClick) { 668 const hideOnDesktop = document.querySelector('#hideOnDesktop'); 669 hideOnDesktop.style = ''; 670 671 const slideoutSearch = document.querySelector('.slideout-search'); 672 slideoutSearch.style = ''; 673 674 const sideNav = document.querySelector('#mySidenav'); 675 sideNav.style = ''; 676 677 setTimeout(() => { 678 const blurOverlay = document.querySelector('#nav_bg_overlay'); 679 blurOverlay.style.height = '100vh'; 680 blurOverlay.style.width = '100%'; 681 document.querySelector('.search-dropdown-hide').style = ''; 682 }, 300); 683 684 const matchingTab = document.querySelectorAll(`.blueMouseover-${index}`)[1]; 685 if (matchingTab) { 686 matchingTab.addEventListener('mouseenter', (e) => { 687 // optionElement.style.borderBottom = "2px solid var(--brand-color-turquoise)"; 688 optionElement.style.borderBottom = '3px solid var(--brand-color-turquoise)'; 689 }); 690 691 matchingTab.addEventListener('mouseleave', (e) => { 692 setTimeout(() => { 693 // optionElement.style.borderBottom = "2px solid var(--ui-color-light)"; 694 optionElement.style.borderBottom = '3px solid var(--ui-color-light)'; 695 }, 200); 696 }); 697 } 698 699 // optionElement.style.borderBottom = "2px solid var(--brand-color-turquoise)"; 700 optionElement.style.borderBottom = '3px solid var(--brand-color-turquoise)'; 701 702 optionElement.addEventListener('mouseenter', (e) => { 703 // optionElement.style.borderBottom = "2px solid var(--brand-color-turquoise)"; 704 optionElement.style.borderBottom = '3px solid var(--brand-color-turquoise)'; 705 }); 706 707 optionElement.addEventListener('mouseleave', (e) => { 708 optionElement.style.borderBottom = '3px solid var(--ui-color-light)'; 709 }); 710 711 if (submenuJSON == null) { 712 $.getJSON('/docs/nasmlibraries/json/nasm-submenu.json', (submenudata) => { 713 submenuJSON = submenudata; 714 715 buildSubmenuTab(optionElement, submenuJSON); 716 }); 717 } else { 718 const thisIndex = optionElement.getAttribute('data-index'); 719 720 optionElement.style.borderBottom = '3px solid var(--brand-color-turquoise)'; 721 722 renderTabContent(submenuJSON.tabs[`${thisIndex}`], thisIndex) 723 .then(() => { 724 const navigationEvent = new CustomEvent(`item${thisIndex}`, { detail: `item${thisIndex}-tab` }); 725 726 const matchingTab = document.querySelectorAll(`.blueMouseover-${thisIndex}`)[1]; 727 728 matchingTab.addEventListener('mouseenter', (e) => { 729 // optionElement.style.borderBottom = "2px solid var(--brand-color-turquoise)"; 730 optionElement.style.borderBottom = '3px solid var(--brand-color-turquoise)'; 731 }); 732 733 matchingTab.addEventListener('mouseleave', (e) => { 734 setTimeout(() => { 735 // optionElement.style.borderBottom = "2px solid var(--ui-color-light)"; 736 optionElement.style.borderBottom = '3px solid var(--ui-color-light)'; 737 }, 200); 738 }); 739 740 document.dispatchEvent(navigationEvent); 741 toggleMobileOptions(); 742 }) 743 .catch((error) => { 744 console.error('Error occurred during rendering:', error); 745 }); 746 } 747} 748 749function toggleMobileOptions() { 750 // Code for Resources Dropdown, DRY up later 751 console.log('ran mobile options'); 752 753 const resourcesLinks = document.querySelectorAll('.link-section h2'); 754 755 if (resourcesLinks !== null) { 756 resourcesLinks.forEach((link) => { 757 link.addEventListener('click', (e) => { 758 const linkChild = link.nextElementSibling; 759 760 if (linkChild.style.display !== 'block') { 761 linkChild.style.display = 'block'; 762 } else { 763 linkChild.style.display = 'none'; 764 } 765 }); 766 }); 767 } 768 769 const resourceCarats = document.querySelectorAll('.link-section h2:after'); 770 console.log('resourceCarats', resourceCarats); 771 772 if (resourceCarats !== null) {
773 resourceCarats.forEach((link) => { 774 link.addEventListener('click', (e) => { 775 const linkChild = link.nextElementSibling; 776 777 if (linkChild.style.display !== 'block') { 778 linkChild.style.display = 'block'; 779 } else { 780 linkChild.style.display = 'none'; 781 } 782 }); 783 }); 784 } 785} 786 787function hideH2s(e) { 788 const content = e.target.nextElementSibling; 789 // Get the sibling p tag of just the target 790 if (e.target.classList.contains('toggled')) { 791 e.target.classList.remove('toggled'); 792 content.style.display = 'none'; 793 } else { 794 e.target.classList.add('toggled'); 795 content.style.display = 'block'; 796 } 797} 798 799function hideSubmenu() { 800 document.getElementById('nav_bg_overlay').style.width = '100%'; 801 802 submenuContent.classList.add('fade-out'); 803 // Add fadeout animaton class 804 805 setTimeout(() => { 806 document.getElementById('nav_bg_overlay').style.height = '0'; 807 for (const child of submenuContent.children) { 808 child.style.display = 'none'; 809 } 810 submenuContent.classList.remove('fade-out'); 811 }, 160); 812} 813 814function runSlickForNav(intervalID) { 815 clearInterval(intervalID); 816 817 $('.continuity-bar-nav').slick({ 818 speed: 500, 819 autoplay: true, 820 infinite: true, 821 draggable: true, 822 vertical: true, 823 verticalSwiping: true, 824 autoplaySpeed: 6000, 825 pauseOnHover: false, 826 pauseOnFocus: false, 827 touchMove: false, 828 }); 829} 830 831const _second = 1000; 832const _minute = _second * 60; 833const _hour = _minute * 60; 834const _day = _hour * 24; 835 836function showRemaining(data, auth, key) { 837 let end; 838 839 if (auth) { 840 end = new Date(`${data['auth-date']} 12:00 AM`); 841 } else { 842 end = new Date(`${data['unauth-date']} 12:00 AM`); 843 } 844 845 const now = new Date(); 846 let distance = end - now; 847 848 if (distance < 0) { 849 distance = 0; // Set distance to 0 if it's negative 850 851 // document.getElementById('countdown').innerHTML = 'EXPIRED!'; 852 853 // Used class rather than ID because having difficulty grabbing IDs of injected elements but not classes 854 $('.continuity-countdown').html(''); 855 856 return; 857 } 858 const days = Math.floor(distance / _day); 859 const hours = Math.floor((distance % _day) / _hour); 860 let totalhours; 861 if (days > 0) { 862 totalhours = Math.floor(days * 24 + hours); 863 } else { 864 totalhours = hours; 865 } 866 const minutes = Math.floor((distance % _hour) / _minute); 867 const seconds = Math.floor((distance % _minute) / _second); 868 869 $(`.${key} .continuity-countdown`).html(`<span class="continuity-countdown-numbers"><p>${totalhours}</p><p>hrs</p></span> <span class="continuity-countdown-numbers"><p>${minutes}</p><p>min</p></span> <span class="continuity-countdown-numbers"><p>${seconds}</p><p>sec</p></span>`); 870 setTimeout(showRemaining, 1000, data, auth, key); 871}
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.