{"version":3,"sources":["webpack:///./src/scripts/accordion-drawer/AccordionDrawer.js","webpack:///./src/scripts/accordion-toggle-list/AccordionToggleList.js","webpack:///./src/scripts/alert/Alert.js","webpack:///./src/scripts/button-toggle-group/ButtonToggleGroup.js","webpack:///./src/scripts/card-group/CardGroup.js","webpack:///./src/scripts/carousel/Carousel.js","webpack:///./src/scripts/collapse-list/CollapseList.js","webpack:///./src/scripts/services/search.js","webpack:///./src/scripts/content-search-results/ContentSearchResults.js","webpack:///./src/scripts/content-search/SearchValidation.js","webpack:///./src/scripts/content-search/ContentSearch.js","webpack:///./src/scripts/custom-select/CustomSelect.js","webpack:///./src/scripts/date-tag-filters/DateTagFilters.js","webpack:///./src/scripts/factsheet-fund-header/FactSheetFundHeader.js","webpack:///./src/scripts/factsheet-horizontal-text/FactsheetHorizontalText.js","webpack:///./src/scripts/factsheet-overview/FactsheetOverview.js","webpack:///./src/scripts/factsheet-pie-chart/FactsheetPieChart.js","webpack:///./src/scripts/factsheet-section/FactsheetSection.js","webpack:///./src/scripts/factsheet-vertical-table/FactsheetVerticalTable.js","webpack:///./src/scripts/faq/FAQ.js","webpack:///./src/scripts/form-banner/FormBanner.js","webpack:///./src/scripts/form-select/formSelect.js","webpack:///./src/scripts/funds-listing/formatting.js","webpack:///./src/scripts/funds-listing/rendering.js","webpack:///./src/scripts/funds-listing/FundsListing.js","webpack:///./src/scripts/header-login/LegacyHeaderLogin.js","webpack:///./src/scripts/header-login/LoginDropdown.js","webpack:///./src/scripts/header-mobile/HeaderMobile.js","webpack:///./src/scripts/header/Header.js","webpack:///./src/scripts/horizontal-tables/HorizontalTables.js","webpack:///./src/scripts/services/attribution.js","webpack:///./src/scripts/utils/cookie-utils.js","webpack:///./src/scripts/attribution/Attribution.js","webpack:///./src/scripts/index.js","webpack:///./src/scripts/back-button/BackButton.js","webpack:///./src/scripts/input/InputFields.js","webpack:///./src/scripts/interactive-map/InteractiveMap.js","webpack:///./src/scripts/milestones/Milestones.js","webpack:///./src/scripts/price-distribution/elements.js","webpack:///./src/scripts/price-distribution/Data.js","webpack:///./src/scripts/price-distribution/LineGraph.js","webpack:///./src/scripts/price-distribution/loadScripts.js","webpack:///./src/scripts/price-distribution/PriceDistribution.js","webpack:///./src/scripts/price-distribution/destroyScripts.js","webpack:///./src/scripts/radio-switch/RadioSwitch.js","webpack:///./src/scripts/retirement-preparedness/RetirementPreparedness.js","webpack:///./src/scripts/site-animations/SiteAnimations.js","webpack:///./src/scripts/smooth-scroll-anchor-link/smooth-scroll-anchor-link.js","webpack:///./src/scripts/tag-filters/TagFilters.js","webpack:///./src/scripts/toggle-button/ToggleButton.js","webpack:///./src/scripts/utils/scroll-utils.js","webpack:///./src/scripts/utils/search-utils.js","webpack:///./src/scripts/wizard/Wizard.js"],"names":["loadScripts","accordionDrawers","Array","from","document","getElementsByClassName","drawerCards","drawerClicked","e","drawer","target","closest","expandLongDrawers","childCards","querySelector","children","map","card","offsetHeight","reduce","s","h","classList","add","contains","remove","closeAllOtherDrawers","parentElement","forEach","dataset","initialized","addEventListener","stopPropagation","containers","container","buttons","slider","accordionPicker","drawerSections","moveSliderPosition","selectedButton","selectedButtonX","getBoundingClientRect","x","accordionPickerX","xTranslation","style","transform","pickerButtonClicked","button","removeAllButtonSelections","buttonIndex","indexOf","removeAllDrawerSelections","flatMap","section","childNodes","ResizeObserver","fixSliderPositionOnResize","querySelectorAll","observe","body","setSliderWidth","transition","width","length","storageMedium","localStorage","AlertStorage","storage","storageName","this","initialize","alertInfo","_getCount","resetDismissals","alert","id","data","getData","hasOwnProperty","dismissible","dismissed","_setData","raw","getItem","JSON","parse","setDismissed","alertId","dismissalDate","Date","now","alertIds","Object","keys","newData","setItem","stringify","getAlertId","elem","getAttribute","getAlertIsDismissable","dismissIcons","getAlertElement","showActiveAlerts","dismissals","activeAlerts","filter","isAlertVisible","status","isDateExpired","alertElement","activeAlertIds","date","expirationDays","element","icon","handleDismissClick","ButtonToggleGroup","el","getButtons","btn","handleButtonClick","bind","componentReady","CustomEvent","detail","component","selectedTab","getSelectedButton","selectedValue","getSelectedValue","dispatchEvent","selectedButtons","getButtonValue","innerText","toLowerCase","setSelectedButton","currentButton","buttonToggleGroupChanged","evt","preventDefault","currentTarget","buttonToggleGroupScripts","groups","gsComponent","showMoreHiddenClass","showLessHiddenClass","toggleCardHidden","toggle","hiddenClass","displayHiddenCards","hiddenCardList","hideAllCardsInGroup","cardGroup","allCardList","showMoreCardsInGroup","event","amountToShow","getCardGroupObject","group","cardsToShow","groupAllHiddenFilteredCards","slice","cardShowLessButtonWrapper","cardShowMoreButtonWrapper","scrollToCardCategory","parentNode","groupCategoryScrollOffsetElement","window","innerWidth","groupCategoryWrapperTag","scrollOffsetGroupHeight","top","pageYOffset","clientHeight","scrollTo","behavior","scrollIntoView","block","initSessionPagination","paginationSessionState","sessionStorage","MouseEvent","showAllCardsInGroup","cardButtonWrapper","groupButtonWrapper","groupShowAllButtonWrapper","groupShowMoreButtonWrapper","groupShowLessButtonWrapper","groupAllVisibleCards","groupAllHiddenCards","push","showLessCardsInGroup","cardsToHide","cardDisplayButton","removeItem","cardDisplayClass","cardGroupScripts","showMoreButtons","showAllButtons","showLessButtons","i","carouselScripts","xDown","yDown","swipeResult","getCurrentSlideIndex","currentItem","parseInt","indexval","getIndexRelativeToCurrentSlide","step","currentItemIndex","numSlides","getNumSlides","setActiveSlide","index","resetSlidePositions","slide","left","allIndicators","selectedIndicator","handleArrowClick","direction","goToPreviousSlide","nextIndex","goToNextSlide","getElementById","handleTouchStart","firstTouch","getTouches","touches","clientX","clientY","handleTouchMove","xUp","yUp","xDiff","yDiff","xDist","Math","abs","yDist","dragDirection","dragBoundary","positionAdjust","max","min","handleTouchEnd","item","handleIndicatorClick","CollapseListScripts","handleClick","activeId","active","generateEmptyResponse","header","statusMessage","SearchResults","NoResultsMessage","ResponseStatus","ResponseMessage","fireSearchAnalyticsEvent","query","tags","tag","isArray","join","console","log","dataLayer","searchContent","site","a","paramSection","paramSite","contentSearchEndpoint","queryString","URLSearchParams","set","tagsParam","location","hostname","includes","fetch","response","json","statusText","error","toggleSkeletonVisibility","searchSkeletonSection","fireNoResultsAnalyticsEvent","params","search","get","contentSearch","removeNoResultsMessage","generateResultsFromTemplates","generateNoResultsMessage","generateCardNode","isHidden","linkTarget","Type","Title","ShortDescription","CardImage","Category","Url","Evergreen","getCardTemplate","warn","subTitleNode","svgIcon","innerHTML","insertBefore","firstChild","href","src","firstElementChild","cardType","templateId","resultCardTemplate","importNode","content","manageResultCardVisbility","maxVisible","resultCards","resultCardsVisible","hide","getMaxVisibleResultCountFromViewport","generateSearchResultsNode","title","resultsNode","innerResultsNode","resultCardGroupTemplate","resultCount","appendChild","generateShowMoreButton","showMoreTemplate","clone","resultsData","contentResultsSection","getInitialSearchParams","type","sectionHeading","c","filteredResults","result","contentNode","message","resultsSection","outer","createElement","inner","noResultsContainer","searchContentAndUpdateResults","removeVisibleSearchResultNodes","removeChild","lastChild","setTimeout","manageMaxVisibleResultCount","searchResults","resultCardGroups","resultVisability","searchElementIds","mobileSearchElementIds","getSearchInput","isMobile","validateSearchQuery","updateSearchValidationVisibility","isValid","contentSearchValidation","getSearchValidation","searchBar","getSearchBar","simpleSearch","contentSiteSearch","setAttribute","contentSearchScripts","contentSearchForm","searchInput","searchListenerAdded","searchListener","manageSearchQueryParam","queryValue","setSearchQueryParam","contentSearchClicked","value","searchQueryValid","getAllSelectedTags","initializeDefaultTag","undefined","some","setTagParam","selectAllTag","siteSearchScripts","siteSearchForm","mobileSiteSearchForm","mobileSearchListenerAdded","siteSearchSubmitted","activeInput","searchQuery","origin","newLocation","initializeContentSearch","hasTags","showAllTags","tagName","selectTag","customSelectScripts","selectId","handleSelectClose","display","handleSelectItem","isSimpleLogin","currGroup","itemName","handleSwitchToLaunchMode","handleSwitchToSignInMode","handleSelectOpen","showMoreTagId","tagHiddenClass","tagSelectedClass","dateFilterID","toggleTagHidden","toggleTagSelected","displayHiddenTags","hiddenTagList","showMoreTag","allHiddenTags","persistShowMoreTagState","filterResults","tagAttributeIndicator","dateAttributeIndicator","tagAttribute","dateAttribute","visibleResults","isDateMatch","isTagMatch","hideNoResultsMessage","noResultsMessage","results","showNoResultsMessage","dateFilter","tagFilter","executeFilterByTag","setTagSelectedClass","currentlySelectedTags","persistSelectedTag","selectedTag","executeFilterByDate","dateSelector","persistSelectedDate","selectedDate","dateTagFilterScripts","tagSelector","restoreShowMoreTagState","restoreSelectedTag","targetTag","restoreSelectedDate","factSheetFundHeaderScript","viewAnotherFund","hamburgerMenu","mobileFundsNavigation","mobileFundsNavigationOverlay","closeButton","bottomLinks","link","l","headerBottom","expandButton","collapseButton","accordionLinks","destroyScripts","removeEventListener","factsheetHorizontalTextScripts","handleExpandClick","parent","handleCollapseClick","resetCollapsing","requestAnimationFrame","factsheetOverviewScripts","headers","isExpanded","currentHeader","accordionExpand","accordionCollapse","createChartBackground","radius","pattern","createElementNS","rect","path","circle","parsePercent","percent","cleaned","replace","parseFloat","NaN","createGroupedChart","svg","background","round","createWholePie","rotation","isNaN","createSlice","degToRadians","deg","PI","percentToDegrees","getSliceParemeters","offsetAngle","arcAngle","percentToRadians","endAngle","largeArc","startX","cos","startY","sin","endX","endY","d","factsheetPieChartScripts","parseChartData","dataStr","split","err","piechartData","chart","createChart","factsheetSectionScripts","factsheetVerticalTableScripts","resetFooters","footer","FAQScripts","formBannerScripts","form","formBanner","backgroundImage","backgroundGraphic","initialFormHeight","height","setBackgroundPosition","verticalPos","backgroundPosition","scrollImages","formHeightChange","offset","formSelectScripts","selectFields","onSelectChange","select","formatNumber","number","toFixed","formatAssetValue","formatTimestamp","matches","RegExp","exec","parsedDate","parseUtcTimestamp","milliseconds","utcOffset","getTimezoneOffset","formatDate","dd","String","getDate","padStart","getMonth","getFullYear","renderDailyPerformanceTable","headingRow","renderDailyTableHeadingRow","create","classes","html","bodyRows","Categories","category","newRows","renderDailyFundCategory","headerRow","renderDailyCategoryHeader","categoryName","categoryCode","nameCol","otherCol","attributes","cells","Description","CategoryCD","fundRows","Funds","fund","renderDailyFundRow","footnoteSymbols","performanceData","DailyPerformance","fundName","renderFundNameCell","hasYieldRow","values","SharePrice","MonthToDateReturn","YearToDateReturn","OneYearReturn","ThreeYearReturnAnnualized","FiveYearReturnAnnualized","TenYearReturnAnnualized","SinceInceptionReturnAnnualized","InceptionDate","GrossExpenseRatio","NetExpenseRatio","valueCells","v","cellClasses","row","renderYieldRow","SevenDayAverageYield","SevenDayGrossYield","TradeDate","getFundFootnoteSymbols","r","thead","tbody","renderMonthlyPerformanceTable","renderMonthlyTableHeadingRow","renderMonthlyFundCategory","renderMonthlyCategoryHeader","renderMonthlyFundRow","MonthlyPerformance","PreTaxOneMonth","PreTaxYearToDate","PreTaxOneYear","PreTaxThreeYearAnnualized","PreTaxFiveYearAnnualized","PreTaxTenYearAnnualized","PreTaxInceptionAnnualized","AsOfDate","renderQuarterlyPerformanceTable","renderQuarterlyTableHeadingRow","renderQuarterlyFundCategory","renderQuarterlyCategoryHeader","renderQuarterlyFundRow","QuarterlyPerformance","PreTaxThreeMonth","renderMorningstarPerformanceTable","renderMorningstarTableHeadingRow","renderMorningstarFundCategory","renderMorningstarCategoryHeader","renderMorningstarFundRow","MorningstarRating","MorningstarCategoryDescription","drawStars","MorningstarOverallRating","MorningstarOverallFunds","MorningstarThreeYearRating","MorningstarThreeYearFunds","MorningstarFiveYearRating","MorningstarFiveYearFunds","MorningstarTenYearRating","MorningstarTenYearFunds","numStars","numFunds","rating","formatMorningstar","siblingNumber","stars","starsContainer","createTextNode","integerSortFunction","b","ticker","TickerSymbol","FundNotesMap","Set","sort","hasAdditionalRow","FundInfoLink","cellAttributes","property","textContent","average","gross","asOfDate","columns","yieldCol","fundsListingScripts","mockData","shareClass","simulatedAnchorId","fundsListingContainer","fundsListingFootnotesContainer","buttonsContainer","asOfDates","daily","monthly","quarterly","morningstar","toggleComponent","currentTab","switchTable","addAnchorToShareClassLinks","jumpToFundCategoryAnchor","history","scrollRestoration","getShareClassFromQueryString","shareClassCode","shareClassToShareClassCD","loadData","renderTables","dateDaily","DateDaily","dateMonthly","DateMonthly","dateQuarterly","DateQuarterly","dateMorningStar","DateMorningStar","loaderContainer","destroyFundTables","tables","getElementsByTagName","renderFootnotes","innerHtML","Footnotes","footnote","text","className","FootnotesCssClass","t","desktop","mobile","Promise","resolve","reject","has","toLocaleLowerCase","endpoint","rawAnchor","getFragmentFromUrl","links","oldUrl","newUrl","anchorPosition","initialUrl","substring","jumpStickyContainerToCategory","categoryId","jumpToCategoryDesktop","categoryTop","totalOffsets","getScrollOffset","total","newWindowY","scrollY","jumpToCategoryMobile","jumpPageToStickyContainer","absolutePosition","headerHeight","currentScroll","scrollTop","newScrollY","actual","siteHeader","stickyHeader","tableHeader","actualAnchor","rawAnchorToActualAnchor","validateAnchorId","anchorId","getButtonToggleGroupComponent","then","catch","legacyHeaderLoginScripts","handleLoginClick","handleLoginButton","usernameVal","passwordVal","loginButtons","togglePasswordVisible","passwordContainer","passwordInput","inputType","handleLoginScroll","isHome","isHomePage","pathname","isDesktop","matchMedia","loginDropdownScripts","loginMenu","loginBtnDesktop","loginBtnMobile","handleMouseLeaveDesktop","mode","setDropdownPosition","position","menuBounds","right","handleClickOutside","page_url","headerMobileScripts","rootId","iconElement","rootElement","hideMobileNav","showMobileNav","addListenersToList","mobileNavLinks","mobileLink","activeListElements","hideElementList","listToHideId","removeListenersFromList","showElementList","listToShowId","listToShowElement","listId","listElement","child","nodeName","listItemNodes","headerScripts","closeAllMenus","subheaders","subheaderPattern","subheader","match","handleLinkExit","handleLinkClick","parentElems","headerLink","subHeader","loginLink","headerLinks","horizontalTableScript","emailPattern","hashEmail","email","payload","method","Status","HashedValue","Error","handleAttributionEmailChange","input","trim","test","hash","emailHash","handleAttributionFormSubmit","emailInput","handleGoogleAnalyticsCookieLoaded","cookieValue","cookieNotifiers","getCookie","cookieName","cookies","getCookies","cookie","k","key","decodeURI","CookieNotifier","name","loaded","callbacks","checkCookieExists","callback","cookieExists","attributionScripts","f","notifyWhenCookieSet","siteAnimations","toggleButtonScripts","tagFilterScripts","toggleRadioScripts","wizardScripts","interactiveMapScripts","priceDistributionScripts","alertScripts","smoothScrollAnchorLinkScripts","retirementPreparednessScripts","milestonesScripts","accordionDrawerScripts","accordionToggleListScripts","backButtonScripts","stopImmediatePropagation","back","inputFieldScripts","restrictInput","placeholder","mask","masked","maskCharacters","dobElements","phoneElements","ssnElements","ssnIconButtons","selectElements","dob","phone","ssn","selectHandler","ssnButtonHandler","previousElementSibling","infoModalCloseButtons","stateElements","prototype","call","handleCloseClick","updateMap","handleStateClick","stateCode","abbreviation","activeState","state","isActive","updateStateStatus","stateElement","stateEl","initialMilestone","getInitialMilestone","stones","milestoneId","find","st","milestone","setActiveStone","stone","handleStoneClick","milestoneNavigationTop","scrollToElement","alignIndicatorToStone","centerIndicatorOnPositon","setIndicatorPosition","shouldScrollToContent","showActiveContent","getActiveStone","getStoneCenter","stoneParent","stoneRect","elements","chartContainer","factsheetSectionHeading","historicalPricesContainer","historicalPricesContainerInner","historicalPricesContainerTable","historicalFromDate","historicalToDate","historicalPricesTable","updateHistoryButton","showHistoryTable","downloadExcelButton","downloadCsvButton","historyTableSelect","dataTypeDaily","histNav","histDiv","histCap","distributionCheckbox","timePeriodList","Data","parseDate","str","regex","moment","utc","process","that","distributions","Values","Distributions","rate","Rate","PayDate","DistributionType","dateRecord","RecordDate","NAVValue","distributionAssetValue","isSame","_d3Mouse","d3","mouse","_d3Zoom","zoom","formatCurrency","amount","Intl","NumberFormat","currency","minimumFractionDigits","format","renderHistoricalPricesTable","tableRows","template","class","itemMarkup","description","LineGraph","args","_container","_node","_distributionCheckbox","_data","_assetValues","_distributions","_height","_width","offsetWidth","_svg","append","_labelContainer","attr","_marginContainer","_margin","bottom","checked","_showDistributions","_removeDistributions","update","reRender","render","_formatCurrency","_tooltip","_currentValueTooltip","startDate","endDate","allValues","_x","time","scale","range","_y","linear","domain","area","y0","y1","line","y","xAxis","axis","tickSize","tickFormat","orient","ticks","yAxis","scaleExtent","on","zoomed","translate","tx","ty","selectAll","datum","mouseG","xDate","invert","bisect","bisector","duration","_renderTable","desc","distclass","circleContainer","label","_renderDistribution","API_BASE","getDatesByMonthAgo","numberOfMonths","start","subtract","end","snippetData","maxData","endPointUrl","getDevData","isDev","Boolean","checkRenderTable","loadChartIfContainerVisible","containerInner","isChartLoaded","isElementVisible","getComputedStyle","fromPicker","Pikaday","field","toPicker","getSelectorUrls","selectorDates","selectorUrls","selector","url","renderLineGraph","graph","activateControls","activateHistoryTable","renderData","click","activateDateButton","resetButtonContainer","li","updateData","obj","toString","open","handleRadioChange","resizeIframe","newHeight","handleIframeMessage","validateEventOrigin","iframe","iframeSrc","eventOrigin","ht","iframeUrl","viewportHeight","isBelowViewport","checkPosition","init","innerHeight","startsWith","scrollToAnchorInUrl","showLessTagId","tagContainerId","tagClass","getServerSideTagsGroup","serverSideTagsGroup","allTag","findTag","showLessTag","applyButton","getSelectedTags","includeAllTag","selectedTags","getAllTags","allTags","getTagsToHide","numTagsToKeep","startingTagNumber","unselectedTags","lenght","tagsToKeep","handleTagSelection","updateLessButtonVisibility","deselectTag","tagContainer","showLessButton","showMoreButton","tagsToShow","hideExtraTags","tagsToHide","hideTags","enableTagGroup","tagGroup","disabled","disableTagGroup","handleTagClick","executeServerSideFilterBySelectedTags","executeClientSideFilterBySelectedTags","resultsGroups","groupTagDataAttribute","resultSection","clientSideTagsGroup","getClientSideTagsGroup","enableServerSideTags","MutationObserver","mutationCallback","mutationsList","mutation","addedNodes","removedNodes","childList","subtree","defaultScrollOptions","freeze","manualOffset","correctForStickyHeader","getCurrentManualOffset","getTotalOffset","elementOffset","totalOffset","getHeaderHeight","options","fullOptions","assign","getOffset","finalOptions","scrollBy","scrollToId","delete","replaceState","tagValue","sectionFromQueryString","tagsFromQueryString","mapUrlPathToSection","mapping","pathItems","expectedPath","handleCardClick","action"],"mappings":"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","file":"scripts.01856df4.iframe.bundle.js","sourcesContent":["////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 10/23/23 GCASEY 117077 Initial Create\r\n// 11/07/2023 BBARRON 118560 Bugfix - loadScripts was getting called multiple times in storybook\r\n// This was adding multple event listeners to drawers\r\n// 01/18/2024 GCASEY 122462 Fix bug with cards not showing in long drawers\r\n// 01/23/2024 GCASEY 122462 Change childNodes to children\r\n// 01/23/2024 GCASEY 122462 Refactor Drawer expansion\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n\r\n\r\nconst loadScripts = () => {\r\n const accordionDrawers = Array.from(document.getElementsByClassName(\"gs-accordion-drawer\"));\r\n const drawerCards = Array.from(document.getElementsByClassName(\"gs-accordion-card\"));\r\n const initialDrawerHeight = 2000;\r\n\r\n const selectionClass = \"--selected\";\r\n\r\n // Removes selection class from all drawers on the page\r\n const closeAllOtherDrawers = (drawer) => {\r\n // limit the scope of this to other draers within the same accordion menu\r\n const siblingDrawers = Array.from(drawer.parentElement.getElementsByClassName(\"gs-accordion-drawer\"));\r\n siblingDrawers.forEach((drawer) => {\r\n if(drawer.classList.contains(selectionClass)) {\r\n drawer.classList.remove(selectionClass);\r\n }\r\n })\r\n }\r\n\r\n // Change the max-height of drawers when the content goes over the initial max-height\r\n const expandLongDrawers = (drawer) => {\r\n const childCards = drawer.querySelector(\".gs-accordion-drawer-cards\");\r\n const totalHeight = Array.from(childCards.children).map(card => card.offsetHeight).reduce((s,h) => s + h, 0);\r\n\r\n if(totalHeight >= initialDrawerHeight) {\r\n drawer.classList.add(\"--expanded\");\r\n }\r\n }\r\n\r\n // Adds/Removes selection class to clicked drawer\r\n const drawerClicked = (e) => {\r\n const drawer = e.target.closest(\".gs-accordion-drawer\"); \r\n expandLongDrawers(drawer);\r\n\r\n if(drawer.classList.contains(selectionClass)) {\r\n drawer.classList.remove(selectionClass);\r\n } else {\r\n closeAllOtherDrawers(drawer);\r\n drawer.classList.add(selectionClass);\r\n }\r\n }\r\n\r\n accordionDrawers.forEach((drawer) => {\r\n // Prevent drawers from being initialized twice\r\n // Needed because storybook calls loadScripts for every instance of the component on the page\r\n if(drawer.dataset.initialized !== \"true\") {\r\n drawer.addEventListener(\"click\", drawerClicked);\r\n drawer.dataset.initialized = \"true\";\r\n }\r\n\r\n \r\n\r\n }, false);\r\n drawerCards.forEach((card) => card.addEventListener(\"click\", (e) => e.stopPropagation()));\r\n}\r\n\r\n\r\n\r\nexport default { loadScripts };","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 10/23/23 GCASEY 117077 Initial Create\r\n// 10/31/2023 GCASEY 117782 Fix console errors\r\n// 11/13/2023 BBARRON 118664 Limit scope of script to elements within a given container.\r\n// 02/12/2024 GCASEY 122529 Fix bug where slider went outside of container\r\n// 02/13/2024 GCASEY 122529 Fix slider not animating bug\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nconst loadScripts = () => {\r\n const containers = Array.from(document.getElementsByClassName('gs-accordiontogglelist'));\r\n \r\n const selectedClass = \"--selected\";\r\n const sliderTransition = \"all .5s ease-in-out\";\r\n // offset to hide divider border lines\r\n const sliderWidthOffset = 6;\r\n\r\n\r\n // Toggling between accordion menus should not impact anything outside of the given container\r\n containers.forEach(container => {\r\n const buttons = Array.from(container.getElementsByClassName(\"gs-accordiontogglelist-picker-button\"));\r\n const slider = container.getElementsByClassName(\"gs-accordiontogglelist-picker-slider\")[0];\r\n const accordionPicker = container.getElementsByClassName(\"gs-accordiontogglelist-picker\")[0];\r\n const drawerSections = Array.from(container.getElementsByClassName(\"gs-accordiontogglelist-drawer-section\"));\r\n\r\n if(!accordionPicker) {\r\n return;\r\n }\r\n\r\n // Removes the selected class from all picker buttons\r\n const removeAllButtonSelections = () => {\r\n buttons.forEach((button) => {\r\n button.classList.remove(selectedClass);\r\n });\r\n }\r\n\r\n // Removes the selected class from all drawer groups\r\n const removeAllDrawerSelections = () => {\r\n drawerSections.flatMap(section => Array.from(section.childNodes))\r\n .forEach((drawer) => drawer.classList.remove(selectedClass));\r\n }\r\n\r\n // Moves the position of the slider for the button click transition\r\n const moveSliderPosition = (selectedButton) => {\r\n const selectedButtonX = selectedButton.getBoundingClientRect().x;\r\n const accordionPickerX = accordionPicker.getBoundingClientRect().x;\r\n const xTranslation = selectedButtonX - accordionPickerX;\r\n\r\n if(accordionPickerX !== 0 && selectedButtonX !== 0) {\r\n slider.style.transform = `translateX(${xTranslation}px)`;\r\n }\r\n }\r\n\r\n // Adjusts slider position and sets drawer group visibility\r\n const pickerButtonClicked = (e) => {\r\n const button = e.target.closest(\".gs-accordiontogglelist-picker-button\");\r\n removeAllButtonSelections();\r\n moveSliderPosition(button);\r\n\r\n button.classList.add(selectedClass);\r\n\r\n const buttonIndex = buttons.indexOf(button);\r\n drawerSections.forEach((drawer) => drawer.classList.remove(\"--active\"));\r\n drawerSections[buttonIndex].classList.add(\"--active\");\r\n removeAllDrawerSelections();\r\n }\r\n\r\n // Recalculates slider translation value for when resized\r\n const fixSliderPositionOnResize = () => {\r\n const selectedButton = document.querySelectorAll(\"div.gs-accordiontogglelist-picker-button.--selected\")[0];\r\n moveSliderPosition(selectedButton);\r\n }\r\n\r\n // Sets width of the slider no matter how many picker buttons there are \r\n const setSliderWidth = () => {\r\n slider.style.transition = \"none !important\";\r\n slider.style.width = `calc(${1 / buttons.length * 100 }% + ${sliderWidthOffset}px)`;\r\n slider.style.transition = sliderTransition;\r\n }\r\n\r\n buttons.forEach((button) => button.addEventListener(\"click\", pickerButtonClicked));\r\n new ResizeObserver(fixSliderPositionOnResize).observe(document.body);\r\n setSliderWidth();\r\n });\r\n}\r\n\r\nexport default { loadScripts };","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 06/12/2023 GCASEY 107566 Initial Create\r\n// 12/01/2023 GCASEY 119405 Fixed bug causing alerts to not show\r\n// 07/29/2024 BBARRON 135304 If a dismissed alert is republished as not dismissible, make sure it shows up\r\n// 02/26/2025 BBARRON 149679 Add better null checking and handle alerts that appear after page load\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nconst alertClass = \"gs-alert\";\r\nconst alertIdData = \"data-alert-id\";\r\nconst iconClass = \"gs-alert--icon\";\r\nconst activeClass = \"--active\";\r\n\r\n// Storage\r\nconst storageName = \"alertInfo\"; // item name in storage \r\nconst storageMedium = localStorage; // local or session storage\r\n\r\n// Alert Dismissal Expiration\r\nconst dismissalExpirationEnabled = true;\r\nconst millisecondsPerDay = 86400000;\r\nconst expirationDays = 60;\r\nconst expirationTime = expirationDays * millisecondsPerDay; \r\n\r\n\r\n\r\n\r\nclass AlertStorage {\r\n\r\n constructor(storage, storageName) {\r\n this.storage = storage;\r\n this.storageName = storageName;\r\n }\r\n\r\n /**\r\n * Sets initial dismissal data if none exists\r\n * @param {string[]} alertIds \r\n */\r\n initialize(alertInfo) {\r\n if(this._getCount() === 0)\r\n this.resetDismissals(alertInfo.map(alert => alert.id));\r\n\r\n if(this._getCount() !== alertInfo.length) {\r\n const data = this.getData();\r\n alertInfo.forEach((alert) => {\r\n // If the alert is new, add it to storage with undismissed state\r\n // If the alert is not dismissible, set state to undismissed\r\n if(!data.hasOwnProperty(alert.id) || !alert.dismissible) {\r\n data[alert.id] = {\r\n id: alert.id, \r\n dismissed: false\r\n }\r\n }\r\n })\r\n this._setData(data);\r\n }\r\n }\r\n \r\n /**\r\n * Gets the dismissal data from storage \r\n * The data is an object where the keys are the alerts ids and the values are an object with the dismissal status\r\n * @returns {Object}\r\n */\r\n getData() {\r\n const raw = this.storage.getItem(this.storageName);\r\n if(raw == null)\r\n return {};\r\n\r\n return JSON.parse(raw);\r\n }\r\n\r\n /**\r\n * Sets an alert as dismissed\r\n * @param {string} alertId \r\n */\r\n setDismissed(alertId) {\r\n const data = this.getData();\r\n data[alertId] = {\r\n id: alertId,\r\n dismissed: true,\r\n dismissalDate: Date.now()\r\n }\r\n this._setData(data);\r\n }\r\n\r\n /**\r\n * Resets the dismissal status for a list of alerts \r\n * @param {string[]} alertIds \r\n */\r\n resetDismissals(alertIds) {\r\n const data = this.getData();\r\n alertIds.forEach(id => {\r\n data[id] = {\r\n id,\r\n dismissed: false\r\n }\r\n });\r\n this._setData(data);\r\n }\r\n\r\n _getCount() {\r\n const data = this.getData();\r\n return Object.keys(data).length;\r\n }\r\n\r\n _setData(newData) {\r\n this.storage.setItem(this.storageName, JSON.stringify(newData));\r\n }\r\n}\r\n\r\n/**\r\n * Gets the alert id from a child element\r\n * @param {HTMLElement} elem The alert element \r\n * @returns {string}\r\n */\r\nconst getAlertId = (elem) => {\r\n const alert = elem.closest(\".gs-alert\");\r\n return alert?.getAttribute(alertIdData);\r\n}\r\n\r\n/**\r\n * Determines whether the given alert element is dismissible based on the presence of the dismiss button\r\n * @param {HtmlElement} elem The alert element \r\n * @returns {boolean} True if the alert is dismissible\r\n */\r\nconst getAlertIsDismissable = (elem) => {\r\n const dismissIcons = Array.from(elem.getElementsByClassName(iconClass));\r\n let isDismissible = !(!dismissIcons || dismissIcons.length === 0);\r\n return isDismissible;\r\n}\r\n\r\n/**\r\n * Gets an alert element from its sitecore id\r\n * @param {string} id \r\n * @returns {HtmlElement}\r\n */\r\nconst getAlertElement = (id) => {\r\n return document.querySelector(`[${alertIdData}=\"${id}\"]`);\r\n}\r\n\r\n/**\r\n* Handles the dismiss button being clicked\r\n* @param {MouseEvent} e \r\n* @param {AlertStorage} storage\r\n*/ \r\nconst handleDismissClick = (e, storage) => {\r\n const alertId = getAlertId(e.target);\r\n const alert = getAlertElement(alertId);\r\n storage.setDismissed(alertId);\r\n alert.classList.remove(activeClass);\r\n} \r\n\r\nconst isAlertVisible = (alert, status) => {\r\n if (!alert) {\r\n return false;\r\n }\r\n\r\n if (!alert.dismissible || !status || !status.dismissed) {\r\n return true;\r\n }\r\n\r\n return dismissalExpirationEnabled && isDateExpired(status.dismissalDate);\r\n}\r\n\r\n/**\r\n * Enables all active alerts to be visible on the page.\r\n * By default all alerts start hidden and active class is added if they are not dismissed.\r\n * @param {HtmlElement[]} alertInfo The alert info {element, id, dismissible}\r\n * @param {AlertStorage} storage The dismissal storage interface\r\n */\r\nconst showActiveAlerts = (alertInfo, storage) => {\r\n const dismissals = storage.getData();\r\n const activeAlerts = alertInfo.filter(alert => isAlertVisible(alert, dismissals[alert.id]));\r\n\r\n // Update element class\r\n activeAlerts.forEach(alert => {\r\n const alertElement = getAlertElement(alert.id);\r\n if (alertElement) {\r\n alertElement.classList.add(activeClass);\r\n }\r\n });\r\n\r\n // Reset all dismissals for alerts where the alert is not dismissed or the dismissal has expired\r\n const activeAlertIds = activeAlerts.map(alert => alert.id);\r\n storage.resetDismissals(activeAlertIds);\r\n}\r\n\r\n/**\r\n * Checks if a date is expired\r\n * @param {number} date \r\n * @returns \r\n */\r\nconst isDateExpired = (date) => {\r\n return Date.now() > date + expirationTime;\r\n}\r\n\r\nconst loadScripts = () => {\r\n const storage = new AlertStorage(storageMedium, storageName);\r\n const dismissIcons = Array.from(document.getElementsByClassName(iconClass));\r\n const alerts = Array.from(document.getElementsByClassName(alertClass));\r\n\r\n const alertInfo = alerts.map(alert => {\r\n return {\r\n element: alert,\r\n id: getAlertId(alert),\r\n dismissible: getAlertIsDismissable(alert)\r\n };\r\n });\r\n\r\n storage.initialize(alertInfo);\r\n showActiveAlerts(alertInfo, storage);\r\n \r\n dismissIcons.forEach((icon) => icon.addEventListener(\"click\", e => handleDismissClick(e, storage), false));\r\n}\r\n\r\nexport default { loadScripts };","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 10/10/2022 BBARRON 93604 Initial create\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nconst selectedButtonClass = 'selected';\r\nconst toggleEventType = 'gs.tabchange';\r\nconst readyEventType = 'gs.load';\r\n\r\n/**\r\n * Usage: When a ButtonToggleGroup component is on the page, you can get the element from the DOM using your preferred method. document.getElementById, etc.\r\n * \r\n * Once you have the container element, check to see if the gsComponent property is set. That will be an instance of the ButtonToggleGroup class.\r\n * If it's set then the component is loaded and ready to use.\r\n * Events:\r\n * gs.load - fires when the component is initialized and ready to use\r\n * event details:\r\n * - id: the id of the container element\r\n * - component: an instance of the ButtonToggleGroup component, \r\n * - container: the container element,\r\n * - selectedTab: the currently selected tab\r\n * - selectedValue: the lowercase text of the currently selected tab\r\n * You can access these details in the event handler by using \"evt.detail.selectedValue\" for example\r\n * gs.toggle - fires when the selected tab is changed. Either by the user or by code\r\n * event details:\r\n * - id: the id of the container element\r\n * - component: an instance of the ButtonToggleGroup component, \r\n * - container: the container element,\r\n * - selectedTab: the currently selected tab\r\n * - selectedValue: the lowercase text of the currently selected tab\r\n * You can access these details in the event handler by using \"evt.detail.selectedValue\" for example\r\n * \r\n * Once the component is loaded, the gsComponent property of the container element is set to the instance of the component class.\r\n * If the gsComponent property is undefined, you can listen for the gs.load event on the container element\r\n * \r\n * Someone wishing to use this component could listen for the gs.toggle event on the container elmeent.\r\n * When fired they will get the currently selected tab element with \"event.selectedTab\".\r\n * From that element they can look at the text, the css classes, id, or any custom data attribute to decide how to respond to the event.\r\n */\r\n\r\nclass ButtonToggleGroup {\r\n /**\r\n * \r\n * @param {HtmlElement} el \r\n * @returns \r\n */\r\n constructor(el) {\r\n if(!el) {\r\n return;\r\n }\r\n\r\n this.container = el;\r\n\r\n if(!this.container.classList.contains('gs-button-toggle-group')) {\r\n this.container.classList.add('gs-button-toggle-group');\r\n }\r\n \r\n \r\n // Wire up the events\r\n let buttons = this.getButtons();\r\n if(!buttons) {\r\n return;\r\n }\r\n buttons.forEach(btn => {\r\n btn.addEventListener('click', this.handleButtonClick.bind(this), false);\r\n });\r\n let componentReady = new CustomEvent(readyEventType, { \r\n detail: {\r\n id: this.container.id, \r\n component: this, \r\n container: this.container,\r\n selectedTab: this.getSelectedButton(),\r\n selectedValue: this.getSelectedValue()\r\n }\r\n });\r\n this.container.dispatchEvent(componentReady);\r\n }\r\n\r\n getButtons() {\r\n let children = Array.from(this.container.children)\r\n return children.filter(btn => btn.classList.contains('gs-button-toggle'));\r\n }\r\n\r\n getSelectedButton() {\r\n let selectedButtons = Array.from(this.container.children).filter(btn => btn.classList.contains('gs-button-toggle') && btn.classList.contains(selectedButtonClass));\r\n if(!selectedButtons || selectedButtons.length === 0) {\r\n return null;\r\n }\r\n return selectedButtons[0];\r\n }\r\n\r\n getButtonValue(button) {\r\n if(!button) return null;\r\n return button.innerText.toLowerCase();\r\n }\r\n\r\n getSelectedValue() {\r\n return this.getButtonValue(this.getSelectedButton());\r\n }\r\n\r\n setSelectedButton(btn) {\r\n if(btn.classList.contains(selectedButtonClass)) {\r\n return;\r\n }\r\n let buttons = this.getButtons();\r\n buttons.forEach(currentButton => {\r\n if(btn == currentButton) {\r\n currentButton.classList.add(selectedButtonClass);\r\n } else {\r\n currentButton.classList.remove(selectedButtonClass);\r\n }\r\n });\r\n let buttonToggleGroupChanged = new CustomEvent(toggleEventType, {\r\n detail: {\r\n id: this.container.id, \r\n component: this, \r\n container: this.container,\r\n selectedTab: btn,\r\n selectedValue: this.getButtonValue(btn)\r\n }\r\n });\r\n this.container.dispatchEvent(buttonToggleGroupChanged);\r\n }\r\n\r\n handleButtonClick(evt) {\r\n evt.preventDefault();\r\n \r\n let button = evt.currentTarget;\r\n if(button.classList.contains(selectedButtonClass)) {\r\n return;\r\n }\r\n \r\n this.setSelectedButton(button);\r\n }\r\n}\r\n\r\nexport const buttonToggleGroupScripts = {\r\n loadScripts: () => {\r\n let groups = document.querySelectorAll('.gs-button-toggle-group');\r\n if(!groups || groups.length === 0) {\r\n return;\r\n }\r\n\r\n let containers = Array.from(groups);\r\n containers.forEach(container => {\r\n // don't wire up the events if the container is in links mode rather than tabs mode\r\n if(container.classList.contains('gs-button-toggle-group--links')) {\r\n return;\r\n }\r\n let component = new ButtonToggleGroup(container);\r\n container.gsComponent = component;\r\n });\r\n }\r\n};","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/18/2020 HJordan Initial create\r\n// 01/28/2020 HJordan 51238 Support Show More & Show All interactions\r\n// 04/28/2023 LBALL 103249 Update Markup in storybook for Show Less feature\r\n// 05/09/2023 LBALL 105697 Add scrolling on pagination close\r\n// 05/10/2023 LBALL 105732 Modify scrolling on Pagination close\r\n// 05/11/2023 LBALL 103247 Updating .js to Save Expand and Collapse State using sessionsStorage\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nconst showMoreButtonClass = 'gs-cardgroup-showMore-btn';\r\nconst showAllButtonClass = 'gs-cardgroup-showAll-btn';\r\nconst showLessButtonClass = 'gs-cardgroup-showLess-btn';\r\nconst showMoreHiddenClass = 'gs-cardgroup-showMore--hidden';\r\nconst showAllHiddenClass = 'gs-cardgroup-showAll--hidden';\r\nconst showLessHiddenClass = 'gs-cardgroup-showLess--hidden';\r\nconst cardHiddenClass = 'gs-card--hidden';\r\n\r\n/**\r\n * Function which accepts an element,a toggle flag, and a class which\r\n * hides a card, ir order to hide/show the element based on the toggle\r\n * flag\r\n *\r\n * @param {Node} element element to be manipulated\r\n * @param {boolean} toggle flag to identify hidden or visible\r\n * @param {string} hiddenClass class which hides cards\r\n */\r\nconst toggleCardHidden = (element, toggle, hiddenClass) => {\r\n\r\n if (!element) {\r\n return;\r\n }\r\n\r\n if (toggle) {\r\n element.classList.add(hiddenClass);\r\n } else {\r\n element.classList.remove(hiddenClass);\r\n }\r\n};\r\n\r\n/**\r\n * Function which accepts a list of tags which are currently hidden, and\r\n * toggles them to be revealed\r\n *\r\n * @param {Array} hiddenCardList list of hidden Tag nodes\r\n */\r\nconst displayHiddenCards = hiddenCardList => {\r\n if (hiddenCardList && hiddenCardList.length > 0) {\r\n hiddenCardList.forEach(card => {\r\n toggleCardHidden(card, false, cardHiddenClass);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Function which accepts a list of tags which are currently hidden\r\n * or calculates them by default, and toggles them to be revealed\r\n *\r\n * @param {Array} hiddenCardList list of hidden Tag nodes\r\n */\r\n\r\nexport const hideAllCardsInGroup = (cardGroup) => {\r\n const allCardList = cardGroup ?? document.querySelectorAll('.gs-card');\r\n if (allCardList && allCardList.length > 0) {\r\n allCardList.forEach(card => {\r\n toggleCardHidden(card, true, cardHiddenClass);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Click handler which handles triggers when the \"Show More\" button in a card\r\n * group is clicked. The handler then takes all of the cards in the card group\r\n * and ensure the correct classes are applied so that all cards are revealed\r\n * based on the designated number of cards to be displayed\r\n *\r\n * The \"Show More\" button is then hidden from the view once amountToShow exceeds\r\n * number of remaining hidden items\r\n *\r\n * @param {EventTarget} event\r\n * @param {number} amountToShow number of elements to show\r\n * @param {string} classToShow number of elements to show\r\n */\r\nexport const showMoreCardsInGroup = (event, amountToShow = 6) => {\r\n\r\n let cardGroup = getCardGroupObject(event);\r\n\r\n if (cardGroup.group) {\r\n\r\n const cardsToShow = Array.from(cardGroup.groupAllHiddenFilteredCards ?? null).slice(0, amountToShow);\r\n const cardShowLessButtonWrapper = cardGroup.group.querySelector('.gs-cardgroup-showLess');\r\n const cardShowMoreButtonWrapper = cardGroup.group.querySelector('.gs-cardgroup-showMore');\r\n\r\n displayHiddenCards(cardsToShow);\r\n\r\n if (cardGroup.groupAllHiddenFilteredCards.length <= amountToShow) {\r\n toggleCardHidden(cardShowMoreButtonWrapper, true, showMoreHiddenClass)\r\n toggleCardHidden(cardShowLessButtonWrapper, false, showLessHiddenClass);\r\n } else {\r\n toggleCardHidden(cardShowMoreButtonWrapper, false, showMoreHiddenClass);\r\n toggleCardHidden(cardShowLessButtonWrapper, true, showLessHiddenClass);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Scrolling function that returns the user to the \"Header\" section of a card group; \r\n * the scrolling is calculated relative to the mobile or desktop navigation menu.\r\n * \r\n * @param {Object} cardGroup\r\n */\r\n\r\nexport const scrollToCardCategory = (cardGroup) => {\r\n\r\n if (cardGroup.group.parentNode) {\r\n\r\n const groupCategoryScrollOffsetElement = window.innerWidth < 1024 ?\r\n document.querySelector('.gs-header-mobile-nav-container') :\r\n document.querySelector('.gs-header-desktop-nav-container');\r\n\r\n const groupCategoryWrapperTag = cardGroup.group.parentNode.getAttribute(\"data-tag\");\r\n\r\n if (groupCategoryWrapperTag && groupCategoryWrapperTag !== \"undefined\") {\r\n\r\n let scrollOffsetGroupHeight = cardGroup.group.parentNode.getBoundingClientRect().top + window.pageYOffset ?? 0;\r\n\r\n if (groupCategoryScrollOffsetElement && groupCategoryScrollOffsetElement.clientHeight) {\r\n scrollOffsetGroupHeight = scrollOffsetGroupHeight - groupCategoryScrollOffsetElement.clientHeight;\r\n }\r\n\r\n window.scrollTo(\r\n {\r\n behavior: \"smooth\",\r\n top: scrollOffsetGroupHeight\r\n }\r\n );\r\n\r\n } else {\r\n cardGroup.group.parentNode.scrollIntoView(\r\n {\r\n behavior: \"smooth\",\r\n block: \"end\"\r\n }\r\n );\r\n }\r\n }\r\n return;\r\n}\r\n\r\n\r\n/**\r\n * Anonymous function that reads the sessionStorage of a cardgroup from the button element.\r\n * This function should dynamically open a cardgroup's pagination.\r\n * \r\n * This is only invoked during CardGroupScripts().\r\n * \r\n * @param {button} buttonElement\r\n */\r\n\r\n\r\nexport const initSessionPagination = (button) => {\r\n\r\n const groupCategoryWrapperTag = button.parentNode.parentNode.parentNode.getAttribute(\"data-tag\");\r\n if(groupCategoryWrapperTag) {\r\n\r\n let paginationSessionState = sessionStorage.getItem(groupCategoryWrapperTag);\r\n\r\n if(paginationSessionState && paginationSessionState.toLowerCase() == \"open\") {\r\n button.dispatchEvent(new MouseEvent(\"click\"));\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Click handler which handles triggers when the \"Show All\" button in a card\r\n * group is clicked. The handler then takes all of the cards in the card group\r\n * and ensure the correct classes are applied so that all cards are revealed\r\n *\r\n * The \"Show All\" button is then hidden from the view\r\n * @param {EventTarget} event\r\n */\r\nexport const showAllCardsInGroup = (event) => {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n const cardGroup = getCardGroupObject(event);\r\n const cardButtonWrapper = cardGroup.groupButtonWrapper ?? cardGroup.groupShowAllButtonWrapper;\r\n const groupCategoryWrapperTag = cardGroup.group.parentNode.getAttribute(\"data-tag\");\r\n\r\n if (groupCategoryWrapperTag) {\r\n sessionStorage.setItem(groupCategoryWrapperTag, \"open\");\r\n }\r\n\r\n if (cardGroup.group) {\r\n displayHiddenCards(cardGroup.groupAllHiddenFilteredCards);\r\n toggleCardHidden(cardButtonWrapper, true, showAllHiddenClass);\r\n toggleCardHidden(cardGroup.group.querySelector('.gs-cardgroup-showLess'), false, showLessHiddenClass);\r\n }\r\n};\r\n\r\n/**\r\n * Anonymous function to return CardGroup UI elements\r\n *\r\n * @param {EventTarget} event\r\n */\r\nexport const getCardGroupObject = (event) => {\r\n\r\n let cardGroup = {\r\n groupButtonWrapper: null,\r\n groupShowAllButtonWrapper: null,\r\n groupShowMoreButtonWrapper: null,\r\n groupShowLessButtonWrapper: null,\r\n groupAllVisibleCards: null,\r\n groupAllHiddenCards: null,\r\n groupAllHiddenFilteredCards: [],\r\n group: null\r\n }\r\n\r\n\r\n if (event) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n cardGroup.groupButtonWrapper = event.target.parentNode;\r\n cardGroup.group = cardGroup.groupButtonWrapper.parentNode;\r\n } else {\r\n cardGroup.groupShowAllButtonWrapper = document.querySelector('.gs-cardgroup-showAll');\r\n cardGroup.groupShowMoreButtonWrapper = document.querySelector('.gs-cardgroup-showMore');\r\n cardGroup.groupShowLessButtonWrapper = document.querySelector('.gs-cardgroup-showLess');\r\n cardGroup.group = document.querySelector('.gs-cardgroup-content');\r\n }\r\n\r\n if (cardGroup.group) {\r\n cardGroup.groupAllVisibleCards = cardGroup.group.querySelectorAll('.gs-cardgroup-content > a.gs-card, a.gs-card:not(.gs-card--hidden, .gs-card--filtered-out)');\r\n cardGroup.groupAllHiddenCards = cardGroup.group.querySelectorAll('.gs-card--hidden');\r\n cardGroup.groupAllHiddenCards.forEach(card => {\r\n if (!card.classList.contains('gs-card--filtered-out')) {\r\n cardGroup.groupAllHiddenFilteredCards.push(card);\r\n }\r\n });\r\n }\r\n\r\n return cardGroup;\r\n};\r\n\r\n/**\r\n * Click handler which handles triggers when the \"Show Less\" button in a card\r\n * group is clicked. The handler then takes all of the cards in the card group\r\n * and ensure the correct classes are applied so that all cards are revealed\r\n * based on the designated number of cards to be displayed\r\n *\r\n * The \"Show Less\" button is then hidden from the view when the minimum number \r\n * of elements are displaying.\r\n *\r\n * @param {EventTarget} event\r\n * @param {number} amountToShow number of elements to show\r\n */\r\nexport const showLessCardsInGroup = (event, amountToShow = 3) => {\r\n\r\n const cardGroup = getCardGroupObject(event);\r\n\r\n if (cardGroup.group) {\r\n\r\n const cardsToHide = Array.from(cardGroup.groupAllVisibleCards).slice(amountToShow, cardGroup.groupAllVisibleCards.length);\r\n const cardButtonWrapper = cardGroup.groupButtonWrapper ?? cardGroup.groupShowMoreButtonWrapper;\r\n const cardDisplayButton = cardGroup.group.querySelector('.gs-cardgroup-showMore') ??\r\n cardGroup.group.querySelector('.gs-cardgroup-showAll');\r\n const groupCategoryWrapperTag = cardGroup.group.parentNode.getAttribute(\"data-tag\");\r\n\r\n if (groupCategoryWrapperTag) {\r\n sessionStorage.removeItem(groupCategoryWrapperTag);\r\n }\r\n\r\n let cardDisplayClass = null;\r\n\r\n if (cardDisplayButton && cardDisplayButton.classList.contains('gs-cardgroup-showMore')) {\r\n cardDisplayClass = showMoreHiddenClass;\r\n } else if (cardDisplayButton && cardDisplayButton.classList.contains('gs-cardgroup-showAll')) {\r\n cardDisplayClass = showAllHiddenClass;\r\n }\r\n\r\n hideAllCardsInGroup(cardsToHide);\r\n toggleCardHidden(cardButtonWrapper, true, showLessHiddenClass);\r\n toggleCardHidden(cardDisplayButton, false, cardDisplayClass);\r\n scrollToCardCategory(cardGroup);\r\n\r\n }\r\n\r\n};\r\n\r\n/**\r\n * Scripts which must be executed on page load in order to establish the interaction capabilities\r\n * of Card Groups. Running the script applies the required listeners to handle the \"Show More\" and\r\n * \"Show All\" capabilities\r\n * functionality\r\n */\r\nexport const cardGroupScripts = () => {\r\n const showMoreButtons = document.getElementsByClassName(showMoreButtonClass);\r\n const showAllButtons = document.getElementsByClassName(showAllButtonClass);\r\n const showLessButtons = document.getElementsByClassName(showLessButtonClass);\r\n\r\n if (showAllButtons && showAllButtons.length > 0) {\r\n for (let i = 0; i < showAllButtons.length; i++) {\r\n showAllButtons[i].addEventListener('click', showAllCardsInGroup);\r\n initSessionPagination(showAllButtons[i]);\r\n }\r\n }\r\n\r\n if (showMoreButtons && showMoreButtons.length > 0) {\r\n for (let i = 0; i < showMoreButtons.length; i++) {\r\n showMoreButtons[i].addEventListener('click', event => showMoreCardsInGroup(event, 6));\r\n initSessionPagination(showMoreButtons[i]); \r\n }\r\n }\r\n\r\n if (showLessButtons && showLessButtons.length > 0) {\r\n for (let i = 0; i < showLessButtons.length; i++) {\r\n showLessButtons[i].addEventListener('click', event => showLessCardsInGroup(event, 3));\r\n }\r\n }\r\n};\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/14/2020 JJacob 51694 Initial Create\r\n// 12/16/2020 JJacob 50360 Created Testimonial Carousel\r\n// 04/27/2021 BBARRON 59084 Add swipe detection to testimonials carousel\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const carouselScripts = {\r\n loadScripts: () => {\r\n const leftArrow = 'gs_testimony_left_arrow';\r\n const rightArrow = 'gs_testimony_right_arrow';\r\n\r\n var xDown = null; \r\n var yDown = null;\r\n var swipeResult = 0;\r\n\r\n const getTouches = (evt) => {\r\n return evt.touches;\r\n } \r\n\r\n // Record the starting point during a touch event\r\n const handleTouchStart = (evt) => {\r\n const firstTouch = getTouches(evt)[0]; \r\n xDown = firstTouch.clientX; \r\n yDown = firstTouch.clientY; \r\n }; \r\n\r\n // Calculate the drag distance during the swipe action\r\n const handleTouchMove = (evt) => {\r\n if ( ! xDown || ! yDown ) {\r\n return;\r\n }\r\n\r\n const xUp = evt.touches[0].clientX; \r\n const yUp = evt.touches[0].clientY;\r\n\r\n const xDiff = xUp - xDown;\r\n const yDiff = yUp - yDown;\r\n const xDist = Math.abs(xDiff);\r\n const yDist = Math.abs(yDiff);\r\n\r\n // minimum drag distance to count as a swipe\r\n const minSwipe = 100;\r\n\r\n // maximum drag distance before the carousel item locks into place\r\n const maxDrag = 200;\r\n\r\n // The direction of the drag\r\n const dragDirection = xDiff / xDist; // 1 or -1\r\n\r\n // The stopping point for the drag action\r\n const dragBoundary = maxDrag * dragDirection;\r\n\r\n //Allow the user to drag the active courael item up to maxDrag pixels in either direction as they swupe\r\n var positionAdjust = dragDirection < 0 ? Math.max(xDiff, dragBoundary) : Math.min(xDiff, dragBoundary);\r\n const currentItem = document.querySelector('.gs-testimony-content.--selected');\r\n currentItem.style.left = `${positionAdjust}px`;\r\n\r\n if ( xDist > yDist && xDist > minSwipe) {/*most significant*/\r\n if ( xDiff < 0 ) {\r\n //left swipe - next slide\r\n swipeResult = 1;\r\n } else {\r\n //right swipe - previous slide\r\n swipeResult = -1;\r\n } \r\n } \r\n };\r\n\r\n /**\r\n * Handle the swipe event if one was intended\r\n */\r\n const handleTouchEnd = () => {\r\n if (swipeResult !== 0) {\r\n var nextIndex = getIndexRelativeToCurrentSlide(swipeResult);\r\n \r\n setActiveSlide(nextIndex);\r\n swipeResult = 0;\r\n }\r\n xDown = null;\r\n yDown = null; \r\n };\r\n\r\n /**\r\n * Takes carousel to the previous slide\r\n */\r\n const goToPreviousSlide = () => {\r\n let nextIndex = getIndexRelativeToCurrentSlide(-1);\r\n setActiveSlide(nextIndex);\r\n };\r\n\r\n /**\r\n * Takes carousel to the next slide\r\n */\r\n const goToNextSlide = () => {\r\n let nextIndex = getIndexRelativeToCurrentSlide(1);\r\n setActiveSlide(nextIndex);\r\n };\r\n\r\n /**\r\n * Gets the current carousel index\r\n */\r\n const getCurrentSlideIndex = () => {\r\n const currentItem = document.querySelector('.gs-testimony-content.--selected');\r\n return parseInt(currentItem.dataset.indexval);\r\n };\r\n\r\n /**\r\n * Gets the slide index that is *step* slides over relative to the currently active slide\r\n * @param {number} step The number of slides relative to the current slide (1 is right and -1 is left)\r\n * @returns The absolute slide index relative \r\n */\r\n const getIndexRelativeToCurrentSlide = (step) => {\r\n const currentItemIndex = getCurrentSlideIndex();\r\n const numSlides = getNumSlides();\r\n return (currentItemIndex + step + numSlides) % numSlides;\r\n };\r\n\r\n /**\r\n * Gets the total number of slides in the carousel\r\n * @returns {number} The number of slides\r\n */\r\n const getNumSlides = () => {\r\n const allItems = document.querySelectorAll('.gs-testimony-content');\r\n return allItems.length;\r\n };\r\n\r\n const resetSlidePositions = () => {\r\n document.querySelectorAll('.gs-testimony-content').forEach(slide => { slide.style.left = '0px' })\r\n };\r\n\r\n /**\r\n * Sets the carousel slide at the given index to active\r\n * @param {number} index The slide to become active\r\n */\r\n const setActiveSlide = index => {\r\n // Change active slide\r\n const currentItem = document.querySelector('.gs-testimony-content.--selected');\r\n currentItem.classList.remove('--selected');\r\n document.querySelector('#gs_testimony_content_' + index).classList.add('--selected');\r\n \r\n // Reset any dragged slides to the center again\r\n resetSlidePositions();\r\n\r\n // update pagination dots\r\n const allIndicators = document.querySelectorAll('.gs-testimony-indicator');\r\n const selectedIndicator = document.querySelector('.gs-testimony-indicator.--active');\r\n if (!allIndicators[index].classList.contains('--active')) {\r\n selectedIndicator.classList.remove('--active');\r\n allIndicators[index].classList.add('--active');\r\n }\r\n };\r\n\r\n /**\r\n * Handles the user's intent to change the carousel to the given index\r\n * @param {number} index The index of the slide to jump to\r\n */\r\n const handleIndicatorClick = index => {\r\n const currentItemIndex = getCurrentSlideIndex();\r\n if (currentItemIndex !== index) {\r\n setActiveSlide(index);\r\n }\r\n };\r\n\r\n /**\r\n * Handles the users intent to jump to the next or previous slide\r\n * @param {string} direction \"left\" or \"right\" indicates which arrow was clicked\r\n */\r\n const handleArrowClick = direction => {\r\n if(direction === 'left') {\r\n goToPreviousSlide();\r\n } else {\r\n goToNextSlide();\r\n }\r\n };\r\n\r\n if (document.getElementById(leftArrow)) {\r\n\r\n const component = document.querySelector('.gs-testimony-inner');\r\n document.getElementById(leftArrow).addEventListener('click', () => {\r\n handleArrowClick('left');\r\n });\r\n\r\n document.getElementById(rightArrow).addEventListener('click', () => {\r\n handleArrowClick('right');\r\n });\r\n\r\n component.addEventListener('touchstart', handleTouchStart, false); \r\n component.addEventListener('touchmove', handleTouchMove, false);\r\n component.addEventListener('touchend', handleTouchEnd, false);\r\n\r\n [...document.querySelectorAll('.gs-testimony-indicator')].map((item, index) => {\r\n item.addEventListener('click', () => {\r\n handleIndicatorClick(index);\r\n });\r\n });\r\n }\r\n }\r\n};\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/14/2020 JJacob 51694 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const CollapseListScripts = {\r\n loadScripts: () => {\r\n const buttonId = 'gs_collapse_list_toggle_button_';\r\n const sectionId = 'gs_collapse_list_section_';\r\n\r\n const buttonClass = 'gs-collapse-list-toggle-button';\r\n const sectionClass = 'gs-collapse-list-toggle-section';\r\n\r\n const handleClick = id => {\r\n const active = document.querySelector('.gs-collapse-list-card.--active');\r\n let activeId;\r\n if (active) {\r\n activeId = active.id;\r\n active.classList.remove('--active');\r\n }\r\n if (activeId !== id) {\r\n const selected = document.querySelector('#' + id);\r\n selected.classList.add('--active');\r\n }\r\n };\r\n\r\n const handleButtonClick = id => {\r\n const items = document.querySelectorAll('.' + buttonClass + ', .' + sectionClass);\r\n items.forEach(item => {\r\n if (item.id === sectionId + id || item.id === buttonId + id) {\r\n item.classList.add('--selected');\r\n } else {\r\n item.classList.remove('--selected');\r\n }\r\n });\r\n };\r\n\r\n const elems = document.querySelectorAll('.gs-collapse-list-card');\r\n elems.forEach(element => {\r\n element.addEventListener('click', () => handleClick(element.id));\r\n });\r\n\r\n const stopLink = document.querySelectorAll('.gs-collapse-list-card a');\r\n stopLink.forEach(element => {\r\n element.addEventListener('click', e => {\r\n e.stopPropagation();\r\n });\r\n });\r\n\r\n const buttons = document.querySelectorAll('.' + buttonClass);\r\n buttons.forEach((button, index) => {\r\n button.addEventListener('click', () => {\r\n handleButtonClick(index + 1);\r\n });\r\n });\r\n }\r\n};\r\n","/* eslint-disable spaced-comment */\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/18/2020 HJordan Initial create\r\n// 04/18/2022 BBARRON 83828 Add Funds Search\r\n// 12/06/2022 BBARRON 95417 Add alternative search method with NoResultsMessage\r\n// 01/18/2023 BBARRON 97895 Add ability to select multiple tags\r\n// 01/25/2023 BBARRON 98536 Generate friendly response for search calls when on localhost or storybook\r\n// 02/20/2025 BBARRON 148963 Added logging around event creation to help troubleshoot\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nconst api = `/api/sitecore/`;\r\n\r\nfunction generateEmptyResponse(header, body, status, statusMessage) {\r\n if (!status) {\r\n status = 500;\r\n }\r\n\r\n return {\r\n SearchResults: null,\r\n NoResultsMessage: `

${header}

${body}

`,\r\n ResponseStatus: status,\r\n ResponseMessage: statusMessage\r\n };\r\n}\r\n\r\nconst fireSearchAnalyticsEvent = (query, tags) => {\r\n const tagsUsed = Array.isArray(tags) ? tags.join(',') : typeof tags === 'string' ? tags : '';\r\n\r\n const event = {\r\n tag: tagsUsed,\r\n query: query,\r\n event: 'search_query_submitted'\r\n };\r\n console.log(event);\r\n window.dataLayer = window.dataLayer || [];\r\n window.dataLayer.push(event);\r\n};\r\n\r\n/**\r\n * Async function which accepts a set of parameters needed to perform a\r\n * request for content via API fetch. The results of this call will be wrapped to allow for a no search results message\r\n * @param {string} section section param\r\n * @param {string} query query param\r\n * @param {string[]} tags tags param\r\n * @param {string} site The site to search\r\n * @return {Promise} promise which resolves upon completion of fetch\r\n */\r\nexport const searchContent = async (section, query, tags, site) => {\r\n const paramSection = section ? section : 'All';\r\n const paramSite = site ? site.toLowerCase() : 'brand';\r\n let contentSearchEndpoint;\r\n\r\n console.log('Content Search', section, query, tags, site);\r\n\r\n switch (site) {\r\n case 'funds':\r\n contentSearchEndpoint = `FundsSearch/Search`;\r\n break;\r\n default:\r\n contentSearchEndpoint = `contentSearch/search`;\r\n }\r\n\r\n const queryString = new URLSearchParams('');\r\n\r\n queryString.set('section', paramSection);\r\n queryString.set('site', paramSite);\r\n\r\n if (query) {\r\n queryString.set('query', query);\r\n }\r\n\r\n const tagsParam = Array.isArray(tags) ? tags.join(',') : tags;\r\n if (tags && tags.length > 0) {\r\n queryString.set('tag', tagsParam);\r\n }\r\n\r\n // Fire analytics event with query and tags\r\n fireSearchAnalyticsEvent(query, tags);\r\n\r\n let response;\r\n\r\n // Don't call search api on localhost or storybook, it won't work. Instead display a friendly error message\r\n if (window.location.hostname.includes('storybook') || window.location.hostname.includes('localhost')) {\r\n return generateEmptyResponse(\r\n 'Search unavailable in storybook',\r\n 'We apologize. Search is not available in storybook'\r\n );\r\n }\r\n\r\n try {\r\n // Get search results from Sitecore\r\n response = await fetch(`${api}${contentSearchEndpoint}?${queryString}`);\r\n\r\n // Parse successful responses as JSON\r\n if (response && response.status === 200) {\r\n return await response.json();\r\n }\r\n\r\n // Show error on failed responses\r\n return generateEmptyResponse(\r\n 'An Error Has Occurred',\r\n `We apologize. Search is not available at this time. Please try again later.`,\r\n response.status,\r\n response.statusText\r\n );\r\n } catch (err) {\r\n // Log errors to console\r\n console.error(err);\r\n return generateEmptyResponse(\r\n 'An Error Has Occurred',\r\n `We apologize. Search is not available at this time. Please try again later.`,\r\n 500,\r\n 'An error has occurred'\r\n );\r\n }\r\n};\r\n","/* eslint-disable spaced-comment */\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/07/2020 HJordan Initial create\r\n// 01/16/2021 HJordan Added timeout to search to allow animation of skeletons\r\n// 01/27/2021 HJordan Refactor method name to getInitialSearchParam for readability\r\n// 01/28/2020 HJordan 51238 Support Show More button if results exceed threshold\r\n// 01/29/2020 HJordan Bugfix to support firstChild selector when generating cards\r\n// 04/18/2022 BBARRON 83828 Add site parameter to search for Funds Search. Refactoring getCardTemplate into seprate method. Cleaned up generateResultsFromTemplates.\r\n// 04/29/2022 BBARRON 84662 Treat null or undefined section as \"all\"\r\n// 08/17/2022 BBARRON 90163 Add podcast as a search result type so results appear\r\n// 12/06/2022 BBARRON 95417 Search alternative endpoint and process NoResultsMessage when attribute is present\r\n// 01/18/2023 BBARRON 97895 Add ability to select and search by multiple tags\r\n// 05/12/2023 BBARRON 105895 Handle video results\r\n// 06/20/2023 GCASEY 107293 Add custom google analytics event for no search results\r\n// 07/12/2023 LBALL 56984 Education page paging should allow fewer items on mobile than for desktop\r\n// 09/20/2023 BBARRON 114362 Check for presence of search results on page before listening for window resize\r\n// 02/20/2025 BBARRON 148963 Cleaned up formatting based on \"prettier js\" formatting rules\r\n// 02/24/2025 GCASEY 148138 Add Evergreen option check to hide publish date\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { searchContent } from '../services/search';\r\nimport { getInitialSearchParams } from '../utils/search-utils';\r\nimport { showMoreCardsInGroup } from '../card-group/CardGroup';\r\n\r\nconst skeletonActiveClass = 'gs-cardGroupSkeleton--active';\r\nconst activeFadeInClass = 'gs-animateIn-bottom';\r\n\r\n/**\r\n * Function which toggles the visibility of skeleton loader based on the toggle flag\r\n *\r\n * @param {boolean} toggle flag which defines if skeleton cards should be hidden or visible\r\n */\r\nconst toggleSkeletonVisibility = toggle => {\r\n const searchSkeletonSection = document.getElementsByClassName('gs-cardGroupSkeleton')[0];\r\n\r\n if (toggle) {\r\n searchSkeletonSection.classList.add(skeletonActiveClass);\r\n searchSkeletonSection.classList.add(activeFadeInClass);\r\n } else {\r\n searchSkeletonSection.classList.remove(skeletonActiveClass);\r\n searchSkeletonSection.classList.remove(activeFadeInClass);\r\n }\r\n};\r\n\r\n/**\r\n * Sends the search_no_results event to google analytics with the information concerning the search query and tag\r\n */\r\nconst fireNoResultsAnalyticsEvent = () => {\r\n const params = new URLSearchParams(window.location.search);\r\n const tag = params.get('tag');\r\n const query = params.get('query');\r\n\r\n window.dataLayer = window.dataLayer || [];\r\n window.dataLayer.push({\r\n tag,\r\n query,\r\n event: 'search_no_results'\r\n });\r\n};\r\n\r\n/**\r\n * Async function which executes the API request for content, and upon response,\r\n * orchestrates the toggling of skeleton cards, and initiates the creation of\r\n * markup based on the results\r\n *\r\n * @param {string} section section param\r\n * @param {string} query query param\r\n * @param {string[]} tags array of tags\r\n * @param {string} site the site to search (funds|brand)\r\n */\r\nconst contentSearch = async (section, query, tags, site) => {\r\n const response = await searchContent(section, query, tags, site);\r\n if (response) {\r\n if (response.SearchResults && response.SearchResults.length > 0) {\r\n toggleSkeletonVisibility(false);\r\n removeNoResultsMessage();\r\n generateResultsFromTemplates(response.SearchResults, site);\r\n } else {\r\n toggleSkeletonVisibility(false);\r\n generateNoResultsMessage(response.NoResultsMessage);\r\n fireNoResultsAnalyticsEvent();\r\n }\r\n } else {\r\n console.error('Failed to get API response');\r\n }\r\n};\r\n\r\n/**\r\n * Function to generate the \"Show More\" button and eventListener registration to\r\n * the \"ShowMore\" script functionality\r\n *\r\n * @return {Node} button and wrapper generated via the template\r\n */\r\nconst generateShowMoreButton = () => {\r\n const showMoreTemplate = document.getElementById('gs-search-showMore-template');\r\n const clone = document.importNode(showMoreTemplate.content, true);\r\n\r\n clone.querySelector('button').addEventListener('click', event => showMoreCardsInGroup(event, 9));\r\n\r\n return clone;\r\n};\r\n\r\n/**\r\n * Function which generates a single Card node based on a dataset\r\n *\r\n * @param {object} data data containing attributes of a card\r\n * @param {boolean} isHidden flag to determine if card should have hidden class applied\r\n * @param {string} linkTarget The link target\r\n * @return {Node} generated markup for a card\r\n */\r\nconst generateCardNode = (data, isHidden, linkTarget) => {\r\n const { Type, Title, ShortDescription, CardImage, Date, Category, Url, Evergreen } = data;\r\n const card = getCardTemplate(Type);\r\n if (!card) {\r\n console.warn(`No card template found for type: ${Type}`);\r\n return null;\r\n }\r\n const subTitleNode = card.querySelector('.gs-card-subtitle');\r\n const svgIcon = card.querySelector('.gs-card-subtitle svg');\r\n\r\n subTitleNode.innerHTML = `${Category} ${Evergreen ? \"\" : \"• \" + Date}`;\r\n subTitleNode.insertBefore(svgIcon, subTitleNode.firstChild);\r\n card.querySelector('a').href = Url;\r\n if (linkTarget) {\r\n card.querySelector('a').target = linkTarget;\r\n }\r\n card.querySelector('img').src = CardImage;\r\n card.querySelector('h6').innerHTML = Title;\r\n card.querySelector('.gs-card-content').innerHTML = ShortDescription;\r\n\r\n if (isHidden) {\r\n card.firstElementChild.classList.add('gs-card--hidden');\r\n }\r\n\r\n return card;\r\n};\r\n\r\nconst getCardTemplate = cardType => {\r\n cardType = cardType.toLowerCase();\r\n let templateId;\r\n switch (cardType) {\r\n case 'video':\r\n case 'webinar':\r\n templateId = 'gs-search-card-webinar-template';\r\n break;\r\n case 'article':\r\n case 'commentary':\r\n case 'podcast':\r\n templateId = 'gs-search-card-article-template';\r\n break;\r\n case 'external link':\r\n templateId = 'gs-search-card-external-link-template';\r\n break;\r\n default:\r\n templateId = null;\r\n break;\r\n }\r\n\r\n if (!templateId) {\r\n return null;\r\n }\r\n\r\n const resultCardTemplate = document.getElementById(templateId);\r\n\r\n if (!templateId) {\r\n return null;\r\n }\r\n return document.importNode(resultCardTemplate.content, true);\r\n};\r\n\r\nconst manageMaxVisibleResultCount = () => {\r\n const maxVisible = getMaxVisibleResultCountFromViewport();\r\n const searchResults = document.getElementById('gs-content-search-results');\r\n if (!searchResults) {\r\n return;\r\n }\r\n\r\n const resultCardGroups = searchResults.querySelectorAll('.gs-cardgroup .gs-container-inner .gs-cardgroup-content');\r\n\r\n if (resultCardGroups.length > 0) {\r\n for (let i = 0; i < resultCardGroups.length; i++) {\r\n const resultCardsVisible = resultCardGroups[i].querySelectorAll('a.gs-card:not(.gs-card--hidden)');\r\n const resultCards = resultCardGroups[i].querySelectorAll('a.gs-card');\r\n let resultVisability = false;\r\n\r\n if (!resultCardsVisible.length) {\r\n continue;\r\n }\r\n\r\n if (resultCardsVisible.length < maxVisible) {\r\n resultVisability = true;\r\n }\r\n\r\n manageResultCardVisbility(maxVisible, resultCards, resultCardsVisible, resultVisability);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Function hides or shows search result cards\r\n *\r\n */\r\n\r\nconst manageResultCardVisbility = (maxVisible, resultCards, resultCardsVisible, hide = false) => {\r\n if (!hide) {\r\n for (let i = maxVisible; i <= resultCardsVisible.length; i++) {\r\n if (!resultCards[i].classList.contains('gs-card--hidden')) {\r\n resultCards[i].classList.add('gs-card--hidden');\r\n }\r\n }\r\n } else {\r\n for (let i = 0; i < maxVisible; i++) {\r\n if (resultCards[i].classList.contains('gs-card--hidden')) {\r\n resultCards[i].classList.remove('gs-card--hidden');\r\n }\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Function outputs the number of results to display based on the viewport\r\n *\r\n */\r\n\r\nconst getMaxVisibleResultCountFromViewport = () => {\r\n return window.innerWidth < 1024 ? 3 : 9;\r\n};\r\n\r\n/**\r\n * Function which generates the Card Group which will contain the list of items generated\r\n * based on the provided data set\r\n *\r\n * @param {string} title title for the card group\r\n * @param {array} data list of data elements needed to generate results\r\n * @param {string} linkTarget The link target\r\n * @return {Node} generated markup of a card group and it's children\r\n */\r\nconst generateSearchResultsNode = (title, data, linkTarget) => {\r\n const resultCardGroupTemplate = document.getElementById('gs-search-card-group-template');\r\n\r\n const resultCount = data.length;\r\n let resultsNode;\r\n let innerResultsNode;\r\n const maxVisible = getMaxVisibleResultCountFromViewport();\r\n\r\n if (resultCount >= 0) {\r\n resultsNode = document.importNode(resultCardGroupTemplate.content, true);\r\n resultsNode.querySelector('h5').innerHTML = `${title} (${resultCount})`;\r\n innerResultsNode = resultsNode.querySelector('.gs-cardgroup-content');\r\n innerResultsNode.classList.add(activeFadeInClass);\r\n\r\n for (let i = 0; i < resultCount; i++) {\r\n const isHidden = i >= maxVisible;\r\n const card = generateCardNode(data[i], isHidden, linkTarget);\r\n if (card) {\r\n innerResultsNode.appendChild(card);\r\n }\r\n }\r\n\r\n if (resultCount > maxVisible) {\r\n innerResultsNode.parentNode.appendChild(generateShowMoreButton());\r\n }\r\n }\r\n\r\n return resultsNode;\r\n};\r\n\r\n/**\r\n * Function targets the results section of a page and removes all nodes\r\n */\r\nconst removeVisibleSearchResultNodes = () => {\r\n const contentResultsSection = document.getElementById('gs-content-search-results');\r\n\r\n while (contentResultsSection.firstChild) {\r\n contentResultsSection.removeChild(contentResultsSection.lastChild);\r\n }\r\n};\r\n\r\n/**\r\n * Function which accepts the JSON results from the Brand or Funds Search API, and uses HTML templates\r\n * to generate the markup needed for the results list. Each type of content gets its own heading and list of cards\r\n *\r\n * @param {object} resultsData JSON payload of results\r\n * @param {string} site The site to search (funds|brand)\r\n */\r\nconst generateResultsFromTemplates = (resultsData, site) => {\r\n const contentResultsSection = document.getElementById('gs-content-search-results');\r\n const { section } = getInitialSearchParams();\r\n\r\n let contentTypes = [];\r\n\r\n if (site == 'funds') {\r\n contentTypes = [\r\n { type: 'commentary', sectionHeading: 'Commentary', section: 'commentary' },\r\n { type: 'external link', sectionHeading: 'News and Media', section: 'newsandmedia' },\r\n { type: 'podcast', sectionHeading: 'Podcasts', section: 'faithinvesting' }\r\n ];\r\n } else {\r\n contentTypes = [\r\n { type: 'article', sectionHeading: 'Articles', section: 'articles' },\r\n { type: 'video', sectionHeading: 'Videos', section: 'videos' },\r\n { type: 'webinar', sectionHeading: 'Webinars', section: 'webinars' }\r\n ];\r\n }\r\n\r\n contentTypes.forEach(c => {\r\n // If section is present it must be \"all\" or match the current content type.\r\n // If section is not present treat it as \"all\"\r\n if (!!section && section.toLowerCase() !== c.section && section.toLowerCase() !== 'all') {\r\n return;\r\n }\r\n\r\n const filteredResults = resultsData.filter(result => result.Type.toLowerCase() === c.type);\r\n const linkTarget = c.type === 'external link' ? '_blank' : null;\r\n const contentNode = generateSearchResultsNode(c.sectionHeading, filteredResults, linkTarget);\r\n if (contentNode) {\r\n contentResultsSection.appendChild(contentNode);\r\n }\r\n });\r\n};\r\n\r\n/**\r\n * Adds the no search results message to the gs-content-search-results container\r\n * @param {string} message The \"no search results found\" message to display\r\n */\r\nconst generateNoResultsMessage = message => {\r\n const resultsSection = document.getElementById('gs-content-search-results');\r\n\r\n const outer = document.createElement('div');\r\n outer.classList.add('gs-container');\r\n outer.classList.add('gs-container-color--primary');\r\n outer.classList.add('gs-section');\r\n outer.classList.add('gs-search--no-results');\r\n\r\n const inner = document.createElement('div');\r\n inner.classList.add('gs-container-inner');\r\n\r\n const content = document.createElement('div');\r\n content.classList.add('gs-section-content');\r\n\r\n const block = document.createElement('div');\r\n block.classList.add('gs-rich-content-block');\r\n block.innerHTML = message;\r\n\r\n content.appendChild(block);\r\n inner.appendChild(content);\r\n outer.appendChild(inner);\r\n resultsSection.appendChild(outer);\r\n};\r\n\r\nconst removeNoResultsMessage = () => {\r\n const contentResultsSection = document.getElementById('gs-content-search-results');\r\n const noResultsContainer = contentResultsSection.querySelector('.gs-search--no-results');\r\n if (noResultsContainer) {\r\n noResultsContainer.remove();\r\n }\r\n};\r\n\r\n/**\r\n * Entry function which orchestrates the execution of an API search, and the update of the DOM\r\n * based on results received from the API request\r\n *\r\n * The request includes a 1 second delay to allow skeleton loaders to animate without a flicker\r\n * in the case that the API returns too quickly\r\n *\r\n * @param {string} section section param\r\n * @param {string} query query param\r\n * @param {string} tags tags param\r\n * @param {string} site the site to search (funds|brand)\r\n */\r\nexport const searchContentAndUpdateResults = (section, query, tags, site) => {\r\n const contentResultsSection = document.getElementById('gs-content-search-results');\r\n\r\n if (contentResultsSection) {\r\n removeVisibleSearchResultNodes();\r\n toggleSkeletonVisibility(true);\r\n\r\n setTimeout(() => {\r\n contentSearch(section, query, tags, site);\r\n }, 1000);\r\n }\r\n};\r\n\r\nconst searchResults = document.getElementById('gs-content-search-results');\r\nif (searchResults) {\r\n window.addEventListener('resize', manageMaxVisibleResultCount);\r\n}\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 01/25/2023 BBARRON 98828 Initial Create\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nconst simpleSearchBarValidationClass = 'gs-simple-search-bar-input-wrapper';\r\nconst searchBarValidationClass = 'gs-search-bar-input-wrapper';\r\nconst validationSuffix = '--error';\r\nconst messageValidationClass = 'gs-search-bar-validation--visible';\r\n\r\nconst searchElementIds = {\r\n searchBar: 'gs-content-search-bar',\r\n searchValidation: 'gs-content-search-validation',\r\n searchInput: 'gs-content-search-input'\r\n};\r\n \r\nconst mobileSearchElementIds = {\r\n searchBar: 'gs-content-search-bar-mobile',\r\n searchValidation: 'gs-content-search-validation-mobile',\r\n searchInput: 'gs-content-search-input-mobile'\r\n};\r\n\r\nexport const getSearchBar = (isMobile) => {\r\n return document.getElementById(isMobile ? mobileSearchElementIds.searchBar : searchElementIds.searchBar);\r\n}\r\n\r\nexport const getSearchValidation = (isMobile) => {\r\n return document.getElementById(isMobile ? mobileSearchElementIds.searchValidation : searchElementIds.searchValidation);\r\n}\r\n\r\nexport const getSearchInput = (isMobile) => {\r\n return document.getElementById(isMobile ? mobileSearchElementIds.searchInput : searchElementIds.searchInput);\r\n}\r\n\r\n/**\r\n * Simple validator function which checks if a given value meets the required number\r\n * of characters\r\n * @param {string} queryString Event passed by the listener\r\n * @return {boolean} identifies if queryString is valid or invalid\r\n */\r\nexport const validateSearchQuery = query => {\r\n if (query) {\r\n if (query.length > 2) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n};\r\n\r\n/**\r\n * Function which takes an element, and a validation flag, and toggles the appropriate\r\n * validation classes on elements depending on the state of the validation flag\r\n * @param {boolean} isValid flag which identifies if valid or invalid\r\n * @param {Node} element dom element to be manipulated\r\n * @param {Object} searchIds ids for the search elements (either desktop or mobile)\r\n */\r\nexport const updateSearchValidationVisibility = (isValid, element, isMobile) => {\r\n const contentSearchValidation = getSearchValidation(isMobile);\r\n const searchBar = getSearchBar(isMobile);\r\n const simpleSearch = searchBar.classList.contains(simpleSearchBarValidationClass);\r\n const contentSiteSearch = searchBar.classList.contains(searchBarValidationClass);\r\n\r\n element.setAttribute('aria-invalid', !isValid);\r\n\r\n if (isValid) {\r\n contentSearchValidation.classList.remove(messageValidationClass);\r\n if (simpleSearch) {\r\n searchBar.classList.remove(`${simpleSearchBarValidationClass}${validationSuffix}`);\r\n } else if (contentSiteSearch) {\r\n searchBar.classList.remove(`${searchBarValidationClass}${validationSuffix}`);\r\n }\r\n } else {\r\n contentSearchValidation.classList.add(messageValidationClass);\r\n if (simpleSearch) {\r\n searchBar.classList.add(`${simpleSearchBarValidationClass}${validationSuffix}`);\r\n } else if (contentSiteSearch) {\r\n searchBar.classList.add(`${searchBarValidationClass}${validationSuffix}`);\r\n }\r\n }\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/07/2020 HJordan Initial create\r\n// 12/18/2020 HJordan Add initializeContentSearch to fetch content when URL params exist\r\n// 01/27/2021 HJordan Refactor to ensure default tag, and appropriate input validation on submit\r\n// 01/29/2020 HJordan Support mobile / desktop unique IDs needed for successful site search\r\n// 04/18/2022 BBARRON 83828 Check markup for site attribute to call the right search API\r\n// 01/18/2023 BBARRON 97895 Add ability to select multiple tags\r\n// 01/23/2023 BBARRON 98536 Get multiple tags when search button is clicked as well\r\n// 01/25/2023 BBARRON 98828 Move search validation methods and constants to SearchValidation file\r\n// 02/01/2023 BBARRON 99334 Renamd updatePageSearchContent function to initializeContentSearch and fix typo\r\n// 02/07/2023 BBARRON 99963 Don't trigger content search unless content search form exists\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { setSearchQueryParam, getInitialSearchParams, setTagParam } from '../utils/search-utils';\r\nimport { searchContentAndUpdateResults } from '../content-search-results/ContentSearchResults';\r\nimport { showAllTags, selectTag, selectAllTag, getAllSelectedTags } from '../tag-filters/TagFilters';\r\nimport { updateSearchValidationVisibility, validateSearchQuery, getSearchInput } from './SearchValidation';\r\n\r\n/** \r\n * Simple function to set the tag query string to \"all\" if there are no provided tag values.\r\n * Otherwise set the tag query string to all selected tags, separated by commas.\r\n * @param {String[]} tags string values for the tags\r\n */\r\nconst initializeDefaultTag = tags => {\r\n if (typeof tags === undefined || tags === null || tags.length === 0 || !tags.some(tag => tag !== '')) {\r\n selectAllTag();\r\n setTagParam('all');\r\n } else {\r\n setTagParam(tags.join(','));\r\n }\r\n};\r\n\r\n/**\r\n * Scripts which must be executed on page load in order to establish submit\r\n * listeners on the search form used for handling \"Content Search\" functionality.\r\n *\r\n * NOTE: These scripts are assigned to any search form assigned the gs-content-search-form\r\n */\r\nexport const contentSearchScripts = () => {\r\n const contentSearchForm = document.getElementById('gs-content-search-form');\r\n const searchInput = getSearchInput(false);\r\n const searchListenerAdded = contentSearchForm ? contentSearchForm.dataset.searchListener : false;\r\n\r\n /**\r\n * Simple helper function with the responsibility of setting the query url parameter in\r\n * the url if the provided value is valid\r\n *\r\n * @param {String} queryValue value of a search action to be added to the query params\r\n */\r\n const manageSearchQueryParam = queryValue => {\r\n const searchQueryValid = validateSearchQuery(queryValue);\r\n\r\n if (searchQueryValid) {\r\n setSearchQueryParam(queryValue);\r\n } else {\r\n setSearchQueryParam(null);\r\n }\r\n };\r\n\r\n /**\r\n * Form submit handler function which checks the validity of the form values, and\r\n * then executes a request to execute a content search (which subsequently updates\r\n * search results in the view)\r\n *\r\n * @param {EventTarget} event Event passed by the listener\r\n */\r\n const contentSearchClicked = event => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n const searchInput = getSearchInput(false);\r\n manageSearchQueryParam(searchInput.value);\r\n\r\n const { section, query } = getInitialSearchParams();\r\n const searchQueryValid = validateSearchQuery(query);\r\n const site = contentSearchForm ? contentSearchForm.dataset.site || 'brand' : 'brand';\r\n const tags = getAllSelectedTags();\r\n\r\n if (searchQueryValid) {\r\n initializeDefaultTag(tags);\r\n updateSearchValidationVisibility(searchQueryValid, searchInput, false);\r\n searchContentAndUpdateResults(section, query, tags, site);\r\n } else {\r\n updateSearchValidationVisibility(searchQueryValid, searchInput, false);\r\n }\r\n };\r\n\r\n if (contentSearchForm && !searchListenerAdded) {\r\n contentSearchForm.dataset.searchListener = true;\r\n contentSearchForm.addEventListener('submit', contentSearchClicked);\r\n searchInput.addEventListener('blur', event => manageSearchQueryParam(event.target.value));\r\n }\r\n};\r\n\r\n/**\r\n * Scripts which must be executed on page load in order to establish submit\r\n * listeners on the search form used for handling \"Site Search\" functionality.\r\n *\r\n * NOTE: These scripts are assigned to any search form assigned the gs-site-search-form\r\n */\r\nexport const siteSearchScripts = () => {\r\n const siteSearchForm = document.getElementById('gs-site-search-form');\r\n const mobileSiteSearchForm = document.getElementById('gs-site-search-form-mobile');\r\n const searchListenerAdded = siteSearchForm ? siteSearchForm.dataset.searchListener : false;\r\n const mobileSearchListenerAdded = mobileSiteSearchForm ? mobileSiteSearchForm.dataset.searchListener : false;\r\n\r\n /**\r\n * Form submit handler function which checks the validity of the form values, and\r\n * then executes a redirect to the appropriate URL if the search term is valid\r\n *\r\n * @param {EventTarget} event Event passed by the listener\r\n * @param {Object} isMobile whether the search is mobile\r\n */\r\n const siteSearchSubmitted = (event, isMobile) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n const activeInput = getSearchInput(isMobile);\r\n const searchQuery = activeInput.value;\r\n const searchQueryValid = validateSearchQuery(searchQuery);\r\n\r\n updateSearchValidationVisibility(searchQueryValid, activeInput, isMobile);\r\n\r\n if (searchQueryValid) {\r\n const origin = window.location.origin;\r\n const searchURL = `/search`;\r\n const newLocation = `${origin}${searchURL}?q=${searchQuery}`;\r\n\r\n window.location.href = newLocation;\r\n }\r\n };\r\n\r\n if (siteSearchForm && !searchListenerAdded) {\r\n siteSearchForm.dataset.searchListener = true;\r\n siteSearchForm.addEventListener('submit', event => siteSearchSubmitted(event, false));\r\n }\r\n\r\n if (mobileSiteSearchForm && !mobileSearchListenerAdded) {\r\n mobileSiteSearchForm.dataset.searchListener = true;\r\n mobileSiteSearchForm.addEventListener('submit', event => siteSearchSubmitted(event, true));\r\n }\r\n};\r\n\r\n/**\r\n * When the page loads, we want to update the state of the UI to match the state indicated in the URL query parms.\r\n * This includes populating the search text and selected tags.\r\n */\r\nexport const initializeContentSearch = () => {\r\n const { section, tags, query } = getInitialSearchParams();\r\n const hasTags = tags && tags.length > 0;\r\n if (!hasTags && !query) {\r\n // if nothing in the query string, then no initial setup needed\r\n return;\r\n }\r\n\r\n const contentSearchForm = document.getElementById('gs-content-search-form');\r\n if (contentSearchForm) {\r\n const site = contentSearchForm ? contentSearchForm.dataset.site || 'brand' : 'brand';\r\n searchContentAndUpdateResults(section, query, tags, site);\r\n }\r\n\r\n if (hasTags) {\r\n // Start with all tags visible if any tag is selected/active based on query string.\r\n // NOTE: if all tags show even when hasTags is false, check session storage.\r\n // DateTagFilters.js for the news-room page stores show more clikc as a user preference for later.\r\n showAllTags();\r\n tags.forEach(tagName => selectTag(tagName));\r\n }\r\n\r\n if (query && contentSearchForm) {\r\n const searchFormInput = contentSearchForm.querySelector('input');\r\n searchFormInput.value = query;\r\n }\r\n \r\n};\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/09/2020 Jjacob 52558 Initial Create\r\n// 02/04/2021 BBARRON 56210 Updated the handleSelectItem event handler to include an isSimpleLogin parameter\r\n// Added a launch mode (simple) and a login mode (not simple)\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const customSelectScripts = {\r\n loadScripts: () => {\r\n const selectId = 'gs_login_location_select';\r\n const groupName = 'gs-login-group';\r\n const numSelectItems = 3;\r\n const loginSection = 'gs-login-section';\r\n const loginSectionButton = 'gs-login-section-button';\r\n\r\n const handleSelectOpen = () => {\r\n document.getElementById('gs_login_location_select_selector').style.display = 'block';\r\n };\r\n\r\n const handleSelectClose = () => {\r\n document.getElementById('gs_login_location_select_selector').style.display = 'none';\r\n };\r\n\r\n const handleSwitchToLaunchMode = () => {\r\n // Hide form fields\r\n document.querySelectorAll(`.${loginSection}`).forEach(element => {\r\n element.classList.add('--hidden');\r\n });\r\n // Hide signin buttons\r\n document.querySelectorAll(`.${loginSectionButton}`)[0].classList.add('--hidden');\r\n // Show launch buttons\r\n document.querySelectorAll(`.${loginSectionButton}`)[1].classList.remove('--hidden');\r\n };\r\n\r\n const handleSwitchToSignInMode = () => {\r\n // Show form fields\r\n document.querySelectorAll(`.${loginSection}`).forEach(element => {\r\n element.classList.remove('--hidden');\r\n });\r\n // Show signin buttons\r\n document.querySelectorAll(`.${loginSectionButton}`)[0].classList.remove('--hidden');\r\n // Hide launch buttons\r\n document.querySelectorAll(`.${loginSectionButton}`)[1].classList.add('--hidden');\r\n };\r\n\r\n const handleSelectItem = (item, isSimpleLogin) => {\r\n for (let i = 1; i <= numSelectItems; i++) {\r\n const currGroup = document.querySelectorAll('.' + groupName + '-' + i);\r\n \r\n if (item === i) {\r\n // Update the dropdown menu text\r\n const itemName = document.getElementById(selectId + '_item_' + i).innerHTML;\r\n // Show/hide links for the current selection\r\n document.getElementById(selectId + '_input').innerHTML = itemName;\r\n currGroup.forEach(element => {\r\n element.style.display = 'block';\r\n });\r\n } else {\r\n currGroup.forEach(element => {\r\n element.style.display = 'none';\r\n });\r\n }\r\n }\r\n\r\n if(isSimpleLogin) {\r\n handleSwitchToLaunchMode();\r\n } else {\r\n handleSwitchToSignInMode();\r\n }\r\n\r\n handleSelectClose();\r\n };\r\n\r\n if (document.getElementById(selectId + '_input')) {\r\n document.getElementById(selectId + '_input_wrapper').addEventListener('click', () => {\r\n handleSelectOpen();\r\n });\r\n document.getElementById(selectId + '_selector').addEventListener('mouseleave', () => {\r\n handleSelectClose();\r\n });\r\n for (let i = 1; i <= numSelectItems; i++) {\r\n document.getElementById(selectId + '_item_' + i).addEventListener('click', (evt) => {\r\n let isSimpleLogin = evt.target.classList.contains('gs-login-simple')\r\n handleSelectItem(i, isSimpleLogin);\r\n });\r\n }\r\n }\r\n }\r\n};\r\n","/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 01/14/2021 JJacob 52579 Initial Create\r\n// 02/25/2021 KKapoor 56273 Persist filter criteria state\r\n// 04/22/2021 BBARRON 60111 Add a no results message when no cards are visible\r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\nimport { hideAllCardsInGroup, showMoreCardsInGroup } from '../card-group/CardGroup';\r\n\r\n// The ID of the button that shows all hidden tags\r\nconst showMoreTagId = 'gs-tag-filter-show-more';\r\n\r\n// The css class of all hidden tags\r\nconst tagHiddenClass = 'gs-tag-filter-btn--hidden';\r\n\r\n// The css class of the currently selected tag\r\nconst tagSelectedClass = 'gs-tag-filter-btn--selected';\r\n\r\n// In order for this component to work, the results to be filtered must be wrapped in an element with this ID\r\nconst resultsSectionId = 'gs-content-results';\r\n\r\n// The ID of the tag filter control\r\nconst tagFilterID = 'gs-date-tag-filters-tag-filter';\r\n\r\n// The ID of the date filter control\r\nconst dateFilterID = 'gs-date-tag-filters-date-filter';\r\n\r\nconst noResultsClass = 'gs-date-tag-filters--noresults';\r\n\r\n/**\r\n * Function accepts a tag element and persists in session storage\r\n *\r\n * @param {Node} element element to be manipulated\r\n */\r\nconst persistSelectedTag = (element) => {\r\n var selectedTag = element.dataset.tag ? element.dataset.tag : 'all';\r\n window.sessionStorage.setItem(window.location.href + 'Tag', selectedTag); \r\n};\r\n\r\n/**\r\n * Function accepts a date element and persists in session storage\r\n *\r\n * @param {Node} element element to be manipulated\r\n */\r\nconst persistSelectedDate = (element) => {\r\n var selectedDate = element.value ? element.value : 'all';\r\n window.sessionStorage.setItem(window.location.href + 'Date', selectedDate);\r\n};\r\n\r\n/**\r\n * Function to persist state of show more button in session storage\r\n */\r\nconst persistShowMoreTagState = () => {\r\n var isShowMoreTagHidden = true;\r\n window.sessionStorage.setItem(window.location.href + 'ShowMore', isShowMoreTagHidden);\r\n};\r\n\r\n/**\r\n * Function to restore persisted tag filter from session storage\r\n */\r\nconst restoreSelectedTag = () => {\r\n var selectedTag = window.sessionStorage.getItem(window.location.href + 'Tag');\r\n selectedTag = selectedTag ? selectedTag : 'all';\r\n const tagSelector = document.getElementById(tagFilterID);\r\n var targetTag = tagSelector.querySelector(\"button[data-tag='\" + selectedTag + \"']\");\r\n if (targetTag) {\r\n executeFilterByTag(targetTag);\r\n }\r\n};\r\n\r\n/**\r\n * Function to restore persisted date filter from session storage\r\n */\r\nconst restoreSelectedDate = () => {\r\n var selectedDate = window.sessionStorage.getItem(window.location.href + 'Date');\r\n selectedDate = selectedDate ? selectedDate : 'all';\r\n const dateSelector = document.getElementById(dateFilterID);\r\n dateSelector.value = selectedDate;\r\n};\r\n\r\n/**\r\n * Function to restore show more button state from session storage\r\n */\r\nconst restoreShowMoreTagState = () => {\r\n const showMoreTag = document.getElementById(showMoreTagId);\r\n const allHiddenTags = document.getElementsByClassName(tagHiddenClass);\r\n var isShowMoreTagHidden = window.sessionStorage.getItem(window.location.href + 'ShowMore');\r\n if (isShowMoreTagHidden) {\r\n displayHiddenTags(allHiddenTags);\r\n toggleTagHidden(showMoreTag, true);\r\n }\r\n};\r\n\r\n\r\n\r\n\r\n/**\r\n * Function which accepts an element, and a toggle flag and\r\n * toggles the elements \"Hidden\" classes based on the toggle\r\n *\r\n * @param {Node} element The tag element to be shown/hidden\r\n * @param {boolean} hide if true, the tag will be hidden. If false the tag will become visible\r\n */\r\n const toggleTagHidden = (element, hide) => {\r\n if (hide) {\r\n element.classList.add(tagHiddenClass);\r\n } else {\r\n element.classList.remove(tagHiddenClass);\r\n }\r\n};\r\n\r\n/**\r\n * Function which accepts an element, and a toggle flag and\r\n * toggles the elements \"Selected\" classes based on the toggle\r\n *\r\n * @param {Node} element element to be manipulated\r\n * @param {boolean} toggle flag to identify selected or not-selected\r\n */\r\nconst toggleTagSelected = (element, toggle) => {\r\n if (toggle) {\r\n element.classList.add(tagSelectedClass);\r\n } else {\r\n element.classList.remove(tagSelectedClass);\r\n }\r\n};\r\n\r\n/**\r\n * Function which accepts a list of tags which are currently hidden, and\r\n * toggles them to be revealed\r\n *\r\n * @param {Array} hiddenTagList list of hidden Tag nodes\r\n */\r\nconst displayHiddenTags = hiddenTagList => {\r\n if (hiddenTagList && hiddenTagList.length > 0) {\r\n while (hiddenTagList.length > 0) {\r\n toggleTagHidden(hiddenTagList[0], false);\r\n }\r\n }\r\n};\r\n\r\nconst showNoResultsMessage = () => {\r\n const noResultsMessage = document.querySelector(`#${resultsSectionId} .${noResultsClass}`);\r\n const results = document.querySelector(`#${resultsSectionId} > .gs-cardgroup`);\r\n if(noResultsMessage !== null) {\r\n console.log('showing the no results element');\r\n noResultsMessage.classList.remove('--hidden');\r\n results.style.display = \"none\";\r\n }\r\n}\r\n\r\nconst hideNoResultsMessage = () => {\r\n const noResultsMessage = document.querySelector(`#${resultsSectionId} .${noResultsClass}`);\r\n const results = document.querySelector(`#${resultsSectionId} > .gs-cardgroup`);\r\n if(noResultsMessage !== null) {\r\n console.log('hiding the no results element');\r\n noResultsMessage.classList.add('--hidden');\r\n results.style.display = \"block\";\r\n }\r\n}\r\n\r\n/**\r\n * Function which targets any tags marked with \"hidden\" classes to be\r\n * updated so that they are revealed\r\n *\r\n * @param {EventTarget} event event passed by the listener\r\n */\r\nexport const showAllTags = event => {\r\n const showMoreTag = document.getElementById(showMoreTagId);\r\n // const allHiddenTags = document.querySelectorAll('.'+tagHiddenClass);\r\n const allHiddenTags = document.getElementsByClassName(tagHiddenClass);\r\n\r\n if (event) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }\r\n\r\n if (showMoreTag && allHiddenTags) { \r\n displayHiddenTags(allHiddenTags);\r\n toggleTagHidden(showMoreTag, true);\r\n persistShowMoreTagState();\r\n }\r\n};\r\n\r\n/**\r\n * Function which accepts a tag element and sets the tag to the correct \"selected\"\r\n * classes, and ensures all other tags in the group are NOT marked as selected\r\n *\r\n * @param {Node} tag the clicked tag element\r\n */\r\nexport const setTagSelectedClass = tag => {\r\n const currentlySelectedTags = document.getElementsByClassName(tagSelectedClass);\r\n\r\n if (currentlySelectedTags && currentlySelectedTags.length > 0) {\r\n for(let i = 0; i < currentlySelectedTags.length; i += 1) {\r\n toggleTagSelected(currentlySelectedTags[i], false);\r\n }\r\n }\r\n\r\n tag.classList.add(tagSelectedClass);\r\n};\r\n\r\n/**\r\n * Client-Side Tag click handler which accepts a clicked tag element, and uses the element's\r\n * data-tag attribute to perform the following actions\r\n *\r\n * Set the correct classNames to style the tag as selected\r\n * Set any elements with matching the data-tag attribute to hidden/visible\r\n *\r\n * @param {Node} tag the clicked tag element\r\n */\r\nconst filterResults = () => {\r\n const resultsSection = document.getElementById(resultsSectionId);\r\n const resultCards = resultsSection ? resultsSection.querySelectorAll('.gs-card') : null;\r\n const tagAttributeIndicator = document.querySelector('.gs-tag-filter-btn.gs-tag-filter-btn--selected');\r\n const dateAttributeIndicator = document.getElementById(dateFilterID);\r\n const tagAttribute = tagAttributeIndicator?.dataset.tag ? tagAttributeIndicator?.dataset.tag : 'all';\r\n const dateAttribute = dateAttributeIndicator.value ? dateAttributeIndicator.value : 'all';\r\n let visibleResults = [];\r\n\r\n if(resultCards) {\r\n resultCards.forEach(card => {\r\n if (isDateMatch(card, dateAttribute) && isTagMatch(card, tagAttribute)) {\r\n card.classList.remove('gs-card--filtered-out');\r\n visibleResults.push(card);\r\n } else {\r\n card.classList.add('gs-card--filtered-out');\r\n }\r\n });\r\n\r\n // Show or hide the no results message depending on the number of visible results after filtering\r\n \r\n if(visibleResults.length > 0) {\r\n hideNoResultsMessage();\r\n } else {\r\n showNoResultsMessage();\r\n }\r\n\r\n hideAllCardsInGroup();\r\n showMoreCardsInGroup(null, 6);\r\n }\r\n}\r\n\r\n/**\r\n * Determines whether a given card or article matches the given date filter.\r\n * If the date filter is 'all', it always matches.\r\n * @param {HTMLElement} card The card element which contains a data-date attribute\r\n * @param {string} dateFilter The desired year or 'all'\r\n */\r\nconst isDateMatch = (card, dateFilter) => {\r\n if(dateFilter === 'all') {\r\n return true;\r\n }\r\n const cardDateAttribute = card.dataset.date;\r\n return cardDateAttribute === dateFilter;\r\n}\r\n\r\n/**\r\n * Determines whether a given card or article matches the given tag filter.\r\n * If the tag filter is 'all', it always matches.\r\n * @param {HTMLElement} card The card element which contains a data-tag attribute\r\n * @param {string} tagFilter The desired tag name or 'all'\r\n */\r\nconst isTagMatch = (card, tagFilter) => {\r\n if (tagFilter === 'all') {\r\n return true;\r\n }\r\n const cardTagAttribute = card.dataset.tag;\r\n return cardTagAttribute === tagFilter;\r\n}\r\n\r\n\r\n\r\nconst executeFilterByTag = tag => {\r\n setTagSelectedClass(tag);\r\n persistSelectedTag(tag);\r\n filterResults();\r\n};\r\n\r\nconst executeFilterByDate = dateSelector => {\r\n persistSelectedDate(dateSelector);\r\n filterResults();\r\n};\r\n\r\nexport const dateTagFilterScripts = () => {\r\n const tagSelector = document.getElementById(tagFilterID);\r\n const dateSelector = document.getElementById(dateFilterID);\r\n const showMoreTag = document.getElementById(showMoreTagId);\r\n\r\n if (showMoreTag) {\r\n showMoreTag.addEventListener('click', showAllTags, false);\r\n restoreShowMoreTagState();\r\n }\r\n\r\n if (tagSelector) {\r\n const tags = tagSelector.querySelectorAll('button.gs-tag-filter-btn');\r\n for (let i = 0; i < tags.length; i++) {\r\n if (tags[i].id !== showMoreTagId) {\r\n tags[i].addEventListener('click', () => executeFilterByTag(tags[i]), false);\r\n }\r\n }\r\n restoreSelectedTag();\r\n }\r\n\r\n if (dateSelector) {\r\n dateSelector.addEventListener('change', () => executeFilterByDate(dateSelector), false);\r\n restoreSelectedDate();\r\n }\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 05/16/2022 ZSunOo 83533 Initial Create\r\n// 05/18/2022 ZSunOo 83533 Enhancement for Full factSheetFundHeader\r\n// 05/23/2022 ZSunOo 83533 Mobile Dropdown Enhancement\r\n// 06/02/2022 ZSunOo 86197 Design Revision Updates\r\n// 08/04/2022 BBARRON 89814 Break out of funds header script if key elements are missing\r\n// 09/26/2022 BBARRON 89639 Update mobile expand/collapse script to work with simplified markup\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const factSheetFundHeaderScript = {\r\n loadScripts: () => {\r\n const viewAnotherFund = document.querySelector('.view-another-fund-desktop');\r\n const hamburgerMenu = document.querySelector('.mobile-hamburger-menu');\r\n const mobileFundsNavigation = document.querySelector('.mobile-funds-navigation');\r\n\r\n // Exit if the component is not on the page\r\n if(!viewAnotherFund || !hamburgerMenu || !mobileFundsNavigation) {\r\n return;\r\n }\r\n\r\n if ((hamburgerMenu && mobileFundsNavigation, viewAnotherFund)) {\r\n const mobileFundsNavigationOverlay = mobileFundsNavigation.querySelector('.mobile-funds-navigation-overlay');\r\n const closeButton = mobileFundsNavigation.querySelector('.close-button');\r\n\r\n mobileFundsNavigation.classList.remove('active');\r\n [viewAnotherFund, hamburgerMenu].forEach(element =>\r\n element.addEventListener('click', e => {\r\n e.preventDefault();\r\n mobileFundsNavigation.classList.add('active');\r\n })\r\n );\r\n\r\n const closeNavTriggers = [closeButton, mobileFundsNavigationOverlay];\r\n closeNavTriggers.forEach(element => {\r\n element.classList.remove('active');\r\n element.addEventListener('click', e => {\r\n e.preventDefault();\r\n mobileFundsNavigation.classList.remove('active');\r\n });\r\n });\r\n }\r\n\r\n const bottomLinks = document.querySelectorAll('.bottom-row-list-item-link');\r\n if (!!bottomLinks.length) {\r\n bottomLinks.forEach(link =>\r\n link.addEventListener('click', e => {\r\n bottomLinks.forEach(l => l.classList.remove('active'));\r\n link.classList.add('active');\r\n const target = document.querySelector(e.currentTarget.href);\r\n if (target) target.scrollIntoView();\r\n })\r\n );\r\n }\r\n\r\n const headerBottom = document.querySelector('.header-bottom');\r\n const expandButton = document.querySelector('.expand-button');\r\n const collapseButton = document.querySelector('.collapse-button');\r\n\r\n // logic for if headerBottom, expandButton, and collapseButton exists\r\n const isCollapsible = headerBottom && expandButton && collapseButton;\r\n\r\n if (isCollapsible) {\r\n expandButton.addEventListener('click', () => {\r\n expandButton.classList.remove('active');\r\n collapseButton.classList.add('active');\r\n headerBottom.classList.add('expanded');\r\n });\r\n\r\n collapseButton.addEventListener('click', () => {\r\n expandButton.classList.add('active');\r\n collapseButton.classList.remove('active');\r\n headerBottom.classList.remove('expanded');\r\n });\r\n }\r\n\r\n const accordionLinks = mobileFundsNavigation.querySelectorAll('.is-accordion > a');\r\n if (accordionLinks?.length) {\r\n accordionLinks.forEach(link => {\r\n link.addEventListener('click', e => {\r\n e.preventDefault();\r\n e.target.parentNode.classList.toggle('active');\r\n });\r\n });\r\n }\r\n },\r\n destroyScripts: () => {\r\n const mobileFundsNavigation = document.querySelector('.mobile-funds-navigation');\r\n const mobileFundsNavigationOverlay = mobileFundsNavigation.querySelector('.mobile-funds-navigation-overlay');\r\n const closeButton = mobileFundsNavigation.querySelector('.close-button');\r\n\r\n const closeNavTriggers = [closeButton, mobileFundsNavigationOverlay];\r\n closeNavTriggers.forEach(element => {\r\n element.removeEventListener('click', () => {});\r\n });\r\n\r\n const accordionLinks = mobileFundsNavigation.querySelectorAll('.is-accordion > a');\r\n if (accordionLinks?.length) {\r\n accordionLinks.forEach(link => {\r\n link.removeEventListener('click', () => {});\r\n });\r\n }\r\n }\r\n};\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 06/16/2022 BBARRON 86867 Initial create\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const factsheetHorizontalTextScripts = {\r\n loadScripts: () => {\r\n\r\n /**\r\n * Handles a click on the expand button, changing the state of the component to expanded\r\n * @param {ClickEvent} evt \r\n */\r\n const handleExpandClick = (evt) => {\r\n evt.preventDefault();\r\n let parent = evt.currentTarget.parentNode;\r\n if(parent.classList.contains('factsheet-htext-body')) {\r\n parent.classList.remove('factsheet-htext-body--collapsed');\r\n parent.classList.add('factsheet-htext-body--expanded');\r\n }\r\n };\r\n \r\n\r\n /**\r\n * Handles a click on the collapse button, changing the state of the component to collapsed\r\n * @param {ClickEvent} evt \r\n */\r\n const handleCollapseClick = (evt) => {\r\n evt.preventDefault();\r\n let parent = evt.currentTarget.parentNode;\r\n if(parent.classList.contains('factsheet-htext-body')) {\r\n parent.classList.add('factsheet-htext-body--collapsed');\r\n parent.classList.remove('factsheet-htext-body--expanded');\r\n }\r\n };\r\n\r\n \r\n // Get all expand buttons and have them listen for click events\r\n const expandButtons = document.querySelectorAll('.factsheet-htext-controls--collapsed');\r\n expandButtons.forEach(button => {\r\n button.addEventListener('click', handleExpandClick, false);\r\n });\r\n \r\n // Get all collapse buttons and have them listen for click events\r\n const collapseButtons = document.querySelectorAll('.factsheet-htext-controls--expanded');\r\n collapseButtons.forEach(button => {\r\n button.addEventListener('click', handleCollapseClick, false);\r\n });\r\n \r\n const expandCollapseThreshold = 180;\r\n \r\n /**\r\n * Checks the text height and only shows the expand-collapse\r\n * options if height is greater than the expandCollapseThreshold.\r\n */\r\n function resetCollapsing() {\r\n const factsheetBodies = document.querySelectorAll('.factsheet-htext-body');\r\n factsheetBodies.forEach(body => {\r\n if(body.offsetHeight > expandCollapseThreshold) {\r\n body.classList.add('factsheet-htext-body--collapsed');\r\n } else {\r\n body.classList.remove('factsheet-htext-body--collapsed');\r\n body.classList.remove('factsheet-htext-body--expanded');\r\n }\r\n });\r\n }\r\n \r\n resetCollapsing();\r\n \r\n /**\r\n * Re-check whether to show/hide expand-collapse buttons on browser resize\r\n */\r\n window.addEventListener('resize', function() {\r\n this.window.requestAnimationFrame(resetCollapsing);\r\n });\r\n }\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 05/31/2022 BBARRON 86210 Initial Create\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const factsheetOverviewScripts = {\r\n loadScripts: () => {\r\n const expandedClass = \"expanded\";\r\n const headers = document.querySelectorAll('.factsheet-overview-header-mobile');\r\n\r\n function isExpanded(currentHeader) {\r\n var parent = currentHeader.parentNode;\r\n return parent.classList.contains(expandedClass);\r\n }\r\n\r\n function accordionExpand(currentHeader) {\r\n headers.forEach(header => {\r\n var parent = header.parentNode;\r\n if(header === currentHeader) {\r\n parent.classList.add(expandedClass);\r\n } else {\r\n parent.classList.remove(expandedClass);\r\n }\r\n });\r\n }\r\n\r\n function accordionCollapse(currentHeader) {\r\n headers.forEach(header => {\r\n var parent = header.parentNode;\r\n parent.classList.remove(expandedClass);\r\n });\r\n }\r\n\r\n\r\n // Activate each factsheet overview header element\r\n headers.forEach(header => {\r\n var parent = header.parentNode;\r\n header.addEventListener('click', evt => {\r\n if(isExpanded(header)) {\r\n accordionCollapse(header);\r\n } else {\r\n accordionExpand(header);\r\n }\r\n }, false);\r\n });\r\n }\r\n};\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 03/31/2022 BBARRON 82812 Initial create\r\n// 04/27/2022 BBARRON 84447 Remove unused variable\r\n// 05/11/2022 BBARRON 85238 Pie chart should correctly handle a single 100% slice\r\n// 05/26/2022 BBARRON 86062 Updated to handle grouped data (arrays of arrays)\r\n// 08/24/2022 BBARRON 90888 Fix iOS bug where transform-origin property not supported\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n/**\r\n * Creates the pie chart background circle with hatched lines\r\n * @param {number} radius \r\n * @returns \r\n */\r\nconst createChartBackground = (radius) => {\r\n const pattern = document.createElementNS(\"http://www.w3.org/2000/svg\", \"pattern\");\r\n pattern.setAttribute('id', 'diagonalHatch');\r\n pattern.setAttribute('patternUnits', 'userSpaceOnUse');\r\n pattern.setAttribute('width', '8');\r\n pattern.setAttribute('height', '8');\r\n\r\n const rect = document.createElementNS(\"http://www.w3.org/2000/svg\", \"rect\");\r\n rect.setAttribute('x', '0');\r\n rect.setAttribute('y', '0');\r\n rect.setAttribute('width', '8');\r\n rect.setAttribute('height', '8');\r\n rect.setAttribute('fill', '#F2F2F2');\r\n pattern.appendChild(rect);\r\n\r\n const path = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\r\n path.setAttribute('d', 'M-2,2 l4,-4 M0,8 l8,-8 M6,10 l4,-4');\r\n path.setAttribute('stroke', '#A0A0A0');\r\n path.setAttribute('stroke-width', '1');\r\n pattern.appendChild(path);\r\n\r\n const circle = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\");\r\n circle.setAttribute('r', `${radius}`);\r\n circle.setAttribute('cx', `${radius}`);\r\n circle.setAttribute('cy', `${radius}`);\r\n circle.setAttribute('fill', `url(#diagonalHatch)`);\r\n return {\r\n pattern: pattern,\r\n circle: circle\r\n };\r\n}\r\n\r\nconst parsePercent = (percent) => {\r\n if(typeof percent === 'number') {\r\n return percent;\r\n } else if (typeof percent === 'string') {\r\n var cleaned = percent.replace(/[^0-9\\.-]/g, '');\r\n return parseFloat(cleaned);\r\n }\r\n return NaN;\r\n}\r\n\r\n/**\r\n * Creates the full pie chart SVG element with the standard colors\r\n * @param {number[]} data The array of percentages\r\n * @returns The SVG element\r\n */\r\nconst createChart = (data) => {\r\n if(Array.isArray(data[0])) {\r\n return createGroupedChart(data);\r\n }\r\n\r\n const radius = 200;\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n const background = createChartBackground(radius);\r\n svg.setAttribute('width', '100%');\r\n svg.setAttribute('height', '100%');\r\n svg.setAttribute('class', 'gs-piechart');\r\n svg.setAttribute('viewBox', `0 0 ${2 * radius} ${2 * radius}`);\r\n svg.appendChild(background.pattern);\r\n svg.appendChild(background.circle);\r\n \r\n if(data.length === 1 && Math.round(data[0]) === 100) {\r\n let circle = createWholePie(0, radius);\r\n svg.appendChild(circle);\r\n return svg;\r\n }\r\n\r\n let rotation = 0;\r\n data.forEach((percent, index) => {\r\n percent = parsePercent(percent);\r\n if(percent <= 0 || isNaN(percent)) {\r\n return;\r\n }\r\n let slice = createSlice(percent, index, radius, rotation);\r\n rotation += percentToDegrees(percent);\r\n svg.appendChild(slice);\r\n });\r\n return svg;\r\n};\r\n\r\n/**\r\n * Creates the full pie chart SVG element with the standard colors\r\n * @param {number[][]} data The array of arrays percentages\r\n * @returns The SVG element\r\n */\r\nconst createGroupedChart = (groups) => {\r\n const radius = 200;\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n const background = createChartBackground(radius);\r\n svg.setAttribute('width', '100%');\r\n svg.setAttribute('height', '100%');\r\n svg.setAttribute('class', 'gs-piechart');\r\n svg.setAttribute('viewBox', `0 0 ${2 * radius} ${2 * radius}`);\r\n svg.appendChild(background.pattern);\r\n svg.appendChild(background.circle);\r\n\r\n \r\n if(groups.length === 1 && groups[0].length === 1 && Math.round(groups[0][0]) === 100) {\r\n let circle = createWholePie(0, radius);\r\n svg.appendChild(circle);\r\n return svg;\r\n }\r\n\r\n let rotation = 0;\r\n groups.forEach((group, index) => {\r\n group.forEach(percent => {\r\n if(percent <= 0 || isNaN(percent)) {\r\n return;\r\n }\r\n let slice = createSlice(percent, index, radius, rotation);\r\n rotation += 360 * percent / 100;\r\n svg.appendChild(slice);\r\n });\r\n });\r\n return svg;\r\n};\r\n\r\n/**\r\n * Convert degrees to radians\r\n * @param {number} deg The degrees\r\n * @returns the angle in radians\r\n */\r\nconst degToRadians = (deg) => {\r\n return deg * Math.PI / 180;\r\n}\r\n\r\n/**\r\n * Convert a percent to radians\r\n * @param {number} percent The angle as a percentage\r\n * @returns The angle in radians\r\n */\r\nconst percentToRadians = (percent) => {\r\n return percent * Math.PI / 50;\r\n}\r\n\r\n/**\r\n * Convert a percent to degrees\r\n * @param {number} percent The angle as a percent\r\n * @returns The angle in degrees\r\n */\r\nconst percentToDegrees = (percent) => {\r\n return percent * 180 / 50;\r\n}\r\n\r\n/**\r\n * Handles the math for generating a pie slice and provides arc path parameters\r\n * @param {number} radius the size of the pie chart\r\n * @param {number} percent The percent of the whole pie\r\n * @returns \r\n */\r\nconst getSliceParemeters = (radius, percent, rotation) => {\r\n // Start pie chart at the top rather than the right\r\n const offsetAngle = degToRadians(-90) + degToRadians(rotation);\r\n let arcAngle = percentToRadians(percent);\r\n let endAngle = (offsetAngle + arcAngle) % (2 * Math.PI);\r\n const largeArc = percent > 50 ? '1' : '0';\r\n const startX = radius + radius * Math.cos(offsetAngle);\r\n const startY = radius + radius * Math.sin(offsetAngle);\r\n const endX = radius + radius * Math.cos(endAngle);\r\n const endY = radius + radius * Math.sin(endAngle);\r\n return {\r\n startX: startX,\r\n startY: startY,\r\n endX: endX,\r\n endY: endY,\r\n largeArc: largeArc\r\n };\r\n};\r\n\r\n/**\r\n * Generates an SVG path element representing one pie slice\r\n * @param {*} percent The percent of the pie\r\n * @param {*} index The index/order of this pie slice among all slices\r\n * @param {*} radius The chart size\r\n * @param {*} rotation How much this slice should be rotated based on previous slices\r\n * @returns The SVG Path element (The slice)\r\n */\r\nconst createSlice = (percent, index, radius, rotation) => {\r\n let d = getSliceParemeters(radius, percent, rotation);\r\n const slice = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\r\n \r\n // Start at chart center, draw line to startX,startY, arc to endX, endY and then close the wedge\r\n slice.setAttribute('d', `M${radius} ${radius} L${d.startX} ${d.startY} A${radius} ${radius} 0 ${d.largeArc} 1 ${d.endX} ${d.endY} z`);\r\n slice.setAttribute('class', `gs-piechart-slice-${index + 1}`);\r\n \r\n return slice;\r\n}\r\n\r\n/**\r\n * When there's just a single slice with a value of ~100%, just create a circle instead of a pie wedge\r\n * @param {*} index Determines the pie chart color\r\n * @param {*} radius The pie chart radius\r\n * @returns The SVG circle element\r\n */\r\nconst createWholePie = (index, radius) => {\r\n const circle = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\");\r\n circle.setAttribute('r', `${radius}`);\r\n circle.setAttribute('cx', `${radius}`);\r\n circle.setAttribute('cy', `${radius}`);\r\n circle.setAttribute('class', `gs-piechart-slice-${index + 1}`);\r\n return circle;\r\n}\r\n\r\nconst parseChartData = dataStr => {\r\n if(!dataStr || dataStr === '') {\r\n return null;\r\n }\r\n\r\n // Handles legacy parsing when data string is not in json format\r\n if(dataStr.indexOf('[') !== 0) {\r\n return dataStr.split(',').map(d => parsePercent(d));\r\n }\r\n\r\n // Handles json parsing of data string\r\n try {\r\n return JSON.parse(dataStr).map(d => {\r\n if(Array.isArray(d)) {\r\n return d.map(i => parsePercent(i));\r\n }\r\n return parsePercent(d);\r\n });\r\n } catch (err) {\r\n console.log(\"Could not parse chart data: \", err);\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * Create a pie chart inside every element with the data-piechart-data attribute.\r\n * Warning: Clears the element contents, so use a container element specifically for your charts\r\n */\r\nexport const factsheetPieChartScripts = {\r\n loadScripts: () => {\r\n let containers = document.querySelectorAll('*[data-piechart-data]');\r\n\r\n containers.forEach(container => {\r\n let dataStr = container.dataset.piechartData;\r\n let data = parseChartData(dataStr);\r\n if(!data || data.length === 0) {\r\n return;\r\n }\r\n\r\n let chart = createChart(data);\r\n container.innerHTML = '';\r\n container.appendChild(chart);\r\n });\r\n }\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 06/01/2022 BBARRON 86205 Initial create\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const factsheetSectionScripts = {\r\n loadScripts: () => {\r\n let headers = document.querySelectorAll('.gs-factsheet-section-heading');\r\n headers.forEach(header => {\r\n let parent = header.parentNode.parentNode;\r\n header.addEventListener('click', evt => {\r\n evt.preventDefault();\r\n parent.classList.toggle('expanded');\r\n });\r\n });\r\n }\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 03/29/2022 BBARRON 82643 Initial create\r\n// 03/31/2022 BBARRON 82812 changed module name to lowercase to match other modules\r\n// 05/26/2022 BBARRON 86063 Fix footer collapsing. Only show controls if footnotes are too tall\r\n// 08/04/2022 GDEME 89643 Fund Details Pages (all) - expand/collapse functionality\r\n// 08/07/2022 BBARRON 89643 Overhaul expanding/collapsing footnotes. Default to expanded, disable collapsing if too short\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const factsheetVerticalTableScripts = {\r\n loadScripts: () => {\r\n\r\n const defaultToCollapsed = false;\r\n const expandCollapseThreshold = 180;\r\n\r\n const handleExpandClick = (evt) => {\r\n evt.preventDefault();\r\n let parent = evt.currentTarget.parentNode;\r\n if(parent.classList.contains('factsheet-vtable-footer')) {\r\n parent.classList.remove('factsheet-vtable-footer--collapsed');\r\n parent.classList.add('factsheet-vtable-footer--expanded');\r\n }\r\n };\r\n\r\n const handleCollapseClick = (evt) => {\r\n evt.preventDefault();\r\n let parent = evt.currentTarget.parentNode;\r\n if(parent.classList.contains('factsheet-vtable-footer')) {\r\n parent.classList.add('factsheet-vtable-footer--collapsed');\r\n parent.classList.remove('factsheet-vtable-footer--expanded');\r\n }\r\n };\r\n \r\n const expandButtons = document.querySelectorAll('.factsheet-vtable-footer-controls--collapsed');\r\n expandButtons.forEach(button => {\r\n button.addEventListener('click', handleExpandClick, false);\r\n });\r\n\r\n const collapseButtons = document.querySelectorAll('.factsheet-vtable-footer-controls--expanded');\r\n collapseButtons.forEach(button => {\r\n button.addEventListener('click', handleCollapseClick, false);\r\n });\r\n\r\n \r\n // Only show expand/collapse controls if footer is high enough to justify this.\r\n // If present, remove these buttons if the footnotes are too short.\r\n function resetFooters() {\r\n const tableFooters = document.querySelectorAll('.factsheet-vtable-footer');\r\n tableFooters.forEach(footer => {\r\n var footnotes = footer.querySelector('.factsheet-vtable-footnotes');\r\n if(footnotes.offsetHeight > expandCollapseThreshold) {\r\n if(defaultToCollapsed){\r\n footer.classList.add('factsheet-vtable-footer--collapsed');\r\n }else{\r\n footer.classList.add('factsheet-vtable-footer--expanded');\r\n } \r\n } else {\r\n footer.classList.remove('factsheet-vtable-footer--collapsed');\r\n footer.classList.remove('factsheet-vtable-footer--expanded');\r\n }\r\n });\r\n }\r\n\r\n resetFooters();\r\n\r\n window.addEventListener('resize', function() {\r\n this.window.requestAnimationFrame(resetFooters);\r\n });\r\n }\r\n};\r\n ","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 11/02/2020 JJacob 49830 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const FAQScripts = {\r\n loadScripts: () => {\r\n const handleClick = id => {\r\n const active = document.querySelector('.gs-faq-card.--active');\r\n let activeId;\r\n if (active) {\r\n activeId = active.id;\r\n active.classList.remove('--active');\r\n }\r\n if (activeId !== id) {\r\n const selected = document.querySelector('#' + id);\r\n selected.classList.add('--active');\r\n }\r\n };\r\n\r\n const elems = document.querySelectorAll('.gs-faq-card');\r\n elems.forEach(element => {\r\n element.addEventListener('click', () => handleClick(element.id));\r\n });\r\n const stopLink = document.querySelectorAll('.gs-faq-card a');\r\n stopLink.forEach(element => {\r\n element.addEventListener('click', e => {\r\n e.stopPropagation();\r\n });\r\n });\r\n }\r\n};\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 10/16/2023 GCASEY 110128 Initial Create\r\n// 10/31/2023 GCASEY 117782 Fix console errors\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n\r\nexport const formBannerScripts = () => {\r\n const form = document.getElementsByClassName(\"gs-formbanner-form\")[0];\r\n const formBanner = document.getElementsByClassName(\"gs-formbanner\")[0];\r\n const backgroundImage = document.getElementsByClassName(\"gs-formbanner-image\")[0];\r\n const backgroundGraphic = document.getElementsByClassName(\"gs-formbanner-graphic\")[0];\r\n\r\n if(!formBanner) {\r\n return;\r\n }\r\n\r\n // pixel offsets for the background images\r\n const imageHorizontalOffset = 50;\r\n const imageVerticalOffset = 0;\r\n const graphicHorizontalOffset = 50;\r\n const graphicVerticalOffset = 0;\r\n\r\n const initialFormHeight = form?.getBoundingClientRect().height;\r\n\r\n // tablet breakpoint\r\n const widthBreakpoint = 768;\r\n\r\n // sets position of the background image and background graphic \r\n const setBackgroundPosition = (verticalPos) => {\r\n backgroundImage.style.backgroundPosition = `${imageHorizontalOffset}px ${verticalPos + imageVerticalOffset}px`;\r\n backgroundGraphic.style.backgroundPosition = `${graphicHorizontalOffset}px ${verticalPos + graphicVerticalOffset}px`;\r\n };\r\n\r\n // manually sets image positions to emulate scrolling with fixed backgrounds\r\n const scrollImages = () => {\r\n if(window.innerWidth < widthBreakpoint) \r\n return;\r\n\r\n const formHeight = form.getBoundingClientRect().height;\r\n const formHeightChange = formHeight - initialFormHeight;\r\n\r\n // distance of form from top of page\r\n const offset = formBanner.getBoundingClientRect().top;\r\n\r\n if (offset < - formHeightChange) {\r\n setBackgroundPosition(offset + formHeightChange);\r\n } else if (offset < 0) {\r\n setBackgroundPosition(0);\r\n } else {\r\n setBackgroundPosition(offset);\r\n }\r\n\r\n }\r\n\r\n window.addEventListener(\"scroll\", scrollImages);\r\n // recalculate image positions when the form expands/detracts\r\n new ResizeObserver(scrollImages).observe(formBanner);\r\n}\r\n\r\n\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 07/01/2024 GCASEY 133318 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n\r\nexport const formSelectScripts = () => {\r\n const query = \"select.gs-form-input, select.gs-form-cta-input\";\r\n const selectFields = document.querySelectorAll(query);\r\n\r\n const onSelectChange = (e) => {\r\n e.target.classList.add(\"--selected\");\r\n }\r\n\r\n selectFields.forEach((select) => {\r\n select.addEventListener(\"change\", onSelectChange)\r\n })\r\n}","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 04/05/2022 BBARRON 83017 Initial create\r\n// 08/16/2022 BBARRON 90362 Fix timestamp parsing. Timestamps were being interpreted as local dates\r\n// rather than UTC dates, throwing off inception dates by one day.\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n/**\r\n * Filter function that ensures all elements are distinct (no duplicates)\r\n * @param {*} value The value to check\r\n * @param {*} index The value's index\r\n * @param {*} self The full list of values\r\n * @returns \r\n */\r\n export const distinct = (value, index, self) => {\r\n return self.indexOf(value) === index;\r\n};\r\n\r\nexport const formatNumber = (number) => {\r\n if (!number && number != \"0\") {\r\n return \"N/A\";\r\n }\r\n\r\n return number.toFixed(2) + \"%\";\r\n};\r\n\r\nexport const formatAssetValue = (number) => {\r\n if (!number) {\r\n return \"N/A\";\r\n }\r\n\r\n return number.toFixed(2);\r\n};\r\n\r\n/**\r\n * Timestamps are interpreted as local time by default.\r\n * This assumes the timestamp is for a UTC date instead which is what comes from the fund performance API\r\n * @param {number} milliseconds The UTC timestamp\r\n */\r\nexport const parseUtcTimestamp = (milliseconds) => {\r\n // Incorrectly parse the timestamp as if it was local time to get a rough estimate of the date/time.\r\n let localTime = new Date(milliseconds);\r\n // Timezone offset changes throughout the year. Get the specific timezeone offset at the approximate time of the timestamp\r\n let utcOffset = localTime.getTimezoneOffset() * 60000;\r\n // Add the time zone offset to convert it to UTC\r\n return new Date(milliseconds + utcOffset);\r\n}\r\n\r\nexport const formatTimestamp = (date) => {\r\n let pattern = new RegExp(/Date\\((\\d+)\\)/);\r\n let matches = pattern.exec(date);\r\n if (!matches || matches.length < 1) {\r\n return \"\";\r\n }\r\n\r\n let milliseconds = parseInt(matches[1]);\r\n let parsedDate = parseUtcTimestamp(milliseconds);\r\n return formatDate(parsedDate);\r\n}\r\n\r\nexport const formatDate = (date) => {\r\n let parsedDate = new Date(date);\r\n let dd = String(parsedDate.getDate()).padStart(2, '0');\r\n let mm = String(parsedDate.getMonth() + 1).padStart(2, '0'); //January is 0!\r\n let yyyy = parsedDate.getFullYear();\r\n return mm + '/' + dd + '/' + yyyy;\r\n};\r\n\r\nexport const formatMorningstar = (number, siblingNumber) => {\r\n if (!number || !siblingNumber) {\r\n return \"N/A\";\r\n }\r\n\r\n return number;\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 04/05/2022 BBARRON 83017 Initial create\r\n// 04/12/2022 BBARRON 83345 Added footnotes and moved as of date out of tables\r\n// 04/13/2022 BBARRON 83018 Added factsheet domain. Can change location of fact sheet links with config variable\r\n// 05/11/2022 BBARRON 85240 Removed factsheet domain. No longer need to redirect fund urls to other domains.\r\n// 07/12/2022 BBARRON 88923 Make fund links bold\r\n// 07/19/2022 BBARRON 88352 For every as of date and every fund category, add anchor ids\r\n// 08/01/2022 BBARRON 89485 Change anchor ids for each fund category to fundcategory-CategoryCD-ActiveTab\r\n// 08/16/2022 BBARRON 90398 Fix three month performance column. Was populating with OneMonth data\r\n// 08/18/2022 BBARRON 90176 Remove duplicate footnote symbols and sort numerically\r\n// 10/13/2022 BBARRON 93634 Overhaul funds listing table for horizontal and vertical scroll on mobile\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { formatAssetValue, formatNumber, formatMorningstar, formatDate, formatTimestamp } from './formatting.js'\r\n\r\n/////////////////////////////////////////\r\n// Daily Performance\r\n/////////////////////////////////////////\r\n\r\nexport const renderDailyPerformanceTable = (data) => {\r\n if(!data) {\r\n return;\r\n }\r\n let headingRow = renderDailyTableHeadingRow();\r\n let bodyRows = [];\r\n data.Categories.forEach(category => {\r\n let newRows = renderDailyFundCategory(category, data);\r\n newRows.forEach(r => bodyRows.push(r)); \r\n });\r\n \r\n let thead = create('thead', {children: [headingRow]});\r\n let tbody = create('tbody', {children: [...bodyRows]});\r\n\r\n return create('table', {\r\n classes: [],\r\n attributes: {'data-type': 'daily'},\r\n children: [thead, tbody]\r\n });\r\n}\r\n\r\nfunction renderDailyTableHeadingRow() {\r\n let html = `\r\n Net
Asset
Value\r\n Month To
Date\r\n Year To
Date\r\n One
Year\r\n Three
Year
(Annualized)\r\n Five
Year
(Annualized)\r\n Ten
Year
(Annualized)\r\n Since
Inception\r\n Inception
Date\r\n Gross
Expense
Ratio\r\n Net
Expense
Ratio`;\r\n return create('tr', {\r\n classes: [],\r\n html: html\r\n });\r\n}\r\n\r\nfunction renderDailyFundCategory(category, data) {\r\n let headerRow = renderDailyCategoryHeader(category.Description, category.CategoryCD);\r\n let fundRows = [];\r\n category.Funds.forEach((fund, i) => {\r\n let newRows = renderDailyFundRow(fund, getFundFootnoteSymbols(fund, data));\r\n newRows.forEach(r => fundRows.push(r));\r\n });\r\n return [headerRow, ...fundRows];\r\n}\r\n\r\nfunction renderDailyCategoryHeader(categoryName, categoryCode) {\r\n\r\n let nameCol = create('th', {\r\n content: categoryName\r\n });\r\n\r\n let otherCol = create('td', {\r\n attributes: { 'colspan': '11' },\r\n });\r\n\r\n let cells = [nameCol, otherCol];\r\n\r\n \r\n\r\n return create('tr', {\r\n classes: ['category'],\r\n attributes: {\r\n 'id': `fundcategory-${categoryCode.toLowerCase()}-daily`\r\n },\r\n children: cells\r\n });\r\n}\r\n\r\nfunction renderDailyFundRow(fund, footnoteSymbols) {\r\n const performanceData = fund.DailyPerformance;\r\n let fundName = renderFundNameCell(fund, footnoteSymbols, hasYieldRow(fund));\r\n let classes = ['switchableCol', 'dailyCol'];\r\n let values = [\r\n formatAssetValue(performanceData.SharePrice),\r\n formatNumber(performanceData.MonthToDateReturn),\r\n formatNumber(performanceData.YearToDateReturn),\r\n formatNumber(performanceData.OneYearReturn),\r\n formatNumber(performanceData.ThreeYearReturnAnnualized),\r\n formatNumber(performanceData.FiveYearReturnAnnualized),\r\n formatNumber(performanceData.TenYearReturnAnnualized),\r\n formatNumber(performanceData.SinceInceptionReturnAnnualized),\r\n formatTimestamp(fund.InceptionDate),\r\n formatNumber(fund.GrossExpenseRatio),\r\n formatNumber(fund.NetExpenseRatio),\r\n ];\r\n\r\n \r\n let valueCells = values.map((v, i) => {\r\n let cellClasses = classes;\r\n \r\n if(i === values.length - 2) {\r\n cellClasses = ['grossExpenseRatioCol', ...classes]\r\n }\r\n if(i === values.length - 1) {\r\n cellClasses = ['netExpenseRatioCol', ...classes]\r\n }\r\n \r\n return create('td', {\r\n classes: cellClasses,\r\n content: v\r\n });\r\n });\r\n\r\n let row = create('tr', {\r\n classes: ['fundInfo'],\r\n children: [fundName, ...valueCells]\r\n });\r\n\r\n if(hasYieldRow(fund)) {\r\n let yieldRow = renderYieldRow(performanceData.SevenDayAverageYield, performanceData.SevenDayGrossYield, performanceData.TradeDate, ['switchableCol','dailyCol'], 12);\r\n return [row, yieldRow]\r\n }\r\n\r\n return [row];\r\n}\r\n\r\n\r\n/////////////////////////////////////////\r\n// Monthly Performance\r\n/////////////////////////////////////////\r\n\r\nexport const renderMonthlyPerformanceTable = (data) => {\r\n //table body: Gray heading row is at top of table body\r\n let headingRow = renderMonthlyTableHeadingRow();\r\n let bodyRows = [];\r\n data.Categories.forEach(category => {\r\n let newRows = renderMonthlyFundCategory(category, data);\r\n newRows.forEach(r => bodyRows.push(r)); \r\n });\r\n\r\n let thead = create('thead', {children: [headingRow]});\r\n let tbody = create('tbody', {children: [...bodyRows]});\r\n\r\n return create('table', {\r\n attributes: {'data-type': 'monthly'},\r\n children: [thead, tbody]\r\n });\r\n}\r\n\r\nfunction renderMonthlyTableHeadingRow() {\r\n\r\n let html = `\r\n Month To
Date\r\n Year To
Date\r\n One
Year\r\n Three
Year
(Annualized)\r\n Five
Year
(Annualized)\r\n Ten
Year
(Annualized)\r\n Since
Inception\r\n Inception
Date\r\n Gross
Expense
Ratio\r\n Net
Expense
Ratio`;\r\n\r\n return create('tr', {\r\n html: html\r\n });\r\n}\r\n\r\nfunction renderMonthlyFundCategory(category, data) {\r\n let headerRow = renderMonthlyCategoryHeader(category.Description, category.CategoryCD);\r\n let fundRows = [];\r\n category.Funds.forEach((fund, i) => {\r\n let newRows = renderMonthlyFundRow(fund, getFundFootnoteSymbols(fund, data));\r\n newRows.forEach(r => fundRows.push(r));\r\n });\r\n return [headerRow, ...fundRows];\r\n}\r\n\r\nfunction renderMonthlyCategoryHeader(categoryName, categoryCode) {\r\n let nameCol = create('th', {\r\n content: categoryName\r\n });\r\n\r\n let otherCol = create('td', {\r\n attributes: { 'colspan': '10' },\r\n });\r\n\r\n return create('tr', {\r\n classes: ['category'],\r\n attributes: {\r\n 'id': `fundcategory-${categoryCode.toLowerCase()}-monthly`\r\n },\r\n children: [nameCol, otherCol]\r\n });\r\n}\r\n\r\nfunction renderMonthlyFundRow(fund, footnoteSymbols) {\r\n const performanceData = fund.MonthlyPerformance;\r\n let fundName = renderFundNameCell(fund, footnoteSymbols, hasYieldRow(fund));\r\n let classes = ['switchableCol', 'monthlyCol'];\r\n let values = [\r\n formatNumber(performanceData.PreTaxOneMonth),\r\n formatNumber(performanceData.PreTaxYearToDate),\r\n formatNumber(performanceData.PreTaxOneYear),\r\n formatNumber(performanceData.PreTaxThreeYearAnnualized),\r\n formatNumber(performanceData.PreTaxFiveYearAnnualized),\r\n formatNumber(performanceData.PreTaxTenYearAnnualized),\r\n formatNumber(performanceData.PreTaxInceptionAnnualized),\r\n formatTimestamp(fund.InceptionDate),\r\n formatNumber(fund.GrossExpenseRatio),\r\n formatNumber(fund.NetExpenseRatio),\r\n ];\r\n\r\n let valueCells = values.map((v, i) => {\r\n let cellClasses = classes;\r\n if(i === values.length - 2) {\r\n cellClasses = ['grossExpenseRatioCol', ...classes]\r\n }\r\n if(i === values.length - 1) {\r\n cellClasses = ['netExpenseRatioCol', ...classes]\r\n }\r\n return create('td', {\r\n classes: cellClasses,\r\n content: v\r\n });\r\n });\r\n\r\n let row = create('tr', {\r\n classes: ['fundInfo'],\r\n children: [fundName, ...valueCells]\r\n });\r\n\r\n if(hasYieldRow(fund)) {\r\n let yieldRow = renderYieldRow(performanceData.SevenDayAverageYield, performanceData.SevenDayGrossYield, performanceData.AsOfDate, ['switchableCol','monthlyCol'], 11);\r\n return [row, yieldRow]\r\n }\r\n\r\n return [row];\r\n}\r\n\r\n\r\n/////////////////////////////////////////\r\n// Quarterly Performance\r\n/////////////////////////////////////////\r\n\r\nexport const renderQuarterlyPerformanceTable = (data) => {\r\n let headingRow = renderQuarterlyTableHeadingRow();\r\n let bodyRows = [];\r\n data.Categories.forEach(category => {\r\n let newRows = renderQuarterlyFundCategory(category, data);\r\n newRows.forEach(r => bodyRows.push(r)); \r\n });\r\n\r\n let thead = create('thead', {children: [headingRow]});\r\n let tbody = create('tbody', {children: [...bodyRows]});\r\n\r\n return create('table', {\r\n attributes: {'data-type': 'quarterly'},\r\n children: [thead, tbody]\r\n });\r\n}\r\n\r\nfunction renderQuarterlyTableHeadingRow() {\r\n\r\n let html = `\r\n Three
Month\r\n Year To
Date\r\n One
Year\r\n Three
Year
(Annualized)\r\n Five
Year
(Annualized)\r\n Ten
Year
(Annualized)\r\n Since
Inception\r\n Inception
Date\r\n Gross
Expense
Ratio\r\n Net
Expense
Ratio`;\r\n\r\n return create('tr', {\r\n html: html\r\n });\r\n}\r\n\r\nfunction renderQuarterlyFundCategory(category, data) {\r\n let headerRow = renderQuarterlyCategoryHeader(category.Description, category.CategoryCD);\r\n let fundRows = [];\r\n category.Funds.forEach((fund, i) => {\r\n let newRows = renderQuarterlyFundRow(fund, getFundFootnoteSymbols(fund, data));\r\n newRows.forEach(r => fundRows.push(r));\r\n });\r\n return [headerRow, ...fundRows];\r\n}\r\n\r\nfunction renderQuarterlyCategoryHeader(categoryName, categoryCode) {\r\n let nameCol = create('th', {\r\n content: categoryName\r\n });\r\n\r\n let otherCol = create('td', {\r\n attributes: { 'colspan': '10' },\r\n });\r\n\r\n return create('tr', {\r\n classes: ['category'],\r\n attributes: {\r\n 'id': `fundcategory-${categoryCode.toLowerCase()}-quarterly`\r\n },\r\n children: [nameCol, otherCol]\r\n });\r\n}\r\n\r\nfunction renderQuarterlyFundRow(fund, footnoteSymbols) {\r\n const performanceData = fund.QuarterlyPerformance;\r\n let fundName = renderFundNameCell(fund, footnoteSymbols, hasYieldRow(fund));\r\n let classes = ['switchableCol', 'quarterlyCol'];\r\n let values = [\r\n formatNumber(performanceData.PreTaxThreeMonth),\r\n formatNumber(performanceData.PreTaxYearToDate),\r\n formatNumber(performanceData.PreTaxOneYear),\r\n formatNumber(performanceData.PreTaxThreeYearAnnualized),\r\n formatNumber(performanceData.PreTaxFiveYearAnnualized),\r\n formatNumber(performanceData.PreTaxTenYearAnnualized),\r\n formatNumber(performanceData.PreTaxInceptionAnnualized),\r\n formatTimestamp(fund.InceptionDate),\r\n formatNumber(fund.GrossExpenseRatio),\r\n formatNumber(fund.NetExpenseRatio),\r\n ];\r\n\r\n let valueCells = values.map((v, i) => {\r\n let cellClasses = classes;\r\n if(i === values.length - 2) {\r\n cellClasses = ['grossExpenseRatioCol', ...classes]\r\n }\r\n if(i === values.length - 1) {\r\n cellClasses = ['netExpenseRatioCol', ...classes]\r\n }\r\n return create('td', {\r\n classes: cellClasses,\r\n content: v\r\n });\r\n });\r\n\r\n let row = create('tr', {\r\n classes: ['fundInfo'],\r\n children: [fundName, ...valueCells]\r\n });\r\n\r\n if(hasYieldRow(fund)) {\r\n let yieldRow = renderYieldRow(performanceData.SevenDayAverageYield, performanceData.SevenDayGrossYield, performanceData.AsOfDate, ['switchableCol','quarterlyCol'], 11);\r\n return [row, yieldRow]\r\n }\r\n\r\n return [row];\r\n}\r\n\r\n\r\n/////////////////////////////////////////\r\n// Morningstar Performance\r\n/////////////////////////////////////////\r\n\r\n\r\nexport const renderMorningstarPerformanceTable = (data) => {\r\n let headingRow = renderMorningstarTableHeadingRow();\r\n let bodyRows = [];\r\n data.Categories.forEach(category => {\r\n let newRows = renderMorningstarFundCategory(category, data);\r\n newRows.forEach(r => bodyRows.push(r)); \r\n });\r\n\r\n \r\n let thead = create('thead', {children: [headingRow]});\r\n let tbody = create('tbody', {children: [...bodyRows]});\r\n\r\n return create('table', {\r\n attributes: {'data-type': 'morningstar'},\r\n children: [thead, tbody]\r\n });\r\n}\r\n\r\nfunction renderMorningstarTableHeadingRow() {\r\n\r\n let html = `\r\n Category\r\n Overall Rating\r\n 3 Year Rating\r\n 5 Year Rating\r\n 10 Year Rating`;\r\n\r\n return create('tr', {\r\n html: html\r\n });\r\n}\r\n\r\nfunction renderMorningstarFundCategory(category, data) {\r\n let headerRow = renderMorningstarCategoryHeader(category.Description, category.CategoryCD);\r\n let fundRows = [];\r\n category.Funds.forEach((fund, i) => {\r\n let newRows = renderMorningstarFundRow(fund, getFundFootnoteSymbols(fund, data));\r\n newRows.forEach(r => fundRows.push(r));\r\n });\r\n return [headerRow, ...fundRows];\r\n}\r\n\r\nfunction renderMorningstarCategoryHeader(categoryName, categoryCode) {\r\n let nameCol = create('th', {\r\n content: categoryName\r\n });\r\n\r\n let otherCol = create('td', {\r\n attributes: { 'colspan': '5' },\r\n });\r\n\r\n return create('tr', {\r\n classes: ['category'],\r\n attributes: {\r\n 'id': `fundcategory-${categoryCode.toLowerCase()}-morningstar`\r\n },\r\n children: [nameCol, otherCol]\r\n });\r\n}\r\n\r\nfunction renderMorningstarFundRow(fund, footnoteSymbols) {\r\n const performanceData = fund.MorningstarRating;\r\n let fundName = renderFundNameCell(fund, footnoteSymbols, false);\r\n let valueCells = [\r\n create('td', { \r\n content: performanceData.MorningstarCategoryDescription\r\n }),\r\n drawStars(performanceData.MorningstarOverallRating, performanceData.MorningstarOverallFunds),\r\n drawStars(performanceData.MorningstarThreeYearRating, performanceData.MorningstarThreeYearFunds),\r\n drawStars(performanceData.MorningstarFiveYearRating, performanceData.MorningstarFiveYearFunds),\r\n drawStars(performanceData.MorningstarTenYearRating, performanceData.MorningstarTenYearFunds),\r\n ];\r\n\r\n \r\n\r\n let row = create('tr', {\r\n children: [fundName, ...valueCells]\r\n });\r\n\r\n return [row];\r\n}\r\n\r\nconst drawStars = function(numStars, numFunds) {\r\n\r\n const rating = formatMorningstar(numStars, numFunds);\r\n if(rating === 'N/A') {\r\n return create('td', {\r\n classes: ['switchableCol','morningstarCol'],\r\n content: rating\r\n });\r\n }\r\n \r\n const star = ``;\r\n let stars = [];\r\n for(let i = 0; i < numStars; i += 1) {\r\n stars.push(star);\r\n }\r\n let html = stars.join('');\r\n let starsContainer = create('div', {\r\n classes: ['stars'],\r\n html: html\r\n });\r\n let text = document.createTextNode(` of ${numFunds}`);\r\n return create('td', {\r\n classes: ['switchableCol','morningstarCol','ratingCol'],\r\n children: [starsContainer, text]\r\n });\r\n}\r\n\r\n/////////////////////////////////////////\r\n// Utility\r\n/////////////////////////////////////////\r\n\r\nexport const renderAsOfDate = function (asOfDate, container, isMorningstar) {\r\n container.innerHTML = '';\r\n let content;\r\n if(!isMorningstar) {\r\n content = create('div', {\r\n classes: ['funds-listing-asof-date'],\r\n content: `As of Date: ${formatDate(asOfDate)}`\r\n });\r\n } else {\r\n let row1 = create('div', {\r\n content: `Morningstar Ratings (number of funds in category). As of Date: ${formatDate(asOfDate)}`\r\n });\r\n \r\n let row2 = create('div', {\r\n content: 'Based on Risk Adjusted Return'\r\n });\r\n \r\n content = create('div', {\r\n classes: ['funds-listing-asof-date'], \r\n children: [row1, row2]\r\n });\r\n }\r\n \r\n container.appendChild(content);\r\n}\r\n\r\n/**\r\n * A compareFn for Array.prototype.sort that compares the integer value of the two numbers\r\n * @param {*} a The first number to compare. Either a number or a string representation of a number\r\n * @param {*} b The second number to compare. Either a number or a string representation of a number\r\n * @returns negative number if b > a, positive number if a > b\r\n */\r\nfunction integerSortFunction (a, b) {\r\n let first = typeof a === 'string' ? parseInt(a, 10): a;\r\n var second = typeof b === 'string' ? parseInt(b, 10): b;\r\n return first - second;\r\n}\r\n\r\nfunction getFundFootnoteSymbols(fund, data) {\r\n const ticker = fund.TickerSymbol;\r\n const footnoteSymbols = data.FundNotesMap[ticker];\r\n if(footnoteSymbols) {\r\n // remove duplicates\r\n let uniqueSymbols = [...new Set(footnoteSymbols)];\r\n // sort numerically\r\n let sortedUnique = uniqueSymbols.sort(integerSortFunction);\r\n return sortedUnique.join(',');\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Renders the first cell of a fund row with the fund name, link, and footnotes\r\n * @param {*} fund The fund data\r\n * @param {string[]} footnoteSymbols The list of footnote numbers/supercripts\r\n * @returns The first cell in the row\r\n */\r\nfunction renderFundNameCell(fund, footnoteSymbols, hasAdditionalRow) {\r\n let link = create('a', {\r\n classes: ['gs-link','gs-link--primary','gs-link--small','gs-link--green', 'gs-link--bold'],\r\n attributes: {\r\n href: fund.FundInfoLink,\r\n },\r\n html: `${fund.Description}`\r\n });\r\n\r\n let cellAttributes = {};\r\n if(hasAdditionalRow) {\r\n cellAttributes = { 'rowspan': \"2\" };\r\n }\r\n\r\n let children = [link];\r\n if(footnoteSymbols) {\r\n let footnotes = create('sup', {content: footnoteSymbols});\r\n children = [link, footnotes];\r\n }\r\n \r\n return create('th', {\r\n classes: ['fundInfoCol','fundNameCol'],\r\n attributes: cellAttributes,\r\n children: children\r\n });\r\n}\r\n\r\nfunction create(type, {classes, attributes, content, children, html}) {\r\n var element = document.createElement(type);\r\n \r\n if(classes) {\r\n classes.forEach(c => element.classList.add(c));\r\n }\r\n\r\n if(attributes) {\r\n for(let property in attributes) {\r\n element.setAttribute(`${property}`, `${attributes[property]}`);\r\n }\r\n }\r\n\r\n if(content) {\r\n element.textContent = content;\r\n }\r\n\r\n if(children) {\r\n children.forEach(c => {\r\n element.appendChild(c);\r\n });\r\n }\r\n\r\n if(html) {\r\n element.innerHTML = html;\r\n }\r\n\r\n return element;\r\n};\r\n\r\nfunction hasYieldRow(fund) {\r\n return fund.Description.toLowerCase().includes(\"money market\");\r\n}\r\n\r\nfunction renderYieldRow(average, gross, asOfDate, classes, columns) {\r\n let yieldMessage = `7-day current annualized yield (net) = ${formatNumber(average)}, 7-day current annualized yield (gross) = ${formatNumber(gross)}, as of ${formatTimestamp(asOfDate)}`;\r\n let yieldCol = create('td', {\r\n classes: classes,\r\n attributes: {'colspan': columns - 1},\r\n content: yieldMessage\r\n });\r\n return create('tr', {\r\n classes: ['fundYieldInfo'],\r\n children: [yieldCol]\r\n });\r\n}\r\n\r\nexport const renderFootnotes = (data, container) => {\r\n container.innerHtML = '';\r\n let children = [];\r\n const footnotes = data.Footnotes.map((footnote, index) => { \r\n // get all data together\r\n return {\r\n text: footnote, \r\n number: index + 1, \r\n className: !!data.FootnotesCssClass[index] ? [data.FootnotesCssClass[index]] : null\r\n };\r\n }).forEach(footnote => {\r\n // convert to elements\r\n children.push(create('br', {}));\r\n children.push(create('sup', { content: footnote.number })); \r\n children.push(create('span', { classes: footnote.className, content: footnote.text }));\r\n children.push(create('br', {}));\r\n });\r\n\r\n // append to container element\r\n children.forEach(c => container.appendChild(c));\r\n}","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 10/11/2022 BBARRON 93634 Initial create\r\n// 01/11/2023 BBARRON 89895 Fix scroll position bug when clicking browser back button\r\n// 08/02/2023 BBARRON 110687 Removed unused references and variables, updated scroll-util reference\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport {\r\n renderDailyPerformanceTable,\r\n renderMonthlyPerformanceTable,\r\n renderQuarterlyPerformanceTable,\r\n renderMorningstarPerformanceTable,\r\n renderFootnotes\r\n } from './rendering.js';\r\n\r\nimport { getFragmentFromUrl } from '../utils/scroll-utils.js';\r\n\r\nexport const fundsListingScripts = {\r\n loadScripts: (mockData, shareClass, simulatedAnchorId) => {\r\n const containerSelector = '.fund-performance .table-container';\r\n const footnotesContainerSelector = '.footnote-container';\r\n const buttonsSelector = '.asof-date-selector .gs-button-toggle-group';\r\n const fundsListingContainer = document.querySelector(containerSelector);\r\n const fundsListingFootnotesContainer = document.querySelector(footnotesContainerSelector);\r\n const buttonsContainer = document.querySelector(buttonsSelector);\r\n let asOfDates = { daily: null, monthly: null, quarterly: null, morningstar: null };\r\n\r\n // Check for container\r\n if (!fundsListingContainer) {\r\n return;\r\n }\r\n\r\n getButtonToggleGroupComponent()\r\n .then(initialize)\r\n .catch((err) => {\r\n console.error(\"Error rendering fund performance tables\", err);\r\n });\r\n\r\n async function initialize(toggleComponent) {\r\n // Wire up the as of date buttons\r\n var currentTab = toggleComponent.getSelectedValue();\r\n toggleComponent.container.addEventListener('gs.tabchange', (evt) => { \r\n switchTable(evt.detail.selectedValue, simulatedAnchorId); \r\n }, false);\r\n\r\n // Make sure share class links reflect the desired anchor\r\n window.addEventListener('hashchange', () => {\r\n addAnchorToShareClassLinks();\r\n jumpToFundCategoryAnchor(currentTab, simulatedAnchorId);\r\n }, false);\r\n\r\n // Reset browser scroll position to top of page until data is loaded.\r\n // Helpful in the event that the user has previously scrolled down the page, navigated away, and then presses the browser back button.\r\n if(window.history && 'scrollRestoration' in window.history) {\r\n window.history.scrollRestoration = 'manual';\r\n }\r\n window.scrollTo({top: 0, left: 0});\r\n\r\n // Load the data\r\n if (!shareClass) {\r\n shareClass = getShareClassFromQueryString();\r\n }\r\n let shareClassCode = shareClassToShareClassCD(shareClass);\r\n var data = await loadData(shareClassCode);\r\n console.log(data);\r\n addAnchorToShareClassLinks();\r\n renderTables(currentTab, data);\r\n \r\n }\r\n\r\n function destroyFundTables() {\r\n let tables = fundsListingContainer.getElementsByTagName('table');\r\n for(let index = tables.length - 1; index >= 0; index -= 1) {\r\n tables[index].parentNode.removeChild(tables[index]);\r\n }\r\n }\r\n\r\n function renderTables(currentTab, data) {\r\n let daily = renderDailyPerformanceTable(data);\r\n let monthly = renderMonthlyPerformanceTable(data);\r\n let quarterly = renderQuarterlyPerformanceTable(data);\r\n let morningstar = renderMorningstarPerformanceTable(data);\r\n\r\n window.dateDaily = data.DateDaily;\r\n window.dateMonthly = data.DateMonthly;\r\n window.dateQuarterly = data.DateQuarterly;\r\n window.dateMorningStar = data.DateMorningStar;\r\n\r\n asOfDates = {\r\n daily: data.DateDaily,\r\n monthly: data.DateMonthly,\r\n quarterly: data.DateQuarterly,\r\n morningstar: data.DateMorningStar\r\n };\r\n\r\n // Hide the ajax spinner\r\n const loaderContainer = document.querySelector('.spinner-container');\r\n if (loaderContainer) {\r\n loaderContainer.style.display = 'none';\r\n }\r\n\r\n destroyFundTables();\r\n\r\n fundsListingContainer.appendChild(daily);\r\n fundsListingContainer.appendChild(monthly);\r\n fundsListingContainer.appendChild(quarterly);\r\n fundsListingContainer.appendChild(morningstar);\r\n\r\n renderFootnotes(data, fundsListingFootnotesContainer);\r\n switchTable(currentTab, simulatedAnchorId);\r\n jumpToFundCategoryAnchor(currentTab, simulatedAnchorId);\r\n }\r\n \r\n function switchTable(selectedTab, simulatedAnchorId) {\r\n if(!selectedTab) {\r\n return;\r\n }\r\n\r\n // Show/hide tables\r\n let tables = fundsListingContainer.getElementsByTagName('table');\r\n tables = Array.from(tables);\r\n tables.forEach(t => {\r\n if(t.dataset.type === selectedTab) {\r\n t.style.display = 'table';\r\n } else {\r\n t.style.display = 'none';\r\n }\r\n });\r\n\r\n // Update as of dates\r\n let desktop = document.getElementById('desktopAsOfDate');\r\n let mobile = document.getElementById('mobileAsOfDate');\r\n let asOfDate = asOfDates[selectedTab];\r\n\r\n desktop.innerHTML = asOfDate;\r\n mobile.innerHTML = asOfDate;\r\n }\r\n\r\n\r\n async function getButtonToggleGroupComponent() {\r\n return new Promise((resolve, reject) => {\r\n if(!buttonsContainer) {\r\n reject(\"No buttons container on page\");\r\n }\r\n if(buttonsContainer.gsComponent) {\r\n resolve(buttonsContainer.gsComponent);\r\n }\r\n buttonsContainer.addEventListener('gs.load', (evt) => {\r\n if(evt.detail.component) {\r\n resolve(evt.detail.component);\r\n } else {\r\n reject(\"No component for this buttons container\")\r\n }\r\n }, false);\r\n });\r\n }\r\n\r\n\r\n function getShareClassFromQueryString() {\r\n const params = new URLSearchParams(window.location.search);\r\n const defaultShareClass = 'investor';\r\n \r\n if (!params.has('sclass')) {\r\n return defaultShareClass;\r\n }\r\n \r\n return params.get('sclass');\r\n }\r\n \r\n /**\r\n * Converts the share class name \"Investor/Institutional to a share class cd \"R\" or \"I\"\r\n * @param {string} shareClass\r\n * @returns the share class code\r\n */\r\n function shareClassToShareClassCD(shareClass) {\r\n if (!shareClass || shareClass.toLocaleLowerCase() !== 'institutional') {\r\n return 'R';\r\n }\r\n \r\n return 'I';\r\n }\r\n \r\n /**\r\n * Fetches data directly from API without looking in local storage\r\n * @param {*} shareClass\r\n */\r\n async function loadData(shareClass) {\r\n if(mockData) {\r\n return mockData;\r\n }\r\n\r\n try {\r\n const endpoint = `/api/sitecore/FundsListingData/Get?sclass=${shareClass}`;\r\n let response = await fetch(endpoint);\r\n let json = await response.json();\r\n return json;\r\n } catch (err) {\r\n console.error(err);\r\n }\r\n }\r\n\r\n function addAnchorToShareClassLinks() {\r\n let rawAnchor = getFragmentFromUrl();\r\n if(!rawAnchor) { return; }\r\n if(rawAnchor.indexOf('-daily')) {\r\n rawAnchor.replace('-daily', '');\r\n }\r\n let links = document.querySelectorAll('.share-class-selector .gs-shareclass-tab');\r\n links = Array.from(links);\r\n links.forEach(link => {\r\n let oldUrl = link.href;\r\n let newUrl = `${oldUrl}#${rawAnchor}`;\r\n if(oldUrl === newUrl) {\r\n return;\r\n }\r\n\r\n // Make sure the old url doesn't already have an anchor, and replace it if so\r\n let anchorPosition = oldUrl.indexOf('#');\r\n if(anchorPosition >= 0) {\r\n let initialUrl = oldUrl.substring(0, anchorPosition);\r\n newUrl = `${initialUrl}#${rawAnchor}`;\r\n }\r\n link.href = newUrl;\r\n });\r\n }\r\n\r\n /**\r\n * For mobile, jumps the page to put the sticky container into focus,\r\n * but doesn't scroll the sticky container to a specific category\r\n */\r\n function jumpPageToStickyContainer() {\r\n const headerHeight = 97;\r\n const containerTopPadding = 32;\r\n const scrollPosition = window.scrollY;\r\n const container = document.getElementById('sticky-container');\r\n const relativePosition = container.getBoundingClientRect().top;\r\n const absolutePosition = scrollPosition + relativePosition;\r\n const offset = headerHeight - containerTopPadding;\r\n window.scrollTo({left: 0, top: absolutePosition - offset});\r\n }\r\n\r\n function jumpStickyContainerToCategory(categoryId) {\r\n \r\n if(!categoryId) {\r\n return;\r\n }\r\n var category = document.getElementById(categoryId);\r\n if(!category) {\r\n return;\r\n }\r\n if(window.innerWidth >= 1024) {\r\n jumpToCategoryDesktop(categoryId);\r\n } else {\r\n jumpToCategoryMobile(categoryId);\r\n }\r\n }\r\n\r\n function getScrollOffset(type) {\r\n const offsets = {\r\n desktop: {\r\n siteHeader: 77,\r\n stickyHeader: 122,\r\n tableHeader: 64\r\n },\r\n mobile: {\r\n siteHeader: 65,\r\n stickyHeader: 143,\r\n tableHeader: 64\r\n }\r\n }\r\n let actual = offsets[type];\r\n actual.total = actual.siteHeader + actual.stickyHeader + actual.tableHeader;\r\n return actual;\r\n }\r\n\r\n function jumpToCategoryDesktop(categoryId) {\r\n window.scrollTo({left: 0, top: 0});\r\n var category = document.getElementById(categoryId);\r\n let categoryTop = category.getBoundingClientRect().top;\r\n const totalOffsets = getScrollOffset('desktop').total;\r\n let newWindowY = window.scrollY + categoryTop + 1;\r\n window.scrollTo({left: 0, top: newWindowY - totalOffsets});\r\n }\r\n\r\n /**\r\n * If category top equals total offsets, then we scroll to the current scroll position (don't move).\r\n * If categroy top is greater than total offsets, we scroll further down within the container.\r\n * If category top is less than total offsets, we scroll further up within the container.\r\n */\r\n function jumpToCategoryMobile(categoryId) {\r\n jumpPageToStickyContainer();\r\n \r\n const container = document.getElementById('sticky-container');\r\n container.scrollTo({left: 0, top: 0 });\r\n var category = document.getElementById(categoryId);\r\n let categoryTop = category.getBoundingClientRect().top;\r\n let currentScroll = container.scrollTop;\r\n\r\n const totalOffsets = getScrollOffset('desktop').total - 13;\r\n let newScrollY = Math.max(currentScroll + categoryTop - totalOffsets);\r\n container.scrollTo({left: 0, top: newScrollY });\r\n }\r\n\r\n function rawAnchorToActualAnchor(currentTab, rawAnchor) {\r\n if(rawAnchor.indexOf(\"-daily\") >= 0) {\r\n return rawAnchor.replace(\"-daily\", `-${currentTab}`);\r\n }\r\n return `${rawAnchor.toLowerCase()}-${currentTab}`;\r\n }\r\n\r\n function validateAnchorId(anchorId) {\r\n let element = document.getElementById(anchorId);\r\n if(!element) {\r\n return false;\r\n }\r\n return true;\r\n }\r\n\r\n\r\n\r\n function jumpToFundCategoryAnchor(currentTab, simulatedAnchorId) {\r\n let rawAnchor = !simulatedAnchorId ? getFragmentFromUrl(simulatedAnchorId) : simulatedAnchorId;\r\n if(!rawAnchor) {\r\n return;\r\n }\r\n let actualAnchor = rawAnchorToActualAnchor(currentTab, rawAnchor);\r\n if(validateAnchorId(actualAnchor)) {\r\n jumpStickyContainerToCategory(actualAnchor);\r\n }\r\n }\r\n }\r\n};","/* eslint-disable spaced-comment */\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/09/2020 Jjacob 52558 Inital Create\r\n// 04/20/2021 BBARRON 59918 Prevented login from automatically closing when on home page\r\n// 12/21/2022 BBARRON 96859 Added show/hide password button\r\n// 01/31/2025 BBARRON 147759 Renamed from HeaderLogin to indicate that this code is now being deprecated\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n/**\r\n * We're going to be phasing out this header login form that drops down when clicking the sign in button.\r\n * In its place we will have a dropdown menu with links to the various ODIC login urls. So we need a way to feature flag\r\n * the code, using the legacy login form in one case and the new login dropdown links in the other.\r\n */\r\n\r\nexport const legacyHeaderLoginScripts = {\r\n loadScripts: () => {\r\n /**\r\n * Toggles the legacy login form visibility\r\n */\r\n const handleLoginClick = () => {\r\n const login = document.getElementById('gs_header_login');\r\n login.classList.toggle('--active');\r\n };\r\n\r\n /**\r\n * Hide the login menu on scroll unless the user is on\r\n * a mobile device or they are on the site home page\r\n */\r\n function handleLoginScroll() {\r\n const isHome = isHomePage();\r\n const isDesktop = window.matchMedia('(min-width: 1024px)').matches;\r\n\r\n // Sticky login for mobile and home page, otherwise hide login on scroll\r\n if (isHome || !isDesktop) {\r\n return;\r\n }\r\n\r\n const login = document.getElementById('gs_header_login');\r\n login.classList.remove('--active');\r\n }\r\n\r\n /**\r\n * Determine if the user is currently on the home page\r\n * @return {boolean} true if the current page is the home page or site root\r\n */\r\n function isHomePage() {\r\n return (\r\n window.location.pathname === '/' || window.location.pathname === '/en' || window.location.pathname === '/en/'\r\n );\r\n }\r\n\r\n /**\r\n * Enable/disable the login button depending on whether the username/password fields are empty\r\n */\r\n function handleLoginButton() {\r\n const usernameVal = document.getElementById('userName').value;\r\n const passwordVal = document.getElementById('password').value;\r\n const loginButtons = document.querySelectorAll('.gs-login-section-button.--validate > .gs-link');\r\n if (usernameVal !== '' && passwordVal !== '') {\r\n for (let i = 0; i < loginButtons.length; i++) {\r\n loginButtons[i].classList.remove('gs-link--disabled');\r\n }\r\n } else {\r\n for (let i = 0; i < loginButtons.length; i++) {\r\n loginButtons[i].classList.add('gs-link--disabled');\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Click the eye icon to toggle password visiblity/masking\r\n * @param {MouseEvent} evt The click event\r\n */\r\n function togglePasswordVisible(evt) {\r\n const passwordContainer = document.querySelector('.gs-login-password-container');\r\n if (passwordContainer) {\r\n passwordContainer.classList.toggle('password-hidden');\r\n const passwordInput = document.querySelector('.gs-login-password-container input');\r\n const inputType = passwordContainer.classList.contains('password-hidden') ? 'password' : 'text';\r\n passwordInput.type = inputType;\r\n }\r\n }\r\n\r\n // Add click event handlers to password visibility buttons\r\n document.querySelectorAll('.gs-login-password-container > span').forEach(btn => {\r\n btn.addEventListener('click', togglePasswordVisible, false);\r\n });\r\n\r\n // Wire up the legacy login events if the legacy login form is present on the page\r\n if (document.getElementById('gs_header_login')) {\r\n document.getElementById('gs_header_mobile_login_link').addEventListener('click', () => {\r\n handleLoginClick();\r\n });\r\n document.getElementById('gs_header_login_link').addEventListener('click', () => {\r\n handleLoginClick();\r\n });\r\n if (document.getElementById('userName')) {\r\n document.getElementById('userName').addEventListener('keyup', () => {\r\n handleLoginButton();\r\n });\r\n }\r\n if (document.getElementById('password')) {\r\n document.getElementById('password').addEventListener('keyup', () => {\r\n handleLoginButton();\r\n });\r\n }\r\n\r\n window.addEventListener('scroll', handleLoginScroll);\r\n }\r\n }\r\n};\r\n","/* eslint-disable spaced-comment */\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/09/2020 Jjacob 52558 Inital Create\r\n// 04/20/2021 BBARRON 59918 Prevented login from automatically closing when on home page\r\n// 12/21/2022 BBARRON 96859 Added show/hide password button\r\n// 02/06/2025 BBARRON 148174 Adjust login dropdown positoin so it stays within page bounds\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n/**\r\n * We want the login menu to appear on hover for desktop and on click for mobile.\r\n * But we don't want it to accidentally appear on hover for mobile or on click for desktop.\r\n */\r\n\r\nexport const loginDropdownScripts = {\r\n loadScripts: () => {\r\n const loginMenu = document.getElementById('gs_login_menu');\r\n const loginBtnDesktop = document.getElementById('gs_header_login_link');\r\n const loginBtnMobile = document.getElementById('gs_header_mobile_login_link');\r\n const mobileNavBreakpoint = 992;\r\n /**\r\n * Moves the login menu horizontally to align with the sign in button\r\n * (desktop only)\r\n */\r\n const setDropdownPosition = () => {\r\n if (window.innerWidth < mobileNavBreakpoint) {\r\n loginMenu.style.left = '0px';\r\n return;\r\n }\r\n\r\n const bounds = loginBtnDesktop.getBoundingClientRect();\r\n const position = bounds.left;\r\n loginMenu.style.left = `${position}px`;\r\n\r\n const menuBounds = loginMenu.getBoundingClientRect();\r\n\r\n // If menu extends right outside of the page bounds, move it left until it is back in bounds\r\n if (menuBounds.right > window.innerWidth) {\r\n loginMenu.style.left = `${window.innerWidth - menuBounds.width}px`;\r\n }\r\n };\r\n\r\n /**\r\n * Wait a fraction of a second, and then check to see if the login menu can be hidden\r\n * (desktop only)\r\n */\r\n const handleMouseLeaveDesktop = () => {\r\n window.setTimeout(() => {\r\n if (\r\n loginMenu.dataset.mode === 'desktop' &&\r\n !loginMenu.matches(':hover') &&\r\n !loginBtnDesktop.matches(':hover')\r\n ) {\r\n loginMenu.classList.remove('--active');\r\n }\r\n }, 250);\r\n };\r\n\r\n /**\r\n * Hide the login menu if the click is outside of it (for both desktop and mobile)\r\n * @param {MouseEvent} evt The click event\r\n */\r\n const handleClickOutside = evt => {\r\n if (\r\n loginMenu &&\r\n !loginMenu.contains(evt.target) && // Clicked outside the login menu\r\n !loginBtnDesktop.contains(evt.target) && // Clicked outside the desktop login button\r\n !loginBtnMobile.contains(evt.target) // Clicked outside the mobile login button\r\n ) {\r\n loginMenu.classList.remove('--active'); // Hide the login menu\r\n }\r\n };\r\n\r\n // If we don't have a vertical login submenu to control, then exit early\r\n if (!loginMenu) {\r\n return;\r\n }\r\n\r\n // handle desktop login menu show/hide\r\n if (loginBtnDesktop) {\r\n loginBtnDesktop.addEventListener('mouseenter', evt => {\r\n loginMenu.classList.add('--active');\r\n loginMenu.dataset.mode = 'desktop';\r\n setDropdownPosition();\r\n });\r\n\r\n loginMenu.addEventListener('mouseenter', evt => {\r\n if (loginMenu.dataset.mode === 'desktop') {\r\n loginMenu.classList.add('--active');\r\n }\r\n });\r\n\r\n loginBtnDesktop.addEventListener('mouseleave', handleMouseLeaveDesktop);\r\n\r\n loginMenu.addEventListener('mouseleave', handleMouseLeaveDesktop);\r\n }\r\n\r\n // handle mobile login menu show/hide\r\n if (loginBtnMobile) {\r\n loginBtnMobile.addEventListener('click', evt => {\r\n evt.preventDefault();\r\n loginMenu.style.left = '0px';\r\n loginMenu.dataset.mode = 'mobile';\r\n loginMenu.classList.toggle('--active');\r\n });\r\n }\r\n\r\n // Add an event listener for clicks on the document to hide the menu if clicked outside\r\n document.addEventListener('click', handleClickOutside);\r\n\r\n // Add an event listener for window resize to adjust dropdown position using requestAnimationFrame\r\n window.addEventListener('resize', () => {\r\n requestAnimationFrame(() => {\r\n loginMenu.classList.remove('--active');\r\n loginMenu.dataset.mode = '';\r\n });\r\n });\r\n\r\n // Analytics on login link clicks\r\n const loginLinks = Array.from(loginMenu.querySelectorAll('a'));\r\n loginLinks.forEach(link => {\r\n link.addEventListener('click', evt => {\r\n window.dataLayer = window.dataLayer || [];\r\n window.dataLayer.push({\r\n event: link.dataset.event || 'header_login',\r\n page_url: window.location.href\r\n });\r\n });\r\n });\r\n }\r\n};\r\n","/* eslint-disable no-invalid-this */\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 11/11/2020 HJordan 49177 Initial Create\r\n// 11/17/2020 HJordan Add conditional to check for element before adding listeners\r\n// 08/19/2022 KKapoor 89884 Close mobile nav menu when a link is clicked\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const headerMobileScripts = {\r\n loadScripts: () => {\r\n const iconId = 'gs_header_mobile__menu_icon';\r\n const rootId = 'gs_header_mobile_list__root';\r\n\r\n const iconElement = document.getElementById(iconId);\r\n const rootElement = document.getElementById(rootId);\r\n\r\n /**\r\n * Establish the click events for the menu icon\r\n */\r\n if (iconElement) {\r\n iconElement.addEventListener('click', event => {\r\n if(iconElement.classList.contains('gs-nav-active')) {\r\n hideMobileNav();\r\n } else {\r\n showMobileNav();\r\n }\r\n });\r\n\r\n // close the mobile nav when one of the links is clicked. Useful for anchor links\r\n var mobileNavLinks = document.querySelectorAll('.gs-header-mobile-nav-item > a');\r\n [...mobileNavLinks].forEach(mobileLink => {\r\n mobileLink.addEventListener('click', hideMobileNav, false);\r\n });\r\n }\r\n\r\n /**\r\n * Hides the whole mobile nav menu\r\n */\r\n function hideMobileNav() {\r\n iconElement.classList.remove('gs-nav-active');\r\n const activeListElements = document.getElementsByClassName('gs-nav-active');\r\n [...activeListElements].forEach(el => el.classList.remove('gs-nav-active'));\r\n rootElement.classList.remove('gs-nav-active');\r\n }\r\n\r\n /**\r\n * Shows the mobile nav menu\r\n */\r\n function showMobileNav() {\r\n iconElement.classList.add('gs-nav-active');\r\n addListenersToList(rootId);\r\n rootElement.classList.add('gs-nav-active');\r\n }\r\n\r\n /**\r\n * EventListener callback which fires when a Back button is clicked. Based on the selected button, the\r\n * function determines the elements parentId (which is the ID of the active pane) and hides it and removes\r\n * the child listeners\r\n */\r\n function hideElementList() {\r\n const listToHideId = this.parentNode.id;\r\n const listToHideElement = document.getElementById(listToHideId);\r\n listToHideElement.classList.toggle('gs-nav-active');\r\n removeListenersFromList(listToHideId);\r\n }\r\n\r\n /**\r\n * EventListener callback which fires when a LI is clicked. Based on the selected list item's id,\r\n * the function determines which pane to display by grabbing the unique categoryID from the listItem\r\n * and searching for the corresponding pane with the matching category Id\r\n *\r\n * EXAMPLE : clicking listItem with ID gs_header_mobile_item__root.0 will open gs_header_mobile_list__root.0 pane\r\n */\r\n function showElementList() {\r\n const baseListId = 'gs_header_mobile_list__';\r\n const childId = this.id;\r\n const idCategory = childId.split('__')[1];\r\n const listToShowId = baseListId + idCategory;\r\n const listToShowElement = document.getElementById(listToShowId);\r\n\r\n if (listToShowElement) {\r\n listToShowElement.classList.toggle('gs-nav-active');\r\n addListenersToList(listToShowId);\r\n }\r\n }\r\n\r\n /**\r\n * Takes an element ID for a navigation pane and removes click listeners for it's children.\r\n * @param {string} listId The navigation object containing elements for the nav\r\n */\r\n const removeListenersFromList = listId => {\r\n const listElement = document.getElementById(listId);\r\n\r\n for (const child of listElement.childNodes) {\r\n if (child.nodeName === 'BUTTON') {\r\n child.removeEventListener('click', () => hideElementList);\r\n } else if (child.nodeName === 'UL') {\r\n const listItemNodes = child.childNodes;\r\n\r\n for (const item of listItemNodes) {\r\n item.removeEventListener('click', showElementList);\r\n }\r\n }\r\n }\r\n };\r\n\r\n /**\r\n * Takes an element ID for a navigation pane and adds click listeners to it's children.\r\n * If the child is a button, then a listener to dismiss the pain is added. Otherwise, the\r\n * function looks for all LI elements, and adds listeners to advance to the next pane\r\n * @param {string} listId The navigation object containing elements for the nav\r\n */\r\n const addListenersToList = listId => {\r\n const listElement = document.getElementById(listId);\r\n\r\n for (const child of listElement.childNodes) {\r\n if (child.nodeName === 'BUTTON') {\r\n child.addEventListener('click', hideElementList);\r\n } else if (child.nodeName === 'DIV') {\r\n const listItemNodes = child.getElementsByTagName('LI');\r\n for (const item of listItemNodes) {\r\n if (item.nodeName === 'LI') {\r\n item.addEventListener('click', showElementList);\r\n }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n};\r\n","/* eslint-disable spaced-comment */\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 10/16/2020 JJacob 49024 Initial Create\r\n// 11/11/2020 JJacob 52012 Changed element IDs to operate dynamically\r\n// 03/10/2021 KKapoor 56955 Check for missing sub header\r\n// 08/19/2022 KKapoor 89884 Close desktop nav menu when a link is clicked\r\n// 01/31/2025 BBARRON 147759 Renamed a number of variables for clarity, added documentation\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const headerScripts = {\r\n loadScripts: () => {\r\n /**\r\n * Reveals the desired subnav menu and hides the others marks the desired\r\n * header link as opened and marks the others as closed\r\n * @param {number} index The index of the header navigation link\r\n */\r\n const handleLinkClick = index => {\r\n const subheaders = document.getElementsByClassName('gs-subheader');\r\n const parentElems = document.getElementsByClassName('gs-header-link');\r\n [...subheaders].forEach(subheader => {\r\n if (subheader.id === 'gs_subheader_' + index) {\r\n subheader.classList.add('--active');\r\n } else {\r\n subheader.classList.remove('--active');\r\n }\r\n });\r\n\r\n // color the header\r\n [...parentElems].forEach(headerLink => {\r\n if (headerLink.id === 'gs_header_link_' + index) {\r\n headerLink.classList.add('gs-header-link--opened');\r\n } else {\r\n headerLink.classList.remove('gs-header-link--opened');\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * Close all header menus\r\n */\r\n const closeAllMenus = () => {\r\n const subheaders = document.getElementsByClassName('gs-subheader');\r\n const subheaderPattern = new RegExp('^gs_subheader_(.*)$');\r\n [...subheaders].forEach(subheader => {\r\n const match = subheader.id.match(subheaderPattern);\r\n if (!match || match.length < 2) {\r\n return;\r\n }\r\n const link = match[1];\r\n handleLinkExit(link);\r\n });\r\n };\r\n\r\n /**\r\n * Ensures that the given navigation header menu gets closed\r\n * @param {number} index The index of the header navigation menu that is closed\r\n */\r\n const handleLinkExit = index => {\r\n document.getElementById('gs_subheader_' + index).classList.remove('--active');\r\n const headerLink = document.getElementById('gs_header_link_' + index);\r\n headerLink.classList.remove('gs-header-link--opened');\r\n };\r\n\r\n const linkNumber = 5;\r\n const headerID = 'gs_header_link_';\r\n const subheaderID = 'gs_subheader_';\r\n\r\n if (document.getElementsByClassName('gs-header-link').length > 0) {\r\n for (let index = 0; index < linkNumber; index++) {\r\n const header = document.getElementById(headerID + index);\r\n if (header) {\r\n header.addEventListener('mouseover', () => {\r\n handleLinkClick(index);\r\n });\r\n }\r\n\r\n const subHeader = document.getElementById(subheaderID + index);\r\n if (subHeader) {\r\n subHeader.addEventListener('mouseleave', () => {\r\n handleLinkExit(index);\r\n });\r\n }\r\n\r\n const loginLink = document.getElementById('gs_header_login_link');\r\n if (loginLink) {\r\n loginLink.addEventListener('mouseover', () => {\r\n handleLinkExit(index);\r\n });\r\n }\r\n }\r\n\r\n // Close nav menu when a link is clicked\r\n const headerLinks = document.getElementsByClassName('gs-subheader-link');\r\n [...headerLinks].forEach(link => {\r\n link.addEventListener('click', closeAllMenus, false);\r\n });\r\n }\r\n }\r\n};\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 05/24/2022 ZSunOo 82637 Initial Create -- Added horizontal Table Scripts\r\n// 05/27/2022 ZSunOo 85181 Nested Children\r\n// 08/04/2022 GDEME 89643 Fund Details Pages (all) - expand/collapse functionality\r\n// 08/07/2022 BBARRON 89643 Overhaul expanding/collapsing footnotes. Default to expanded, disable collapsing if too short\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const horizontalTableScript = {\r\n loadScripts: () => {\r\n\r\n const defaultToCollapsed = false;\r\n const expandCollapseThreshold = 180;\r\n\r\n const handleExpandClick = evt => {\r\n evt.preventDefault();\r\n const parent = evt.currentTarget.parentNode;\r\n if (parent.classList.contains('factsheet-htable-footer')) {\r\n parent.classList.remove('factsheet-htable-footer--collapsed');\r\n parent.classList.add('factsheet-htable-footer--expanded');\r\n }\r\n };\r\n\r\n const handleCollapseClick = evt => {\r\n evt.preventDefault();\r\n const parent = evt.currentTarget.parentNode;\r\n if (parent.classList.contains('factsheet-htable-footer')) {\r\n parent.classList.remove('factsheet-htable-footer--expanded');\r\n parent.classList.add('factsheet-htable-footer--collapsed');\r\n }\r\n };\r\n\r\n const expandButtons = document.querySelectorAll('.factsheet-htable-footer-controls--collapsed');\r\n expandButtons.forEach(button => {\r\n button.addEventListener('click', handleExpandClick, false);\r\n });\r\n\r\n const collapseButtons = document.querySelectorAll('.factsheet-htable-footer-controls--expanded');\r\n collapseButtons.forEach(button => {\r\n button.addEventListener('click', handleCollapseClick, false);\r\n });\r\n\r\n // Only show expand/collapse controls if footer is high enough to justify this.\r\n // If present, remove these buttons if the footnotes are too short.\r\n function resetFooters() {\r\n const tableFooters = document.querySelectorAll('.factsheet-htable-footer');\r\n tableFooters.forEach(footer => { \r\n var footnotes = footer.querySelector('.factsheet-htable-footnotes');\r\n if(footnotes.offsetHeight > expandCollapseThreshold) {\r\n if(defaultToCollapsed){\r\n footer.classList.add('factsheet-htable-footer--collapsed');\r\n }else{\r\n footer.classList.add('factsheet-htable-footer--expanded');\r\n }\r\n } else {\r\n footer.classList.remove('factsheet-htable-footer--collapsed');\r\n footer.classList.remove('factsheet-htable-footer--expanded');\r\n }\r\n });\r\n }\r\n\r\n resetFooters();\r\n\r\n // Footer height can\r\n window.addEventListener('resize', function() {\r\n this.window.requestAnimationFrame(resetFooters);\r\n });\r\n\r\n\r\n }\r\n};\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 04/12/2023 BBARRON 103463 Initial create\r\n// 10/25/2023 BBARRON 117497 Add function to Push _ga cookie to data layer amd trigger GTM event\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nconst api = '/attribution/hash-phi';\r\nconst emailPattern = /^\\s*[^\\s@]+@[^\\s@]+\\.[^\\s@]+\\s*$/;\r\n\r\n/**\r\n * Given an email address, this async function generates the hash\r\n * @param {string} email The email address to hash/anonmymize\r\n * @returns The hashed email address\r\n */\r\nexport const hashEmail = async (email) => {\r\n const url = '/attribution/hash-phi';\r\n const payload = { value: email };\r\n const response = await fetch(api, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n const data = await response.json();\r\n \r\n if (data.Status === 'Success') {\r\n return data.HashedValue;\r\n } else {\r\n console.error(\"Attribution API response indicates an error has occurred\", data);\r\n throw new Error('Request failed: ' + data.Status);\r\n }\r\n}\r\n\r\n/**\r\n * Any time the email address changes on any field, \r\n * hash the value and store it for attribution when the form is later submitted.\r\n * @param {InputEvent} evt The change event\r\n */\r\nexport const handleAttributionEmailChange = async (evt) => {\r\n\tconst input = evt.target;\r\n\tconst email = input.value.trim().toLowerCase();\r\n\tif (!emailPattern.test(email)) {\r\n\t\treturn;\r\n\t}\r\n\t\r\n\ttry {\r\n\t\tlet hash = await hashEmail(email);\r\n\t\tinput.dataset.emailHash = hash;\r\n\t} catch (error) {\r\n\t\tconsole.error(error);\r\n\t}\r\n}\r\n\r\n/**\r\n * Event listener for attribution. Listens for any form submit on the page. If the an email address is submitted with the form, \r\n * stop the submit and push it through the attribution flow. Then disable this event handler and resubmit the form as usual.\r\n * If the form does not have an email address\r\n * @param {FormEvent} event The form submit event whose target is the form \r\n */\r\nexport const handleAttributionFormSubmit = (event) => {\r\n var emailInput = event.target.querySelector('input[type=\"email\"]');\r\n\r\n if(emailInput && window.dataLayer && emailInput.dataset.emailHash) {\r\n window.dataLayer.push({\r\n 'event': 'attributionEmailFormSubmit',\r\n 'attributionFormId': event.target.id,\r\n 'attributionEmailHash': emailInput.dataset.emailHash\r\n });\r\n }\r\n}\r\n\r\n\r\nexport const handleGoogleAnalyticsCookieLoaded = (cookieValue) => {\r\n if (window.dataLayer && cookieValue) {\r\n window.dataLayer.push({\r\n 'event': 'googleAnalyticsCookieLoaded',\r\n 'googleAnalyticsCookieValue': cookieValue,\r\n });\r\n }\r\n}","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 10/25/2023 BBARRON 117497 Initial create\r\n// 11/15/2023 BBARRON 118393 Allow listeners to add their own validation function that must bass\r\n// before they are notified while still notifying other listeners\r\n// 12/05/2023 BBARRON 119988 Revert the above change, did not resolve the issue, caused a drop in events recoreded in GA\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n/**\r\n * The polling interval. How often to check to see \r\n * if the cookie has been loaded (in milliseconds)\r\n */\r\nconst interval = 500;\r\n\r\n/**\r\n * A hashtable of cookie notifiers. One for each cookie.\r\n * The notifyWhenCookieSet will use this to manage resources\r\n * and ensure only one notifier is created for each cookie name.\r\n */\r\nconst cookieNotifiers = {};\r\n\r\n/**\r\n * Gets all cookies and returns them as an object\r\n * where key = cookieName and value = cookieValues\r\n * @returns The cookies ad an object\r\n */\r\nexport const getCookies = () => {\r\n return document.cookie\r\n .split(';') // Separate by cookie\r\n .map(k => k.trim()) // Trim whitespace\r\n .reduce((result, k, i) => { // Save keys/values to an object\r\n const [key, value] = k.split('=');\r\n result[key] = decodeURI(value);\r\n return result;\r\n }, {});\r\n};\r\n\r\n/**\r\n * Gets a single cookie value by name or null if not set\r\n * @param {string} cookieName The name of the cookie to watch for\r\n * @returns The cookie value or null\r\n */\r\nexport const getCookie = (cookieName) => {\r\n let cookies = getCookies();\r\n if (cookies.hasOwnProperty(cookieName)) {\r\n return cookies[cookieName];\r\n }\r\n return null;\r\n};\r\n\r\n/**\r\n * Determines whether a cookie with the given name is set\r\n * @param {string} cookieName The name of the cookie to watch for\r\n * @returns true if the cookie is set\r\n */\r\nexport const cookieExists = (cookieName) => {\r\n let cookie = getCookie(cookieName);\r\n return cookie !== null && typeof cookie !== 'undefined';\r\n};\r\n\r\n/**\r\n * This class follows a pub/sub pattern, polling a given cookie and\r\n * notigying all listeners when the cookie is set by calling the given callback method.\r\n * If the cookie is alredy set, then just call the callback function immediately\r\n */\r\nclass CookieNotifier {\r\n constructor(cookieName) {\r\n this.name = cookieName\r\n this.loaded = false;\r\n this.callbacks = [];\r\n this.checkCookieExists();\r\n }\r\n\r\n /**\r\n * Add a callback function to this cookie notifier that will be called once the cookie is set in the browser\r\n * @param {function} callback A callback function that takes a cookie name as a parameter\r\n */\r\n add(callback) {\r\n if(this.loaded) {\r\n let cookieValue = getCookie(this.name);\r\n callback(cookieValue);\r\n } else {\r\n this.callbacks.push(callback);\r\n }\r\n }\r\n\r\n checkCookieExists() {\r\n if (!cookieExists(this.name)) {\r\n window.setTimeout(this.checkCookieExists.bind(this), interval) // try again in a little while\r\n } else {\r\n // notify all listeners that the cookie has been set.\r\n // pass in the cookie value to the callback\r\n let cookie = getCookie(this.name);\r\n this.loaded = true;\r\n this.callbacks.forEach(c => {\r\n c(cookie);\r\n });\r\n this.callbacks = [];\r\n }\r\n }\r\n}\r\n\r\n\r\n/**\r\n * Given a cookie name and a callback function, this method calls the callback function when the desired cookie has been set in the browser.\r\n * @param {string} cookieName The name of the cookie to watch for\r\n * @param {the callback function} callback This function gets called once the cookie value is knowne. cookie value is passed into the callback\r\n */\r\nexport const notifyWhenCookieSet = (cookieName, callback) => {\r\n if (!cookieNotifiers.hasOwnProperty(cookieName)) {\r\n cookieNotifiers[cookieName] = new CookieNotifier(cookieName);\r\n }\r\n cookieNotifiers[cookieName].add(callback);\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 04/12/2023 BBARRON 103463 Initial create\r\n// 10/25/2023 BBARRON 117497 Push _ga cookie value to data layer when it is set\r\n// 11/15/2023 BBARRON 118393 Require _ga cookie value to start with \"GA\" before sending to Tag Manager\r\n// 12/05/2023 BBARRON 119988 Revert the above change, did not resolve the issue, caused a drop in events recoreded in GA\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { handleAttributionFormSubmit, handleAttributionEmailChange, handleGoogleAnalyticsCookieLoaded } from '../services/attribution';\r\nimport { notifyWhenCookieSet } from '../utils/cookie-utils';\r\n\r\nexport const attributionScripts = {\r\n loadScripts: () => {\r\n // Wait a bit after the page loads and then wire up any forms on the page that have an \r\n window.setTimeout(() => {\r\n const forms = Array.from(document.getElementsByTagName(\"form\"));\r\n forms.filter(f => {\r\n // If the form does not have an email input field, we ignore it\r\n let emailInput = f.querySelector('input[type=\"email\"]');\r\n if(!emailInput) {\r\n return false;\r\n }\r\n\r\n emailInput.addEventListener('change', handleAttributionEmailChange, false);\r\n return true;\r\n }).forEach(f => {\r\n console.log('Adding attribution event listener to form', f);\r\n f.addEventListener('submit', handleAttributionFormSubmit, false);\r\n });\r\n }, 2000);\r\n\r\n\r\n // When the _ga cookies is set, pass the value to the data layer\r\n notifyWhenCookieSet('_ga', handleGoogleAnalyticsCookieLoaded);\r\n }\r\n};","/* eslint-disable spaced-comment */\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 11/17/2020 HJordan inclusion of mobileHeaderScripts\r\n// 12/09/2020 Jjacob 52558 Added login related scripts\r\n// 12/14/2020 JJacob 51694 Added toggle colapse list\r\n// 12/14/2020 HJordan 49021 Added support for Site Search / Content Search / Tag Filters / CardGroups\r\n// 01/19/2022 BBARRON 75636 Included Funds Listing Script\r\n// 05/13/2022 ZSunOo 77752 Added Price Distribution Graph Scripts\r\n// 05/24/2022 ZSunOo 82637 Added horizontal Table Scripts\r\n// 07/19/2022 BBARRON 88352 Add simulated anchor ids property to funds listing component\r\n// 10/10/2022 BBARRON 93604 Added ButtonToggleGroup component\r\n// 02/01/2023 BBARRON 99334 Renamd updatePageSearchContent to initializeContentSearch\r\n// 04/12/2023 BBARRON 103463 Added attribution scripts - listens for all form submits\r\n// 06/13/2023 GCASEY 107567 Add alert scripts\r\n// 10/16/2023 GCASEY 110128 Add form banner scripts\r\n// 10/24/2023 BBARRON 116058 Add Milestones component scripts\r\n// 10/23/2023 GCASEY 117077 Add Accordion Drawer and Accordion Toggle Scripts \r\n// 07/01/2024 GCASEY 133318 Add form select scripts\r\n// 08/14/2024 GCASEY 136634 Add back button scripts\r\n// 12/16/2024 GCASEY 144752 Add Input Field scripts\r\n// 01/31/2025 BBARRON 147759 Added new oidc header login dropdown scripts\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { cardGroupScripts } from './card-group/CardGroup';\r\nimport { contentSearchScripts, initializeContentSearch } from './content-search/ContentSearch';\r\nimport { customSelectScripts } from './custom-select/CustomSelect';\r\nimport { FAQScripts } from './faq/FAQ';\r\nimport { legacyHeaderLoginScripts } from './header-login/LegacyHeaderLogin';\r\nimport { loginDropdownScripts } from './header-login/LoginDropdown';\r\nimport { headerMobileScripts } from './header-mobile/HeaderMobile';\r\nimport { headerScripts } from './header/Header';\r\nimport { siteSearchScripts } from './content-search/ContentSearch';\r\nimport { tagFilterScripts } from './tag-filters/TagFilters';\r\nimport { toggleButtonScripts } from './toggle-button/ToggleButton';\r\nimport { CollapseListScripts } from './collapse-list/CollapseList';\r\nimport { toggleRadioScripts } from './radio-switch/RadioSwitch';\r\nimport { carouselScripts } from './carousel/Carousel';\r\nimport { dateTagFilterScripts } from './date-tag-filters/DateTagFilters';\r\nimport { wizardScripts } from './wizard/Wizard';\r\nimport { siteAnimations } from './site-animations/SiteAnimations';\r\nimport { fundsListingScripts } from './funds-listing/FundsListing';\r\nimport { factsheetVerticalTableScripts } from './factsheet-vertical-table/FactsheetVerticalTable';\r\nimport { factsheetPieChartScripts } from './factsheet-pie-chart/FactsheetPieChart';\r\nimport { priceDistributionScripts } from './price-distribution/PriceDistribution';\r\nimport { factSheetFundHeaderScript } from './factsheet-fund-header/FactSheetFundHeader';\r\nimport { horizontalTableScript } from './horizontal-tables/HorizontalTables';\r\nimport { factsheetSectionScripts } from './factsheet-section/FactsheetSection';\r\nimport { factsheetOverviewScripts } from './factsheet-overview/FactsheetOverview';\r\nimport { factsheetHorizontalTextScripts } from './factsheet-horizontal-text/FactsheetHorizontalText';\r\nimport { buttonToggleGroupScripts } from './button-toggle-group/ButtonToggleGroup';\r\nimport { attributionScripts } from './attribution/Attribution';\r\nimport { interactiveMapScripts } from './interactive-map/InteractiveMap';\r\nimport { smoothScrollAnchorLinkScripts } from './smooth-scroll-anchor-link/smooth-scroll-anchor-link';\r\nimport { retirementPreparednessScripts } from './retirement-preparedness/RetirementPreparedness'\r\nimport { formBannerScripts } from './form-banner/FormBanner';\r\nimport { milestonesScripts } from './milestones/Milestones';\r\nimport { formSelectScripts } from './form-select/formSelect';\r\nimport accordionDrawerScripts from './accordion-drawer/AccordionDrawer';\r\nimport accordionToggleListScripts from './accordion-toggle-list/AccordionToggleList';\r\nimport { backButtonScripts } from './back-button/BackButton';\r\n\r\nimport alertScripts from './alert/Alert';\r\nimport { inputFieldScripts } from './input/InputFields';\r\n\r\nwindow.addEventListener('load', () => {\r\n siteAnimations.loadScripts();\r\n headerScripts.loadScripts();\r\n headerMobileScripts.loadScripts();\r\n toggleButtonScripts.loadScripts();\r\n FAQScripts.loadScripts();\r\n legacyHeaderLoginScripts.loadScripts();\r\n loginDropdownScripts.loadScripts();\r\n customSelectScripts.loadScripts();\r\n CollapseListScripts.loadScripts();\r\n contentSearchScripts();\r\n siteSearchScripts();\r\n tagFilterScripts();\r\n cardGroupScripts();\r\n toggleRadioScripts.loadScripts();\r\n carouselScripts.loadScripts();\r\n initializeContentSearch();\r\n dateTagFilterScripts();\r\n wizardScripts.loadScripts();\r\n interactiveMapScripts.loadScripts();\r\n factsheetVerticalTableScripts.loadScripts();\r\n factsheetPieChartScripts.loadScripts();\r\n fundsListingScripts.loadScripts(null, null, null, null);\r\n priceDistributionScripts.loadScripts(null, null);\r\n factSheetFundHeaderScript.loadScripts();\r\n horizontalTableScript.loadScripts();\r\n factsheetSectionScripts.loadScripts();\r\n factsheetOverviewScripts.loadScripts();\r\n factsheetHorizontalTextScripts.loadScripts();\r\n buttonToggleGroupScripts.loadScripts();\r\n attributionScripts.loadScripts();\r\n alertScripts.loadScripts();\r\n smoothScrollAnchorLinkScripts.loadScripts();\r\n retirementPreparednessScripts.loadScripts();\r\n milestonesScripts.loadScripts();\r\n formBannerScripts();\r\n accordionDrawerScripts.loadScripts();\r\n accordionToggleListScripts.loadScripts();\r\n formSelectScripts();\r\n backButtonScripts();\r\n inputFieldScripts();\r\n});\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 08/14/2024 GCASEY 136634 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n/**\r\n * Allows specific links to take the user to the previous page\r\n * Intended for after a user submits a form\r\n */\r\nexport function backButtonScripts() {\r\n const cssClass = \"gs-link--navigate-back\";\r\n const elements = Array.from(document.getElementsByClassName(cssClass));\r\n\r\n elements.forEach((link) => link.addEventListener(\"click\", (e) => {\r\n e.preventDefault();\r\n e.stopImmediatePropagation();\r\n\r\n if(window.history.length > 1) {\r\n window.history.back();\r\n } else {\r\n window.location.href = \"/\";\r\n }\r\n }));\r\n}","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/16/2024 GCASEY 144752 Initial create\r\n// 01/06/2025 GCASEY 143299 Add input selection handling\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n\r\nexport const inputFieldScripts = () => {\r\n /**\r\n * Mask Input string with given pattern\r\n * The 0 character is used in place of numbers\r\n * @param {string} input \r\n * @param {string} mask \r\n * @returns \r\n */\r\n const maskCharacters = (input, mask) => {\r\n let result = '';\r\n let index = 0;\r\n\r\n for (let i = 0; i < mask.length; i++) {\r\n if (mask[i] === '0' && index < input.length) {\r\n result += input[index];\r\n index++;\r\n } else if (mask[i] !== '0') {\r\n result += mask[i];\r\n }\r\n\r\n if (index >= input.length) {\r\n break;\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Override default input behavior and add numeric/length restrictions and mask/placeholder\r\n * @param {HTMLElement} element \r\n * @param {string} placeholder \r\n * @param {string} mask \r\n */\r\n const restrictInput = (element, placeholder, mask) => {\r\n element.placeholder = placeholder;\r\n\r\n element.addEventListener(\"input\", (e) => {\r\n if (e.inputType == \"deleteContentBackward\") {\r\n return;\r\n }\r\n\r\n const numeric = e.target.value.replace(/\\D/g, \"\");\r\n const masked = maskCharacters(numeric, mask);\r\n e.target.value = masked.slice(0, mask.length);\r\n });\r\n }\r\n\r\n /**\r\n * Handles the color of the initial placeholder value in dropdowns\r\n * @param {Event} event \r\n */\r\n const selectHandler = (event) => {\r\n const element = event.target;\r\n const selectedClass = \"--selected\";\r\n\r\n if(element.value !== \"\") {\r\n element.classList.add(selectedClass);\r\n } else {\r\n element.classList.remove(selectedClass);\r\n }\r\n }\r\n\r\n /**\r\n * Handles the toggle button for the visibility of the ssn input field\r\n * @param {Event} event \r\n */\r\n const ssnButtonHandler = (event) => {\r\n const element = event.target;\r\n const selectedClass = \"--selected\";\r\n const hiddenClass = \"--hidden\";\r\n\r\n if (element.classList.contains(selectedClass)) {\r\n element.classList.remove(selectedClass);\r\n element.previousElementSibling.classList.remove(hiddenClass);\r\n } else {\r\n element.classList.add(selectedClass);\r\n element.previousElementSibling.classList.add(hiddenClass);\r\n }\r\n\r\n event.stopImmediatePropagation();\r\n }\r\n\r\n\r\n const dobElements = Array.from(document.getElementsByClassName(\"gs-form-input-dob\"));\r\n const phoneElements = Array.from(document.getElementsByClassName(\"gs-form-input-phone\"));\r\n const ssnElements = Array.from(document.getElementsByClassName(\"gs-form-input-ssn\"));\r\n const ssnIconButtons = Array.from(document.getElementsByClassName(\"gs-form-input-icon-ssn\"));\r\n const selectElements = Array.from(document.querySelectorAll(\"select.gs-form-input, select.gs-form-cta-input\"));\r\n dobElements.forEach((dob) => restrictInput(dob, \"mm/dd/yyyy\", \"00/00/0000\"));\r\n phoneElements.forEach((phone) => restrictInput(phone, \"(###) ###-####\", \"(000) 000-0000\"));\r\n ssnElements.forEach((ssn) => restrictInput(ssn, \"###-##-####\", \"000-00-0000\"));\r\n selectElements.forEach((select) => select.addEventListener(\"change\", (e) => selectHandler(e)));\r\n ssnIconButtons.forEach((btn) => btn.addEventListener(\"click\", (e) => ssnButtonHandler(e)));\r\n}\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 11/22/2021 BBARRON 74527 Initial Create\r\n// 01/06/2022 BBARRON 77108 pass data in as parameter or get from hidden data tables on page from CMS\r\n// 01/12/2022 BBARRON 77743 Fix link styles and url if not starting with http\r\n// 04/27/2022 BBARRON 84447 Remove unused variable\r\n// 05/18/2023 BBARRON 105921 Renamed and updated data model to include link text, isExternal and newTab\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const interactiveMapScripts = {\r\n loadScripts: () => {\r\n const mapInfoCloseBtnClass = 'gs-map-closebtn';\r\n const stateClass = 'state';\r\n const activeStateClass = 'state-active';\r\n\r\n const defaultFill = '#d2d2d2'; // Grayscale Holy Ghost\r\n const activeFill = '#007B4B'; // Brand Green Success\r\n\r\n const infoModalCloseButtons = document.querySelectorAll(`.${mapInfoCloseBtnClass}`);\r\n const stateElements = Array.prototype.slice.call(document.querySelectorAll(`.${stateClass}`));\r\n\r\n\r\n /**\r\n * Handle the case when the info modal close button is clicked\r\n * @param {ClickEvent} evt \r\n */\r\n function handleCloseClick(evt) {\r\n evt.preventDefault();\r\n let stateInfos = document.querySelectorAll('.gs-map-stateinfo');\r\n stateInfos.forEach(s => {\r\n s.classList.add('hidden');\r\n });\r\n updateMap(null, stateElements);\r\n }\r\n\r\n /**\r\n * Handle the case when a US state is clicked\r\n * @param {ClickEvent} evt \r\n */\r\n function handleStateClick(evt) {\r\n evt.preventDefault();\r\n const stateCode = evt.target.dataset.name;\r\n let stateInfos = document.querySelectorAll('.gs-map-stateinfo');\r\n stateInfos.forEach(s => {\r\n if(s.dataset.abbreviation === stateCode) {\r\n s.classList.remove('hidden');\r\n } else {\r\n s.classList.add('hidden');\r\n }\r\n });\r\n updateMap(stateCode, stateElements);\r\n }\r\n\r\n \r\n\r\n /**\r\n * Updates the map with the current active state\r\n * @param {*} activeState The new active state code\r\n * @param {*} stateElements The list of state elements\r\n */\r\n function updateMap(activeState, stateElements) {\r\n stateElements.forEach(state => {\r\n let isActive = false;\r\n if(activeState) {\r\n let currentState = state.dataset.name;\r\n isActive = currentState === activeState;\r\n }\r\n \r\n updateStateStatus(state, isActive);\r\n });\r\n }\r\n\r\n /**\r\n * Updates the active/inactive status of a single state\r\n * @param {HtmlElement} stateElement \r\n * @param {boolean} isActive \r\n */\r\n function updateStateStatus(stateElement, isActive) {\r\n if(isActive) {\r\n stateElement.setAttribute('fill', activeFill);\r\n stateElement.classList.remove(activeStateClass);\r\n } else {\r\n stateElement.setAttribute('fill', defaultFill);\r\n stateElement.classList.remove(activeStateClass);\r\n }\r\n }\r\n\r\n // Wire up the events\r\n if(infoModalCloseButtons && stateElements && stateElements.length > 0) {\r\n stateElements.forEach(stateEl => {\r\n stateEl.addEventListener('click', handleStateClick, false);\r\n });\r\n\r\n infoModalCloseButtons.forEach(btn => {\r\n btn.addEventListener('click', handleCloseClick, false);\r\n });\r\n \r\n }\r\n }\r\n };","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 10/23/2023 BBARRON 116058 Initial create\r\n// 11/07/2023 BBARRON 118337 Smooth scroll when jumping between elements on mobile\r\n// 12/04/2023 BBARRON 119552 Ensure milestone query param for deep linking is not case sensitive\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { scrollToElement } from \"../utils/scroll-utils\";\r\n\r\nconst milestoneActiveClass = 'gs-milestones-stone--active';\r\nconst milestoneContentActiveClass = 'gs-milestones-content--active';\r\n\r\nexport const milestonesScripts = {\r\n loadScripts: () => {\r\n\r\n // This is our circuit breaker. If the milestones component is not on the page, exit immediately.\r\n const milestonesComponent = document.querySelector('.gs-milestones-component');\r\n if (!milestonesComponent) {\r\n return;\r\n }\r\n\r\n /**\r\n * Sets the relative indicator position to a given x value. x value cooresponds to the left edge of the indicator, not the center.\r\n * @param {number} position The x position where the indicator arrow should be moved\r\n */\r\n function setIndicatorPosition(position) {\r\n const indicator = document.querySelector('.gs-milestones-indicator-inner');\r\n indicator.style.left = `${position}px`;\r\n }\r\n\r\n /**\r\n * Given an x coordinate, move the arrow indicator so that it is centered on the given x position\r\n * @param {number} position The x coordinate where the arrow indicator should point (center)\r\n */\r\n function centerIndicatorOnPositon(position) {\r\n const indicator = document.querySelector('.gs-milestones-indicator-inner');\r\n const indicatorRect = indicator.getBoundingClientRect();\r\n setIndicatorPosition(position - (indicatorRect.width / 2));\r\n }\r\n\r\n /**\r\n * Gets the currently active milestone circle by looking for the active class\r\n */\r\n function getActiveStone() {\r\n return document.querySelector(`.${milestoneActiveClass}`);\r\n }\r\n\r\n /**\r\n * Makes the milestone content visible for the given milestone circle \"stone\" element\r\n * Optionally scrolls the user to the content that was revealed\r\n * @param {HtmlElement} stone The milestone circle element\r\n * @param {boolean} shouldScrollToContent Whether to scroll the user to the content (true for mobile, false for desktop)\r\n */\r\n function showActiveContent(stone, shouldScrollToContent) {\r\n if (!stone) {\r\n return;\r\n }\r\n let milestoneId = stone.dataset.milestone;\r\n const content = document.querySelectorAll('.gs-milestones-content');\r\n content.forEach(c => {\r\n if(c.dataset.milestone === milestoneId) {\r\n c.classList.add(milestoneContentActiveClass);\r\n if(shouldScrollToContent) {\r\n scrollToElement(c, { behavior: 'smooth'});\r\n }\r\n } else {\r\n c.classList.remove(milestoneContentActiveClass)\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Sets the given stone to be active, makes all other stones inactive, moves the indicator arrow to this stone, and reveals the content.\r\n * Optionally scrolls the user down to the revealed content for this milestone\r\n * @param {HtmlElement} stone The given milestone circle \"stone\" element to make active\r\n * @param {boolean} shouldScrollToContent Whether to scroll the user to the content (true for mobile, false for desktop)\r\n * @returns \r\n */\r\n function setActiveStone(stone, shouldScrollToContent) {\r\n if (!stone) {\r\n return;\r\n }\r\n let stones = document.querySelectorAll('.gs-milestones-navigation-items .gs-milestones-stone');\r\n stones.forEach((st, index) => {\r\n st.classList.remove(milestoneActiveClass)\r\n });\r\n stone.classList.add(milestoneActiveClass);\r\n showActiveContent(stone, shouldScrollToContent);\r\n alignIndicatorToStone(stone);\r\n }\r\n\r\n /**\r\n * Centers the indicator arrow horizontally under the given milestone circle \"stone\" element\r\n * @param {HtmlElement} stone The given milestone circle \"stone\" element\r\n */\r\n function alignIndicatorToStone(stone) {\r\n if (!stone) {\r\n stone = getActiveStone();\r\n }\r\n const position = getStoneCenter(stone);\r\n centerIndicatorOnPositon(position);\r\n }\r\n\r\n /**\r\n * Calculates the x position at the horizontal center of the milestone circle \"stone\" element\r\n * @param {HtmlElement} stone The given milestone circle \"stone\" element\r\n * @returns The center x coordinate\r\n */\r\n function getStoneCenter(stone) {\r\n const stoneParent = stone.parentElement.parentElement;\r\n const stoneRect = stone.getBoundingClientRect();\r\n let stonePosition = stoneRect.x - stoneParent.getBoundingClientRect().x\r\n let stoneCenter = stonePosition + (stoneRect.width / 2);\r\n return stoneCenter;\r\n }\r\n\r\n /**\r\n * When a stone element ic clicked, we want to make it active but also in some cases scroll the user down to the content\r\n * @param {MouseEvent} evt The click event\r\n */\r\n function handleStoneClick(evt) {\r\n evt.preventDefault();\r\n const stone = evt.currentTarget;\r\n\r\n // on mobile, scroll down to content area\r\n let shouldScrollToContent = window.innerWidth < 640;\r\n setActiveStone(stone, shouldScrollToContent);\r\n }\r\n\r\n /**\r\n * This component supports deep linking. If the milestone query string parameter is\r\n * present and matches the data-milestone attribute of any of the milestone circle elements\r\n * Then we say that the matching milestone is the active milestone on page load. If there is\r\n * no match, then we default to the first stone as active.\r\n * @returns The milestone element that is initially active on page load.\r\n */\r\n function getInitialMilestone() {\r\n \r\n const params = new URLSearchParams(window.location.search);\r\n const stones = Array.from(document.querySelectorAll('.gs-milestones-navigation-items .gs-milestones-stone'));\r\n\r\n let milestoneId = params.get('milestone');\r\n if (!milestoneId) {\r\n return stones[0];\r\n }\r\n\r\n milestoneId = milestoneId.toLocaleLowerCase();\r\n\r\n // default to the initial milestone if no matches found\r\n return stones.find(st => st.dataset.milestone.toLocaleLowerCase() === milestoneId) || stones[0];\r\n }\r\n\r\n\r\n // Initialize the component\r\n var initialMilestone = getInitialMilestone();\r\n setActiveStone(initialMilestone);\r\n\r\n // Listen for stone clicks\r\n let stones = document.querySelectorAll('.gs-milestones-navigation-items .gs-milestones-stone');\r\n stones.forEach((stone, index) => {\r\n stone.addEventListener('click', handleStoneClick, false);\r\n });\r\n\r\n // Listen for clicks on the return to top link\r\n let returnAnchor = document.querySelector('.gs-milestones-return-anchor a');\r\n returnAnchor.addEventListener('click', (evt) => {\r\n evt.preventDefault();\r\n const milestoneNavigationTop = document.querySelector('.gs-milestones-navigation-items');\r\n scrollToElement(milestoneNavigationTop, { behavior: 'smooth'});\r\n }, false);\r\n\r\n // Update the indicator arrow position on window resize\r\n window.addEventListener('resize', (evt) => {\r\n // When resizing the page, make sure the indicatoralways lines up with the active stone\r\n requestAnimationFrame(() => {\r\n alignIndicatorToStone();\r\n });\r\n }, false);\r\n }\r\n};","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 05/11/2022 ZSunOo 77752 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const elements = {\r\n chartContainer: '.chart-container',\r\n factsheetSectionHeading: '.gs-factsheet-section-heading',\r\n historicalPricesContainer: '.historical-prices-container',\r\n historicalPricesContainerInner: '.historical-prices-container .component-container',\r\n historicalPricesContainerTable: '.historical-prices-container-table',\r\n historicalFromDate: '#historical-from-date',\r\n historicalToDate: '#historical-to-date',\r\n historicalPricesTable: '.historical-prices-table',\r\n updateHistoryButton: '.update-history-button',\r\n showHistoryTable: '.showhistorytable',\r\n downloadExcelButton: '.download-excel-button',\r\n downloadCsvButton: '.download-csv-button',\r\n historyTableSelect: '#historytableselect',\r\n dataTypeDaily: '.data-type-daily',\r\n histNav: '.hist-NAV',\r\n histDiv: '.hist-DIV',\r\n histCap: '.hist-CAP',\r\n distributionCheckbox: 'input[name=\"showdistributions\"]',\r\n timePeriodList: '.time-period-list'\r\n};\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 05/11/2022 ZSunOo 77752 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport moment from 'moment';\r\n\r\nexport class Data {\r\n /**\r\n * Parse JSON date string as UTC into a moment Date wrapper object\r\n * @param { string } str The date string\r\n * @returns The parsed date (moment object) or empty string\r\n */\r\n parseDate(str) {\r\n const regex = new RegExp(/Date\\((\\d+)\\)/).exec(str);\r\n if (regex.length > 0) {\r\n return moment.utc(parseInt(regex[1]));\r\n } else {\r\n return '';\r\n }\r\n }\r\n\r\n /**\r\n * Takes raw data from the API and processes it so it can be rendered by the LineGraph class\r\n * @param {string} json \r\n * @returns the processed data\r\n */\r\n process(json) {\r\n const that = this;\r\n const values = [];\r\n const distributions = [];\r\n const distributionAssetValue = function (d) {\r\n for (let i = 0; i < values.length; i++) {\r\n if (moment(values[i].date).isSame(d.date, 'day')) {\r\n return values[i];\r\n }\r\n }\r\n\r\n return undefined;\r\n };\r\n\r\n json.Values.forEach(function (v) {\r\n values.push({\r\n value: v.SharePrice,\r\n date: that.parseDate(v.TradeDate)\r\n });\r\n });\r\n\r\n json.Distributions.forEach(function (d) {\r\n distributions.push({\r\n rate: d.Rate,\r\n date: that.parseDate(d.PayDate),\r\n type: d.DistributionType,\r\n dateRecord: that.parseDate(d.RecordDate)\r\n });\r\n });\r\n\r\n distributions.forEach(function (d) {\r\n const NAVValue = distributionAssetValue(d);\r\n if (NAVValue) {\r\n d.value = NAVValue.value;\r\n d.date = NAVValue.date;\r\n }\r\n });\r\n\r\n return {\r\n values: values,\r\n distributions: distributions\r\n };\r\n }\r\n}\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 05/11/2022 ZSunOo 77752 Initial Create\r\n// 09/01/2022 BBARRON 89603 Pulled lower table rendering out into its own function so it can be rerendered independently of the chart\r\n// 09/12/2022 BBARRON 89878 Remove unnecessary console logging, update width on chart re-render\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n// import * as d3 from 'd3';\r\nimport d3 from 'd3';\r\nimport moment from 'moment';\r\nimport { elements } from './elements';\r\n\r\n// something in another lib is overridding this. Storing a reference for later use...hopefully\r\n// it does the trick\r\nconst _d3Mouse = d3.mouse;\r\nconst _d3Zoom = d3.behavior.zoom();\r\n\r\nfunction formatCurrency(amount) {\r\n const formatter = new Intl.NumberFormat('en-US', {\r\n style: 'currency',\r\n currency: 'USD',\r\n minimumFractionDigits: 2\r\n });\r\n\r\n return formatter.format(amount);\r\n}\r\n\r\n/**\r\n * Re-renders the historical prices table at the bottom of the chart. Filtered out rows are not just hidden, \r\n * they are not rendered at all so css nth-child()-based row coloring works.\r\n * @param {string} filter (nav|div|cap|all)\r\n * @param {object[]} tableRows A list of data rows with the format {date: YYYY-MM-ddThh:mm:ss.000Z, value: XX.XX, class: \"hist-NAV\"}\r\n * @returns void\r\n */\r\nfunction renderHistoricalPricesTable(filter, tableRows) {\r\n const historicalPricesTable = document.querySelector(elements.historicalPricesTable);\r\n if (!historicalPricesTable) {\r\n return;\r\n }\r\n\r\n historicalPricesTable.innerHTML = '';\r\n\r\n if (!filter) {\r\n filter = \"all\";\r\n }\r\n\r\n if (!tableRows) {\r\n tableRows = JSON.parse(historicalPricesTable.dataset.tableRows);\r\n } else {\r\n historicalPricesTable.dataset.tableRows = JSON.stringify(tableRows);\r\n }\r\n\r\n let template = '';\r\n\r\n tableRows.filter((item) => {\r\n if (filter === \"nav\") { return item.class === elements.histNav.substring(1)}\r\n if (filter === \"div\") { return item.class === elements.histDiv.substring(1)}\r\n if (filter === \"cap\") { return item.class === elements.histCap.substring(1)}\r\n return true;\r\n }).forEach(function (item, index) {\r\n const itemMarkup = `${moment\r\n .utc(item.date)\r\n .format('MM/DD/YYYY')}${\r\n item.value === '' ? '' : formatCurrency(item.value)\r\n }${item.description}`;\r\n template += itemMarkup;\r\n });\r\n\r\n historicalPricesTable.innerHTML = template;\r\n \r\n}\r\n\r\n/**\r\n * This class helps with rendering the Historical prices and distributions chart.\r\n * It takes data that has been pulled from the API, but the data must be processed first\r\n */\r\nclass LineGraph {\r\n constructor(args) {\r\n this._container = d3.select(args.container);\r\n this._node = args.container;\r\n this._distributionCheckbox = args.distributionCheckbox;\r\n this._data = args.data;\r\n this._assetValues = args.data.values;\r\n this._distributions = args.data.distributions;\r\n this._height = 200;\r\n this._width = this._node.offsetWidth;\r\n this._svg = this._container.append('svg');\r\n this._labelContainer = this._svg.append('g').attr('class', 'label-container');\r\n this._marginContainer = this._svg.append('g').attr('class', 'margin-container');\r\n this._margin = { top: 20, right: 30, bottom: 30, left: 40 };\r\n const that = this;\r\n\r\n this._distributionCheckbox.addEventListener('change', () => {\r\n if (this._distributionCheckbox.checked) {\r\n that._showDistributions();\r\n } else {\r\n that._removeDistributions();\r\n }\r\n });\r\n }\r\n\r\n _setData(data) {\r\n this._data = data;\r\n this._assetValues = data.values;\r\n this._distributions = data.distributions;\r\n }\r\n\r\n /**\r\n * Update the chart data and re-render\r\n * @param {object} data The processed chart data\r\n */\r\n update(data) {\r\n this._setData(data);\r\n this.reRender();\r\n }\r\n\r\n /**\r\n * Clear the chart and render it again using same data\r\n */\r\n reRender() {\r\n this._container.select('svg').remove();\r\n this._svg = this._container.append('svg');\r\n this._width = this._node.offsetWidth;\r\n this._labelContainer = this._svg.append('g').attr('class', 'label-container');\r\n this._marginContainer = this._svg.append('g').attr('class', 'margin-container');\r\n this.render();\r\n }\r\n\r\n _formatCurrency(amount) {\r\n return formatCurrency(amount);\r\n }\r\n\r\n /**\r\n * Render the chart without changing the data\r\n */\r\n render() {\r\n const that = this;\r\n this._marginContainer.attr('transform', 'translate(' + this._margin.left + ',' + this._margin.top + ')');\r\n\r\n this._tooltip = d3.select('.chart-container').append('div').attr('class', 'tooltip').style('opacity', 0);\r\n\r\n this._currentValueTooltip = d3\r\n .select('.chart-container')\r\n .append('div')\r\n .attr('class', 'current-value-tooltip')\r\n .style('opacity', 0);\r\n\r\n const startDate = this._assetValues[0].date,\r\n endDate = this._assetValues[this._assetValues.length - 1].date;\r\n\r\n //does this break IE?\r\n const allValues = this._assetValues.map(function (i) {\r\n return i.value;\r\n });\r\n\r\n this._x = d3.time.scale().range([0, this._width]);\r\n this._y = d3.scale.linear().range([this._height, 0]);\r\n\r\n this._x.domain([startDate, endDate]);\r\n this._y.domain([d3.min(allValues), d3.max(allValues)]);\r\n\r\n const area = d3.svg\r\n .area()\r\n .x(function (d) {\r\n return that._x(d.date);\r\n })\r\n .y0(this._height)\r\n .y1(function (d) {\r\n return that._y(d.value);\r\n });\r\n\r\n const line = d3.svg\r\n .area()\r\n .x(function (d) {\r\n return that._x(d.date);\r\n })\r\n .y(function (d) {\r\n return that._y(d.value);\r\n });\r\n\r\n const xAxis = d3.svg\r\n .axis()\r\n .scale(this._x)\r\n .tickSize(0)\r\n .tickFormat(d3.time.format('%m/%d/%Y'))\r\n .orient('bottom')\r\n .ticks(5);\r\n\r\n const yAxis = d3.svg.axis().scale(this._y).tickSize(2).orient('left').tickFormat(d3.format('$2.2f')).ticks(6);\r\n\r\n const zoomed = function () {\r\n const t = zoom.translate();\r\n const s = zoom.scale();\r\n\r\n let tx = t[0];\r\n const ty = t[1];\r\n tx = Math.min(0, Math.max(that._width * (1 - s), t[0]));\r\n\r\n zoom.translate([tx, ty]);\r\n that._svg.select('g.x').call(xAxis);\r\n\r\n that._svg\r\n .selectAll('circle.circle')\r\n .attr('r', 0)\r\n .attr('cx', function (d) {\r\n return that._x(d.date);\r\n })\r\n .attr('cy', function (d) {\r\n return that._y(d.value);\r\n })\r\n .attr('r', 4);\r\n\r\n that._svg\r\n .select('path.line')\r\n .attr('clip-path', 'url(#clipper)')\r\n .datum(that._assetValues)\r\n .attr('class', 'line')\r\n .attr('d', line);\r\n\r\n that._svg.select('path.area').datum(that._assetValues).attr('d', area);\r\n\r\n if (that._distributionCheckbox.checked) {\r\n that._removeDistributions();\r\n that._showDistributions();\r\n }\r\n };\r\n\r\n const zoom = _d3Zoom.x(this._x).scaleExtent([1, 5]);\r\n\r\n zoom.on('zoom', zoomed);\r\n\r\n this._svg.attr('width', '100%').attr('height', this._height + this._margin.top + this._margin.bottom);\r\n\r\n this._svg.call(zoom);\r\n\r\n const defs = this._svg.append('svg').attr('width', 0).attr('height', 0).append('defs');\r\n\r\n defs\r\n .append('clipPath')\r\n .attr('id', 'clipper')\r\n .append('rect')\r\n .attr('x', 0)\r\n .attr('y', 0)\r\n .attr('width', this._width)\r\n .attr('height', this._height);\r\n\r\n this._marginContainer\r\n .append('g')\r\n .attr('class', 'x axis')\r\n .attr('transform', 'translate(0,' + this._height + ')')\r\n .call(xAxis);\r\n\r\n this._marginContainer.append('g').attr('class', 'y axis').call(yAxis).append('text');\r\n\r\n this._labelContainer.attr('transform', 'translate(' + (this._margin.left + 20) + ',' + this._margin.top + ')');\r\n\r\n this._marginContainer\r\n .append('path')\r\n .datum(this._assetValues)\r\n .attr('clip-path', 'url(#clipper)')\r\n .attr('class', 'line')\r\n .attr('d', line);\r\n\r\n this._marginContainer\r\n .append('path')\r\n .datum(this._assetValues)\r\n .attr('clip-path', 'url(#clipper)')\r\n .attr('class', 'area')\r\n .attr('d', area);\r\n\r\n const mouseG = this._marginContainer.append('g').attr('class', 'mouse-over-effects').attr('height', this._height);\r\n\r\n mouseG.append('circle').attr('class', 'current-value-circle').attr('r', 5).style('opacity', 0);\r\n\r\n mouseG\r\n .append('svg:rect')\r\n .attr('width', this._width)\r\n .attr('height', this._height)\r\n .attr('fill', 'none')\r\n .attr('pointer-events', 'all');\r\n\r\n mouseG\r\n .on('mousemove', function () {\r\n const mouse = _d3Mouse(this);\r\n const xDate = that._x.invert(mouse[0]);\r\n const bisect = d3.bisector(function (d) {\r\n return d.date;\r\n }).right;\r\n const item = that._assetValues[bisect(that._assetValues, xDate)];\r\n\r\n d3.select('.current-value-circle')\r\n .datum(item)\r\n .style('opacity', 1)\r\n .attr('cx', function (d) {\r\n return that._x(d.date);\r\n })\r\n .attr('cy', function (d) {\r\n return that._y(d.value);\r\n });\r\n\r\n that._currentValueTooltip\r\n .html(that._formatCurrency(item.value) + '
' + moment.utc(item.date).format('MM/DD/YYYY'))\r\n .style('opacity', 1)\r\n .style('left', that._x(item.date) + 50 + 'px')\r\n .style('top', that._y(item.value) + 160 + 'px');\r\n })\r\n .on('mouseout', function () {\r\n that._currentValueTooltip.transition().duration(500).style('opacity', 0);\r\n\r\n d3.select('.current-value-circle').transition().duration(500).style('opacity', 0);\r\n });\r\n\r\n if (this._distributionCheckbox?.checked) {\r\n this._showDistributions();\r\n }\r\n\r\n this._renderTable();\r\n }\r\n\r\n\r\n _renderTable() {\r\n const historyTableSelect = document.querySelector(elements.historyTableSelect);\r\n if (historyTableSelect) {\r\n historyTableSelect.value = 'all';\r\n }\r\n\r\n const tableRows = [];\r\n const that = this;\r\n\r\n this._distributions.forEach(function (item) {\r\n if (typeof item.value !== 'undefined') {\r\n let desc = '';\r\n let distclass = '';\r\n if (item.type === 0) {\r\n desc = 'Pay / Reinvest Date - Dividends';\r\n distclass = 'hist-DIV';\r\n\r\n tableRows.push({\r\n date: moment.utc(item.dateRecord).format('MM/DD/YYYY'),\r\n value: '',\r\n description: 'Record Date - Dividends',\r\n class: 'hist-DIV'\r\n });\r\n } else if (item.type === 1) {\r\n desc = 'Pay / Reinvest Date - Long Term Capital Gain';\r\n distclass = 'hist-CAP';\r\n\r\n tableRows.push({\r\n date: moment.utc(item.dateRecord).format('MM/DD/YYYY'),\r\n value: '',\r\n description: 'Record Date - Long Term Capital Gain',\r\n class: 'hist-CAP'\r\n });\r\n } else if (item.type === 2) {\r\n desc = 'Pay / Reinvest Date - Short Term Capital Gain';\r\n distclass = 'hist-CAP';\r\n\r\n tableRows.push({\r\n date: moment.utc(item.dateRecord).format('MM/DD/YYYY'),\r\n value: '',\r\n description: 'Record Date - Short Term Capital Gain',\r\n class: 'hist-CAP'\r\n });\r\n }\r\n\r\n tableRows.push({\r\n date: moment.utc(item.date).format('MM/DD/YYYY'),\r\n value: item.rate,\r\n description: desc,\r\n class: distclass\r\n });\r\n }\r\n });\r\n\r\n this._assetValues.forEach(function (v) {\r\n tableRows.push({\r\n date: v.date,\r\n value: v.value,\r\n description: 'NAV',\r\n class: 'hist-NAV'\r\n });\r\n });\r\n\r\n tableRows.sort(function (a, b) {\r\n return new Date(b.date) - new Date(a.date);\r\n });\r\n\r\n renderHistoricalPricesTable(\"all\", tableRows);\r\n }\r\n\r\n _showDistributions() {\r\n const container = this._marginContainer;\r\n const circleContainer = container.append('g').attr('class', 'circles');\r\n\r\n const that = this;\r\n\r\n this._distributions.forEach(function (item) {\r\n if (typeof item.value !== 'undefined') {\r\n const label = `Value: ${that._formatCurrency(item.value)}
Dividend: ${that._formatCurrency(\r\n item.rate\r\n )}
${moment.utc(item.date).format('MM/DD/YYYY')}`;\r\n const data = {\r\n date: item.date,\r\n value: item.value,\r\n rate: item.rate,\r\n label: label\r\n };\r\n that._renderDistribution(circleContainer, data);\r\n }\r\n });\r\n }\r\n\r\n _removeDistributions() {\r\n const container = this._marginContainer;\r\n container.selectAll('.circles .distribution-circle').remove();\r\n }\r\n\r\n _renderDistribution(container, data) {\r\n const that = this;\r\n container\r\n .datum(data)\r\n .append('circle')\r\n .attr('clip-path', 'url(#clipper)')\r\n .attr('class', 'distribution-circle')\r\n .attr('cx', function (d) {\r\n return that._x(d.date);\r\n })\r\n .attr('cy', function (d) {\r\n return that._y(d.value);\r\n })\r\n .attr('r', 5)\r\n .on('mouseover', function (d) {\r\n that._tooltip.transition().duration(200).style('opacity', 0.9);\r\n that._tooltip\r\n .html(d.label)\r\n .style('left', that._x(d.date) + 50 + 'px')\r\n .style('top', that._y(d.value) + 20 + 'px');\r\n })\r\n .on('mouseout', function () {\r\n that._tooltip.transition().duration(500).style('opacity', 0);\r\n });\r\n }\r\n}\r\n\r\nexport {\r\n LineGraph,\r\n renderHistoricalPricesTable\r\n}","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 05/11/2022 ZSunOo 77752 Initial Create\r\n// 09/01/2022 BBARRON 89603 Re-render the lower table with same data when dropdown changes.\r\n// Needed to completely remove irrelevant rows from the DOM for correct styling\r\n// 09/12/2022 BBARRON 89878 If chart area is not initially visible, don't render it.\r\n// But check to see if the chart becomes visible on window resize. \r\n// 12/09/2022 BBARRON 89878 Fix the way the chart checks whether it has already been loaded\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport d3 from 'd3';\r\nimport Pikaday from 'pikaday';\r\nimport moment from 'moment';\r\nimport { elements } from './elements';\r\nimport { Data, LineGraph, renderHistoricalPricesTable } from './classes';\r\n\r\nconst API_BASE = `/api/sitecore/HistoricalPricesDistributions`;\r\n\r\nconst data = new Data();\r\n/**\r\n * Gets the start and end dates for a given range measured in the given number of months.\r\n * @param {number} numberOfMonths The number of months in the date range\r\n * @returns {object} An object with start and end date properties\r\n */\r\nconst getDatesByMonthAgo = function (numberOfMonths) {\r\n const now = new Date();\r\n return {\r\n start: moment.utc(now).subtract(numberOfMonths, 'months').format('MM/DD/YYYY'),\r\n end: moment.utc(now).format('MM/DD/YYYY')\r\n };\r\n};\r\n\r\n// onLoad function\r\nexport const loadScripts = (snippetData, maxData) => {\r\n\r\n const container = document.querySelectorAll(elements.historicalPricesContainer);\r\n if(container.length === 0) {\r\n // Page does not contain historical prices component.\r\n return;\r\n }\r\n\r\n /**\r\n * Gets the api endpoint url for the given start and end dates\r\n * @param {string} startDate The start date of the desired data \r\n * @param {string} endDate The end date of the desired data\r\n * @returns \r\n */\r\n const endPointUrl = function (startDate, endDate) {\r\n const ticker = document.querySelector(elements.historicalPricesContainer).getAttribute('data-ticker');\r\n if (startDate && endDate) {\r\n return `${API_BASE}/Get?ticker=${ticker}&from=${startDate}&to=${endDate}`;\r\n } else {\r\n return `${API_BASE}/Get?ticker=${ticker}`;\r\n }\r\n };\r\n\r\n /**\r\n * Gets the mock/dev data by type\r\n * @param {string} type (snippetData|maxData) The type of data to get \r\n * @returns \r\n */\r\n const getDevData = type => {\r\n switch (type) {\r\n case 'snippetData':\r\n return snippetData;\r\n case 'maxData':\r\n return maxData;\r\n default:\r\n return;\r\n }\r\n };\r\n\r\n const isDev = Boolean(snippetData) && Boolean(maxData);\r\n\r\n /**\r\n * Check whether the chart is loaded or not\r\n * @returns true if the chart container is not empty\r\n */\r\n const isChartLoaded = () => {\r\n const container = document.querySelector(elements.chartContainer);\r\n return container.innerHTML !== '';\r\n }\r\n\r\n /**\r\n * Check whether to render the graph/table every 2 seconds.\r\n * If the container is visible when checked, render the table and stop checking.\r\n */\r\n function checkRenderTable(isDev) {\r\n\r\n /**\r\n * If the container is visible, load the chart and return true. Otherwise return false.\r\n * @returns true if chart was loaded\r\n */\r\n var loadChartIfContainerVisible = (evt) => {\r\n let containerInner = document.querySelector(elements.historicalPricesContainerInner);\r\n if(isChartLoaded()) {\r\n if(evt && evt.type === \"resize\") {\r\n window.removeEventListener(\"resize\", loadChartIfContainerVisible, false);\r\n }\r\n return false;\r\n }\r\n if (isElementVisible(containerInner)) {\r\n initialize(isDev);\r\n return true;\r\n }\r\n return false;\r\n };\r\n\r\n\r\n var chartWasLoadedOnFirstTry = loadChartIfContainerVisible();\r\n if(!chartWasLoadedOnFirstTry) {\r\n // If the chart was not loaded of first try, wait for user to resize the browser\r\n window.addEventListener(\"resize\", loadChartIfContainerVisible, false);\r\n }\r\n \r\n }\r\n\r\n function isElementVisible(element) {\r\n if(!element) {\r\n return false;\r\n }\r\n let display = window.getComputedStyle(element, null).display;\r\n return display !== \"none\";\r\n }\r\n\r\n\r\n /**\r\n * Render and initialize the chart and table\r\n */\r\n function initialize(isDev) {\r\n // to / from dates\r\n const fromPicker = new Pikaday({\r\n field: document.querySelector(elements.historicalFromDate),\r\n format: 'M/D/YYYY'\r\n });\r\n\r\n const toPicker = new Pikaday({\r\n field: document.querySelector(elements.historicalToDate),\r\n format: 'M/D/YYYY'\r\n });\r\n\r\n let {selectorDates, selectorUrls} = getSelectorUrls(isDev);\r\n\r\n renderLineGraph(isDev, selectorUrls)\r\n .then((graph) => {\r\n activateControls(graph, selectorUrls, fromPicker, toPicker);\r\n activateHistoryTable(selectorDates, fromPicker, toPicker);\r\n\r\n // In the event the window is resized, re-render the chart to ensure it is the appropriate width at all screen sizes\r\n window.addEventListener('resize', (evt) => {\r\n window.requestAnimationFrame(() => {\r\n graph.reRender();\r\n });\r\n });\r\n })\r\n .catch(err => {\r\n console.error(\"Error rendering historical prices chart\", err);\r\n });\r\n\r\n\r\n }\r\n\r\n\r\n function getSelectorUrls(isDev) {\r\n let selectorDates = '';\r\n let selectorUrls = [\r\n {\r\n selector: '.one-month',\r\n url: function () {\r\n selectorDates = getDatesByMonthAgo(1);\r\n const { start, end } = selectorDates;\r\n if (isDev) return getDevData('snippetData');\r\n return endPointUrl(start, end);\r\n }\r\n },\r\n {\r\n selector: '.three-month',\r\n url: function () {\r\n selectorDates = getDatesByMonthAgo(3);\r\n const { start, end } = selectorDates;\r\n if (isDev) return getDevData('snippetData');\r\n return endPointUrl(start, end);\r\n }\r\n },\r\n {\r\n selector: '.six-month',\r\n url: function () {\r\n selectorDates = getDatesByMonthAgo(6);\r\n const { start, end } = selectorDates;\r\n if (isDev) return getDevData('snippetData');\r\n return endPointUrl(start, end);\r\n }\r\n },\r\n {\r\n selector: '.twelve-month',\r\n url: function () {\r\n selectorDates = getDatesByMonthAgo(12);\r\n const { start, end } = selectorDates;\r\n if (isDev) return getDevData('snippetData');\r\n return endPointUrl(start, end);\r\n }\r\n },\r\n {\r\n selector: '.thirty-six-month',\r\n url: function () {\r\n selectorDates = getDatesByMonthAgo(36);\r\n const { start, end } = selectorDates;\r\n if (isDev) return getDevData('snippetData');\r\n return endPointUrl(start, end);\r\n }\r\n },\r\n {\r\n selector: '.sixty-month',\r\n url: function () {\r\n selectorDates = getDatesByMonthAgo(60);\r\n const { start, end } = selectorDates;\r\n if (isDev) return getDevData('snippetData');\r\n return endPointUrl(start, end);\r\n }\r\n },\r\n {\r\n selector: '.all',\r\n url: function () {\r\n selectorDates = '';\r\n if (isDev) return getDevData('maxData');\r\n return endPointUrl();\r\n }\r\n }\r\n ];\r\n\r\n return {selectorDates, selectorUrls};\r\n }\r\n\r\n \r\n\r\n \r\n /**\r\n * Renders the initial line graph\r\n * @param {boolean} isDev Whether to render in DEV mode or live mode\r\n * @param {object[]} selectorUrls A list of selectors and urls for each time series button\r\n */\r\n async function renderLineGraph(isDev, selectorUrls) {\r\n // default\r\n return new Promise ((resolve, reject) => {\r\n let graph = null;\r\n const container = document.querySelector(elements.chartContainer);\r\n if (container.innerHTML === '') {\r\n if (isDev) {\r\n const renderData = data.process(getDevData('snippetData'));\r\n graph = new LineGraph({\r\n container: document.querySelector(elements.chartContainer),\r\n data: renderData,\r\n distributionCheckbox: document.querySelector(elements.distributionCheckbox)\r\n });\r\n\r\n graph.render();\r\n resolve(graph);\r\n // hacky way to render the graph\r\n setTimeout(() => {\r\n document.querySelector('.one-month').click();\r\n }, 1000);\r\n } else {\r\n d3.json(selectorUrls[0].url(), function (json) {\r\n graph = new LineGraph({\r\n container: document.querySelector(elements.chartContainer),\r\n data: data.process(json),\r\n distributionCheckbox: document.querySelector(elements.distributionCheckbox)\r\n });\r\n graph.render();\r\n resolve(graph);\r\n });\r\n }\r\n } else {\r\n reject('not renedering graph becase container is not empty');\r\n }\r\n });\r\n }\r\n\r\n \r\n /**\r\n * Removes active state on all time period buttons (1M, 3M, 1Y, etc.)\r\n */\r\n const resetButtonContainer = function () {\r\n const buttonContainer = document.querySelector(elements.timePeriodList);\r\n buttonContainer.querySelectorAll('li').forEach(li => li.classList.remove('active'));\r\n };\r\n\r\n\r\n /**\r\n * Wires up the click event on the given date-range button\r\n * @param {HtmlElement} button The button to activate\r\n * @param {*} url The api url to call\r\n * @param {*} isDev Whether or not this is DEV mode\r\n * @param {*} graph The graph to update\r\n */\r\n function activateDateButton(button, url, isDev, graph) {\r\n button.addEventListener('click', e => {\r\n e.preventDefault();\r\n resetButtonContainer();\r\n button.parentNode.classList.add('active');\r\n\r\n if (isDev) {\r\n const updateData = data.process(url);\r\n graph.update(updateData);\r\n } else {\r\n d3.json(url, function (json) {\r\n graph.update(data.process(json));\r\n });\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Activates the line graph controls\r\n * @param {LineGraph} graph The graph to update when controls are used\r\n * @param {object} selectorUrls A list of {selector, url} objects\r\n * @param {DatePicker} fromPicker\r\n * @param {DatePicker} toPicker\r\n */\r\n function activateControls(graph, selectorUrls, fromPicker, toPicker) {\r\n selectorUrls.forEach(function (obj) {\r\n const element = document.querySelector(obj.selector);\r\n activateDateButton(element, obj.url(), isDev, graph);\r\n });\r\n\r\n const showButton = document.querySelector(elements.updateHistoryButton);\r\n showButton.addEventListener('click', () => {\r\n let [start, end] = [fromPicker.toString(), toPicker.toString()];\r\n if (!start || !end) {\r\n alert('Please select a date range');\r\n return;\r\n }\r\n\r\n if (isDev) {\r\n const updateData = start && end ? getDevData('snippetData') : getDevData('maxData');\r\n graph.update(data.process(updateData));\r\n } else {\r\n d3.json(endPointUrl(start, end), function (json) {\r\n graph.update(data.process(json));\r\n });\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Activate the history table and controls below the graph\r\n * @param {object} selectorDates \r\n */\r\n function activateHistoryTable(selectorDates, fromPicker, toPicker) {\r\n const showHistoryTable = document.querySelector(elements.showHistoryTable);\r\n showHistoryTable.addEventListener('click', () => {\r\n document.querySelector(elements.historicalPricesContainerTable).classList.toggle('hide');\r\n });\r\n\r\n const downloadExcelButton = document.querySelector(elements.downloadExcelButton);\r\n if (downloadExcelButton) {\r\n downloadExcelButton.addEventListener('click', () => {\r\n let [start, end] = [fromPicker.toString(), toPicker.toString()];\r\n const ticker = document.querySelector(elements.historicalPricesContainer).getAttribute('data-ticker');\r\n const filter = document.querySelector(elements.historyTableSelect).value;\r\n\r\n if (start === '' || end === '') {\r\n start = selectorDates.start;\r\n end = selectorDates.end;\r\n }\r\n\r\n if (!isDev) {\r\n // for production\r\n let path;\r\n if (start && end) {\r\n path = `${API_BASE}/DownloadExcel?ticker=${ticker}&from=${start}&to=${end}&filter=${filter}`;\r\n } else {\r\n path = `${API_BASE}/DownloadExcel?ticker=${ticker}&filter=${filter}`;\r\n }\r\n window.open(path, '_blank');\r\n }\r\n });\r\n }\r\n\r\n const downloadCsvButton = document.querySelector(elements.downloadCsvButton);\r\n if (downloadCsvButton) {\r\n downloadCsvButton.addEventListener('click', () => {\r\n let [start, end] = [fromPicker.toString(), toPicker.toString()];\r\n const ticker = document.querySelector(elements.historicalPricesContainer).getAttribute('data-ticker');\r\n const filter = document.querySelector(elements.historyTableSelect).value;\r\n\r\n if (start === '' || end === '') {\r\n start = selectorDates.start;\r\n end = selectorDates.end;\r\n }\r\n\r\n if (isDev) {\r\n // for dev\r\n if (start && end) {\r\n alert(`get filtered excel items. ticker: ${ticker}, filter: ${filter}`);\r\n } else {\r\n alert('get max excel items');\r\n }\r\n } else {\r\n // for production\r\n let path;\r\n if (start && end) {\r\n path = `${API_BASE}/DownloadCsv?ticker=${ticker}&from=${start}&to=${end}&filter=${filter}`;\r\n } else {\r\n path = `${API_BASE}/DownloadCsv?ticker=${ticker}&filter=${filter}`;\r\n }\r\n window.open(path, '_blank');\r\n }\r\n });\r\n }\r\n\r\n const historyTableSelect = document.querySelector(elements.historyTableSelect);\r\n if (historyTableSelect) {\r\n historyTableSelect.addEventListener('change', e => {\r\n const { value } = e.target;\r\n // Re-render the table with same data. Completely remove irrelevant rows from the DOM for correct styling\r\n renderHistoricalPricesTable(value);\r\n });\r\n }\r\n }\r\n\r\n checkRenderTable(isDev);\r\n};\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 05/11/2022 ZSunOo 77752 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { loadScripts } from './loadScripts';\r\nimport { destroyScripts } from './destroyScripts';\r\n\r\nexport const priceDistributionScripts = {\r\n loadScripts,\r\n destroyScripts\r\n};\r\n","import { elements } from './elements';\r\n\r\nexport const destroyScripts = () => {\r\n const chartContainer = document.querySelector(elements.chartContainer);\r\n if (chartContainer) {\r\n chartContainer.innerHTML = '';\r\n }\r\n};\r\n","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 11/02/2020 JJacob 49830 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const toggleRadioScripts = {\r\n loadScripts: () => {\r\n /**\r\n * EventListener callback which fires when a radio button is clicked. Identifies\r\n * the clicked radio button and sets the appropriate \"visibility\" classes on the\r\n * forms to either show/hide based on active toggle\r\n *\r\n * @param {string} id Identifier for the selected radio\r\n */\r\n const handleRadioChange = id => {\r\n if (id === 'one') {\r\n document.querySelector('.gs-form-cta-organization').classList.remove('--selected');\r\n document.querySelector('.gs-form-cta-individual').classList.add('--selected');\r\n } else if (id === 'two') {\r\n document.querySelector('.gs-form-cta-individual').classList.remove('--selected');\r\n document.querySelector('.gs-form-cta-organization').classList.add('--selected');\r\n }\r\n };\r\n\r\n if (document.getElementById('gs_form_cta_radio_individual')) {\r\n document\r\n .getElementById('gs_form_cta_radio_individual')\r\n .addEventListener('change', () => handleRadioChange('one'));\r\n document\r\n .getElementById('gs_form_cta_radio_organization')\r\n .addEventListener('change', () => handleRadioChange('two'));\r\n }\r\n }\r\n};\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 09/12/2023 BBARRON 113813 Initial create\r\n// 09/20/2023 BBARRON 114362 Only load retirement preparedness tool once from data attribute\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const retirementPreparednessScripts = {\r\n loadScripts: () => {\r\n\r\n const iframeId = 'vccalcfrm';\r\n \r\n /**\r\n * Ensure that the message sent to this browser window pertains to the retirement preparedness tool\r\n * @param {*} evt The PostMessage event\r\n * @returns True if the iframe is on the page and the message origin matches the iframe src\r\n */\r\n const validateEventOrigin = (evt) => {\r\n const iframe = document.getElementById(iframeId);\r\n if (!iframe) {\r\n return false;\r\n }\r\n\r\n const iframeSrc = iframe.src.toLowerCase();\r\n const eventOrigin = evt.origin.toLowerCase();\r\n\r\n if (!iframeSrc.includes(eventOrigin)) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Handle PostMessage event sent from iframe to current browser window. Only respond to resize messages\r\n * @param {*} evt \r\n */\r\n const handleIframeMessage = (evt) => {\r\n if (!validateEventOrigin(evt)) {\r\n return;\r\n }\r\n \r\n var msg = evt.data.message || 'unknown msg'\r\n if (msg === 'resizeht') {\r\n resizeIframe(evt.data.ht - 0);\r\n }\r\n }\r\n\r\n /**\r\n * Resizes the iframe to the given new height\r\n * @param {number} newHeight The new iframe height\r\n */\r\n const resizeIframe = (newHeight) => {\r\n var iframe = document.getElementById(iframeId);\r\n iframe.style.height = newHeight + 'px';\r\n }\r\n\r\n // Start listening for iframe messages early\r\n window.addEventListener('message', handleIframeMessage, false);\r\n \r\n var iframe = document.getElementById(iframeId);\r\n if (iframe) {\r\n var iframeUrl = iframe.dataset.url;\r\n iframe.src = iframeUrl;\r\n }\r\n }\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 11/02/2020 JJacob 49830 Initial Create\r\n// 03/28/2022 BBARRON 82090 Refactored for readability\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const siteAnimations = {\r\n loadScripts: () => {\r\n\r\n // All the elements to be animated\r\n let elements;\r\n\r\n // The height of the viewport\r\n let viewportHeight;\r\n\r\n /**\r\n * Determines whether the top of the given element is further down the page than the bottom of the viewport\r\n * @param {*} el The element to be animated\r\n * @returns True if element is not below the viewport\r\n */\r\n function isBelowViewport(el) {\r\n var elementYCoordinate = el.getBoundingClientRect().top; // Element's y coordinate relative to viewport top. (Lower position on screen is higher y coordinate)\r\n return elementYCoordinate > viewportHeight;\r\n } \r\n\r\n /**\r\n * Activates the animation if not yet activated\r\n * @param {*} el The element to be animated\r\n */\r\n function activateAnimation(el) {\r\n if(el.classList.contains('gs-animate-init')) {\r\n el.classList.add('gs-animateIn-bottom');\r\n el.classList.remove('gs-animate-init');\r\n }\r\n }\r\n\r\n /**\r\n * Checks the position of all elements to be animated and \r\n * activates the animation if they have scrolled into view\r\n */\r\n function checkPosition() {\r\n for (let i = 0; i < elements.length; i++) {\r\n const element = elements[i];\r\n if (!isBelowViewport(element)) {\r\n activateAnimation(element);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Initialize animated elements\r\n */\r\n function init() {\r\n viewportHeight = window.innerHeight;\r\n elements = document.querySelectorAll('.gs-container-inner');\r\n elements.forEach(element => {\r\n if (!element.classList.contains('gs-animate-false') && isBelowViewport(element)) {\r\n element.classList.add('gs-animate-init');\r\n }\r\n });\r\n checkPosition();\r\n }\r\n\r\n window.addEventListener('scroll', checkPosition);\r\n window.addEventListener('click', checkPosition);\r\n window.addEventListener('resize', init);\r\n\r\n init();\r\n }\r\n};\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 08/03/2023 BBARRON 110687 Initial create\r\n// 08/08/2023 BBARRON 111013 Default all anchor links to smooth scrolling without having to add a css class\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { scrollToAnchorInUrl } from '../utils/scroll-utils';\r\n\r\n/**\r\n * We change the default behavior for anchor link clicks. The user will now smoothly scroll to the anchor target, leaving room for the sticky header.\r\n * \r\n * There are two css classes that can be added to the anchor link to get around this new custom behavior:\r\n * * gs-anchor--default will scroll the user instantly to the anchor using the browser-s default behavior, not accounting for sticky headers\r\n * This might be needed if the sticky header is ever hidden on a specific page or for a specific business reason\r\n * * gs-anchor--instant will scroll the user instantly to the anchor, but it will account for sticky header height\r\n * This will be used most often when the new custom behavior is overridden\r\n */\r\nexport const smoothScrollAnchorLinkScripts = {\r\n loadScripts: () => {\r\n\r\n\r\n // We listen for the click at the document level so we can get anchor links that were not yet on the page when this script loads\r\n document.addEventListener(\"click\", function(evt) {\r\n\r\n // We make sure the click was on an anchor link\r\n if (evt.target.tagName !== \"A\" || !evt.target.getAttribute(\"href\") || !evt.target.getAttribute(\"href\").startsWith(\"#\")) {\r\n return;\r\n }\r\n\r\n console.log(evt.target, evt.target.classList);\r\n\r\n // We allow content authors to break out of this custom scrolling behavior by adding a specific css class to anchor links\r\n if(evt.target.classList.contains('gs-anchor--default')) {\r\n return;\r\n }\r\n\r\n evt.preventDefault();\r\n const url = evt.target.href;\r\n\r\n // We allow content authors to specify that the user should scroll instantly to an anchor, but still account for sticky header with this css class\r\n if(evt.target.classList.contains('gs-anchor--instant')) {\r\n scrollToAnchorInUrl(url, {behavior: 'instant'});\r\n return;\r\n }\r\n\r\n // If none of those special css classes are in place the default behavior for anchor links is to smooth scroll. No special css class needed\r\n scrollToAnchorInUrl(url, {behavior: 'smooth'});\r\n }, false);\r\n }\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/10/2020 HJordan Initial create\r\n// 04/18/2022 BBARRON 83828 Add site param to toggle between brand and funds search\r\n// 01/12/2023 BBARRON 97891 Add ability to hide revealed tags\r\n// 01/18/2023 BBARRON 97895 Add ability to select multiple tags, only hide unselected tags\r\n// 01/23/2023 BBARRON 98536 Remove excessive console logging\r\n// 02/01/2023 BBARRON 99334 Don't activate apply button until a tag is clicked\r\n// 02/07/2023 BBARRON 99963 Make sure all tag gets selected\r\n// 06/01/2023 GCASEY 106291 Remove apply button and add automatic search when a tag is clicked \r\n// 08/14/2024 GCASEY 137177 Update server side tag toggling to use updated browser APIs \r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nimport { getInitialSearchParams, setTagParam } from '../utils/search-utils';\r\nimport { searchContentAndUpdateResults } from '../content-search-results/ContentSearchResults';\r\n\r\nconst showMoreTagId = 'gs-tag-filter-show-more';\r\nconst showLessTagId = 'gs-tag-filter-show-less';\r\nconst applyTagsId = 'gs-tag-filter-apply-tags';\r\n\r\nconst tagContainerId = 'gs-tag-filter-container';\r\nconst tagContainerCollapsedClass = 'gs-tag-filters-listGroup--collapsed';\r\n\r\nconst tagClass = 'gs-tag-filter-btn';\r\nconst tagHiddenClass = 'gs-tag-filter-btn--hidden';\r\nconst tagSelectedClass = 'gs-tag-filter-btn--selected';\r\nconst resultsSectionId = 'gs-content-search-results';\r\n\r\nconst clientSideFilterID = 'gs-tag-filters-client-side';\r\nconst serverSideFilterID = 'gs-tag-filters-server-side';\r\n\r\nconst getClientSideTagsGroup = () => {\r\n const clientSideTagsGroup = document.getElementById(clientSideFilterID);\r\n if (clientSideTagsGroup) {\r\n return {\r\n component: clientSideTagsGroup,\r\n tags: Array.from(clientSideTagsGroup.querySelectorAll('button.gs-tag-filter-btn:not(.gs-tag-filter-btn--special)')),\r\n allTag: findTag('all', clientSideTagsGroup),\r\n showMoreTag: document.getElementById(showMoreTagId),\r\n showLessTag: document.getElementById(showLessTagId),\r\n applyButton: document.getElementById(applyTagsId)\r\n };\r\n }\r\n return null;\r\n}\r\n\r\nconst getServerSideTagsGroup = () => {\r\n const serverSideTagsGroup = document.getElementById(serverSideFilterID);\r\n if(serverSideTagsGroup) {\r\n return {\r\n component: serverSideTagsGroup,\r\n tags: Array.from(serverSideTagsGroup.querySelectorAll('button.gs-tag-filter-btn:not(.gs-tag-filter-btn--special)')),\r\n allTag: findTag('all', serverSideTagsGroup),\r\n showMoreTag: document.getElementById(showMoreTagId),\r\n showLessTag: document.getElementById(showLessTagId),\r\n applyButton: document.getElementById(applyTagsId),\r\n site: serverSideTagsGroup.dataset.site || 'brand'\r\n };\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Gets all selected tags as an array of strings\r\n * @returns {string[]} All selected tag names\r\n */\r\nexport const getAllSelectedTags = () => {\r\n return getSelectedTags(true).map(element => element.dataset.tag);\r\n};\r\n\r\n/**\r\n * If the all tag is selected, return that tag. If not, return all the selected tags\r\n * @returns The selected tag(s)\r\n */\r\nconst getSelectedTags = (includeAllTag) => {\r\n const allTag = findTag('all');\r\n let selectedTags = Array.from(document.getElementsByClassName(tagSelectedClass));\r\n\r\n // remove special tags like all/more/less/apply\r\n selectedTags = selectedTags.filter(tag => !tag.classList.contains('gs-tag-filter-btn--special'));\r\n\r\n // include the all tag if desired\r\n if(includeAllTag && allTag.classList.contains(tagSelectedClass)) {\r\n selectedTags.push(allTag);\r\n }\r\n\r\n return selectedTags;\r\n}\r\n\r\n\r\n/**\r\n * Gets all non-special tags (the all tag, show more, show less, and apply)\r\n * @returns The tags\r\n */\r\nconst getAllTags = () => {\r\n let allTags = Array.from(document.getElementsByClassName(tagClass));\r\n allTags = allTags.filter(tag => !tag.classList.contains('gs-tag-filter-btn--special'));\r\n return allTags;\r\n}\r\n\r\n/**\r\n * Finds a tag by name, includes special tags\r\n * @param {string} tag The tag name\r\n * @returns The tag or null\r\n */\r\nconst findTag = (tag, container) => {\r\n container = container || document;\r\n return document.querySelector(`.${tagClass}[data-tag=\"${tag.toLowerCase()}\"]`)\r\n}\r\n\r\n/**\r\n * Determines which tags to hide when the less button is clicked.\r\n * If\r\n */\r\nconst getTagsToHide = () => {\r\n const container = document.getElementById(tagContainerId);\r\n const numTagsToKeep = parseInt(container.dataset.startingTagNumber);\r\n let allTags = Array.from(document.getElementsByClassName(tagClass));\r\n allTags = allTags.filter(tag => !tag.classList.contains('gs-tag-filter-btn--special'));\r\n\r\n let selectedTags = getSelectedTags();\r\n let unselectedTags = allTags.filter(tag => !selectedTags.some(t => t == tag));\r\n // If you already have enough tags just among the selected ones, you can hide all the unselected ones\r\n if(selectedTags.lenght >= numTagsToKeep) {\r\n return unselectedTags;\r\n }\r\n\r\n // keep all selected tags and the first n unselected tags until you have in the list\r\n let tagsToKeep = [...selectedTags];\r\n unselectedTags.forEach(tag => {\r\n if(tagsToKeep.length < numTagsToKeep) {\r\n tagsToKeep.push(tag);\r\n }\r\n });\r\n\r\n // Return the list of all tags not on the tags to keep list\r\n return unselectedTags.filter(tag => !tagsToKeep.some(t => t == tag));\r\n}\r\n\r\n/**\r\n * Function which accepts an element, and a toggle flag and\r\n * toggles the elements \"Hidden\" classes based on the toggle\r\n *\r\n * @param {Node} element element to be manipulated\r\n * @param {boolean} toggle flag to identify hidden or visible\r\n */\r\nconst toggleTagHidden = (element, toggle) => {\r\n if (toggle) {\r\n element.classList.add(tagHiddenClass);\r\n } else {\r\n element.classList.remove(tagHiddenClass);\r\n }\r\n};\r\n\r\n/**\r\n * Handles selection of each tag\r\n *\r\n * @param {Node} element element to be manipulated\r\n */\r\nconst handleTagSelection = (element) => {\r\n\r\n // If you click the 'all' tag, deselect all other tags\r\n if(element.dataset.tag === 'all') {\r\n getAllTags().forEach(tag => tag.classList.remove(tagSelectedClass));\r\n element.classList.add(tagSelectedClass);\r\n updateLessButtonVisibility();\r\n return;\r\n }\r\n\r\n // Otherwise toggle the tag\r\n let wasSelected = element.classList.contains(tagSelectedClass);\r\n if(!wasSelected) {\r\n selectTag(element);\r\n } else {\r\n // when deselecting the last selected tag, you may need to select the 'all' tag\r\n deselectTag(element);\r\n }\r\n};\r\n\r\n/**\r\n * Marks the given tag as selected, \r\n * if you provide a tag name instead of tag element, \r\n * an attempt will be made to find the correct element.\r\n * @param {string|HtmlElement} element The tag element or tag name to select\r\n */\r\nexport const selectTag = (element) => {\r\n if(typeof element === \"string\") {\r\n element = findTag(element);\r\n }\r\n let allTag = findTag('all');\r\n element.classList.add(tagSelectedClass);\r\n allTag.classList.remove(tagSelectedClass);\r\n\r\n // Determine whether the less button should be visible\r\n updateLessButtonVisibility();\r\n}\r\n\r\nexport const selectAllTag = () => {\r\n let allTag = findTag('all');\r\n allTag.classList.add(tagSelectedClass);\r\n getAllTags().forEach(tag => tag.classList.remove(tagSelectedClass));\r\n}\r\n\r\nconst deselectTag = (element) => {\r\n let allTag = findTag('all');\r\n element.classList.remove(tagSelectedClass);\r\n let selectedTags = getSelectedTags(false);\r\n\r\n // if no tags are selected after this tag gets deselected, then select the \"all\" tag\r\n if(selectedTags.length === 0) {\r\n allTag.classList.add(tagSelectedClass);\r\n }\r\n\r\n // Determine whether the less button should be visible\r\n updateLessButtonVisibility();\r\n}\r\n\r\nconst updateLessButtonVisibility = () => {\r\n const tagContainer = document.getElementById(tagContainerId);\r\n const showLessButton = document.getElementById(showLessTagId);\r\n\r\n if (tagContainer.classList.contains(tagContainerCollapsedClass)) {\r\n showLessButton.classList.add(tagHiddenClass);\r\n return;\r\n }\r\n\r\n let tagsToHide = getTagsToHide();\r\n if(tagsToHide.length === 0) {\r\n showLessButton.classList.add(tagHiddenClass);\r\n return;\r\n }\r\n\r\n showLessButton.classList.remove(tagHiddenClass);\r\n}\r\n\r\n\r\n/**\r\n * Function which accepts a list of tags which are currently hidden, and\r\n * toggles them to be revealed\r\n *\r\n * @param {Array} tagsToShow list of hidden Tag nodes\r\n */\r\nconst displayHiddenTags = tagsToShow => {\r\n if (tagsToShow && tagsToShow.length > 0) {\r\n for (let i = 0; i < tagsToShow.length; i++) {\r\n toggleTagHidden(tagsToShow[i], false);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Function which accepts a list of tags which are currently revealed, and\r\n * toggles them to be hidden\r\n *\r\n * @param {Array} tagsToHide list of hidden Tag nodes\r\n */\r\nconst hideTags = tagsToHide => {\r\n if (tagsToHide && tagsToHide.length > 0) {\r\n for (let i = 0; i < tagsToHide.length; i++) {\r\n toggleTagHidden(tagsToHide[i], true);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Function which targets any tags marked with \"hidden\" classes to be\r\n * updated so that they are revealed\r\n *\r\n * @param {EventTarget} event event passed by the listener\r\n */\r\nexport const showAllTags = event => {\r\n if (event) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }\r\n\r\n const allHiddenTags = Array.from(document.getElementsByClassName(tagHiddenClass));\r\n const tagContainer = document.getElementById(tagContainerId);\r\n const showMoreButton = document.getElementById(showMoreTagId);\r\n const showLessButton = document.getElementById(showLessTagId);\r\n\r\n tagContainer.classList.remove(tagContainerCollapsedClass);\r\n showMoreButton.classList.add(tagHiddenClass);\r\n showLessButton.classList.remove(tagHiddenClass);\r\n\r\n if (allHiddenTags) {\r\n displayHiddenTags(allHiddenTags);\r\n }\r\n};\r\n\r\n/**\r\n * Function which targets any tags marked with \"revealed\" classes to be\r\n * updated so that they are hidden\r\n *\r\n * @param {EventTarget} event event passed by the listener\r\n */\r\nexport const hideExtraTags = event => {\r\n if (event) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }\r\n\r\n const tagsToHide = getTagsToHide();\r\n if(tagsToHide && tagsToHide.length > 0) {\r\n const tagContainer = document.getElementById(tagContainerId);\r\n const showMoreButton = document.getElementById(showMoreTagId);\r\n const showLessButton = document.getElementById(showLessTagId);\r\n\r\n // collapse the list\r\n tagContainer.classList.add(tagContainerCollapsedClass);\r\n showMoreButton.classList.remove(tagHiddenClass);\r\n showLessButton.classList.add(tagHiddenClass);\r\n hideTags(tagsToHide);\r\n }\r\n}\r\n\r\n/**\r\n * Function which accepts a tag element and sets the tag to the correct \"selected\"\r\n * classes, and ensures all other tags in the group are NOT marked as selected\r\n *\r\n * @param {Node} tags the clicked tag element\r\n */\r\nexport const setTagSelectedClass = tags => {\r\n tags.forEach(tag => {\r\n let foundTag = findTag(tag);\r\n if(!foundTag) { return; }\r\n foundTag.classList.add(tagSelectedClass);\r\n });\r\n};\r\n\r\n/**\r\n * Server-Side Tag click handler which accepts a clicked tag element, and uses the element's\r\n * data-tag attribute to perform the following actions\r\n *\r\n * Update the window query params with the tag's value\r\n * Set the correct classNames to style the tag as selected\r\n * Execute an API request for content matching the given tag\r\n *\r\n * @param {Node} tag the clicked tag element\r\n */\r\nconst executeServerSideFilterBySelectedTags = (site) => {\r\n const { section, query } = getInitialSearchParams();\r\n\r\n const selectedTags = getAllSelectedTags(); // Array of strings based on the tag's data-tag attribute\r\n\r\n setTagParam(selectedTags.join(','));\r\n searchContentAndUpdateResults(section, query, selectedTags, site);\r\n};\r\n\r\n/**\r\n * Client-Side Tag click handler which accepts a clicked tag element, and uses the element's\r\n * data-tag attribute to perform the following actions\r\n *\r\n * Set the correct classNames to style the tag as selected\r\n * Set any elements with matching the data-tag attribute to hidden/visible\r\n *\r\n * @param {Node} tag the clicked tag element\r\n */\r\nconst executeClientSideFilterBySelectedTags = () => {\r\n const resultsSection = document.getElementById(resultsSectionId);\r\n const resultsGroups = resultsSection ? resultsSection.querySelectorAll('.gs-cardgroup') : null;\r\n const selectedTags = getAllSelectedTags(); // Array of strings based on the tag's data-tag attribute\r\n\r\n if (resultsGroups) {\r\n resultsGroups.forEach(group => {\r\n const groupTagDataAttribute = group.dataset.tag;\r\n if (selectedTags.includes('all')) {\r\n group.classList.remove('gs-cardgroup--hidden');\r\n } else if (!selectedTags.includes(groupTagDataAttribute)) {\r\n group.classList.add('gs-cardgroup--hidden');\r\n } else {\r\n group.classList.remove('gs-cardgroup--hidden');\r\n }\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Enables all tags in a tag group to be clickable. \r\n * \r\n * @param {Node[]} tagGroup \r\n */\r\nconst enableTagGroup = (tagGroup) => {\r\n tagGroup.tags.forEach(tag => tag.disabled = false);\r\n tagGroup.allTag.disabled = false;\r\n}\r\n\r\n/**\r\n * Disables all tags in a tag group from being clickable.\r\n * \r\n * @param {Node[]} tagGroup \r\n */\r\nconst disableTagGroup = (tagGroup) => {\r\n tagGroup.tags.forEach(tag => tag.disabled = true);\r\n tagGroup.allTag.disabled = true;\r\n}\r\n\r\n/**\r\n * Handles click event for all tags. Calls corresponding filtering function for client and server side tags.\r\n * @param {Node} tag \r\n */\r\nconst handleTagClick = (tag) => {\r\n const container = tag.parentNode.parentNode.parentNode;\r\n if(container.id === serverSideFilterID) {\r\n const serverSideTagsGroup = getServerSideTagsGroup();\r\n // disable tags while searching\r\n disableTagGroup(serverSideTagsGroup);\r\n handleTagSelection(tag);\r\n executeServerSideFilterBySelectedTags(serverSideTagsGroup.site);\r\n } else {\r\n handleTagSelection(tag);\r\n executeClientSideFilterBySelectedTags(tag);\r\n }\r\n}\r\n\r\n/**\r\n * Adds listener to check when the search results are populated and then enables the tags to be clickable\r\n * @param {Node[]} serverSideTagsGroup \r\n * @param {Node} resultSection \r\n */\r\nconst enableServerSideTags = (serverSideTagsGroup, resultSection) => {\r\n const mutationCallback = (mutationsList) => {\r\n for (const mutation of mutationsList) {\r\n if (mutation.type === \"childList\") {\r\n if (mutation.addedNodes.length > 0) {\r\n enableTagGroup(serverSideTagsGroup);\r\n }\r\n\r\n if (mutation.removedNodes.length > 0) {\r\n disableTagGroup(serverSideTagsGroup);\r\n }\r\n }\r\n }\r\n };\r\n const observer = new MutationObserver(mutationCallback);\r\n observer.observe(resultSection, {\r\n childList: true,\r\n subtree: true\r\n });\r\n}\r\n\r\n/**\r\n * Scripts which must be executed on page load in order to establish the interaction capabilities\r\n * of Tag Filters. Tag filters have the capacity to trigger both ClientSide and ServerSide capabilities - thus\r\n * setting the appropriate ID on the tag group will facilitate the correct interaction for a given need\r\n *\r\n * Client Side Interaction | Trigger show/hide of elements on the page based on data-tag\r\n * Server Side Interaction | Trigger API request for data based on data-tag\r\n *\r\n */\r\nexport const tagFilterScripts = () => {\r\n const resultSection = document.getElementById(resultsSectionId);\r\n\r\n const clientSideTagsGroup = getClientSideTagsGroup();\r\n if (clientSideTagsGroup) {\r\n // wire up tag clicks\r\n clientSideTagsGroup.tags.forEach(tag => tag.addEventListener('click', () => handleTagClick(tag), false));\r\n clientSideTagsGroup.allTag.addEventListener('click', () => handleTagClick(clientSideTagsGroup.allTag), false);\r\n clientSideTagsGroup.showMoreTag.addEventListener('click', showAllTags);\r\n clientSideTagsGroup.showLessTag.addEventListener('click', hideExtraTags);\r\n }\r\n\r\n const serverSideTagsGroup = getServerSideTagsGroup();\r\n if (serverSideTagsGroup) {\r\n // wire up tag clicks\r\n serverSideTagsGroup.tags.forEach(tag => tag.addEventListener('click', () => handleTagClick(tag), false));\r\n serverSideTagsGroup.allTag.addEventListener('click', () => handleTagClick(serverSideTagsGroup.allTag), false);\r\n serverSideTagsGroup.showMoreTag.addEventListener('click', showAllTags);\r\n serverSideTagsGroup.showLessTag.addEventListener('click', hideExtraTags);\r\n enableServerSideTags(serverSideTagsGroup, resultSection);\r\n }\r\n};","// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 11/02/2020 JJacob 49830 Initial Create\r\n// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const toggleButtonScripts = {\r\n loadScripts: () => {\r\n const buttonIdOne = 'gs_cardlist_toggle_button_one';\r\n const buttonIdTwo = 'gs_cardlist_toggle_button_two';\r\n const handleClick = id => {\r\n if (id === 'one') {\r\n document.getElementById('gs_cardlist_toggle_button_two').classList.remove('--selected');\r\n document.getElementById('gs_cardlist_toggle_section_two').classList.remove('--selected');\r\n\r\n document.getElementById('gs_cardlist_toggle_section_one').classList.add('--selected');\r\n document.getElementById('gs_cardlist_toggle_button_one').classList.add('--selected');\r\n } else if (id === 'two') {\r\n document.getElementById('gs_cardlist_toggle_button_one').classList.remove('--selected');\r\n document.getElementById('gs_cardlist_toggle_section_one').classList.remove('--selected');\r\n\r\n document.getElementById('gs_cardlist_toggle_section_two').classList.add('--selected');\r\n document.getElementById('gs_cardlist_toggle_button_two').classList.add('--selected');\r\n }\r\n };\r\n if (document.getElementById(buttonIdOne)) {\r\n document.getElementById(buttonIdOne).addEventListener('click', () => {\r\n handleClick('one');\r\n });\r\n document.getElementById(buttonIdTwo).addEventListener('click', () => {\r\n handleClick('two');\r\n });\r\n }\r\n }\r\n};\r\n","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 07/19/2022 BBARRON 88352 Initial Create\r\n// 08/02/2023 BBARRON 110687 Renamed file. Automatically account for sticky page header when scrolling, allow scollingto be instant or smooth\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n/**\r\n * This utility allows you to detect the anchor tag in the url and jump the user down the page to that anchor tag.\r\n * A browser will do this for you if the element exists when the DOM is loaded. This script is useful when the element does not exist when the DOM is loaded.\r\n * For example if you have dynamically loaded content\r\n */\r\n\r\n/**\r\n * Gets the x and y position of an element\r\n * @param {DomElement} el \r\n * @returns \r\n */\r\n const getOffset = (el) => {\r\n const rect = el.getBoundingClientRect();\r\n\r\n return {\r\n left: rect.left,\r\n top: rect.top\r\n };\r\n};\r\n\r\nconst desktopHeaderHeight = 78;\r\nconst mobileHeaderHeght = 69;\r\nconst largestMobileBreakpoint = 1023;\r\n\r\nconst defaultScrollOptions = Object.freeze({\r\n /**\r\n * Determines how far above (-) or below (+) the target element you want to end up after scrolling. This is an additional manual offset beyond what autoOffset does\r\n * You can enter a number that will be used for both desktop and mobile or you can use an object {desktop: -5, mobile: -12} if you need different values by device\r\n * This is not meant to account for the sticky page header\r\n **/\r\n manualOffset: {\r\n desktop: 0, \r\n mobile: 0\r\n },\r\n /**\r\n * Attempts to auto-correct for the sticky page header, will adjust the scroll position for desktop and mobile accordingly\r\n */\r\n correctForStickyHeader: true,\r\n /**\r\n * behavior can be 'smooth', 'instant', or 'auto'. If set to auto it will be based on the css property 'scroll-behavior'\r\n */\r\n behavior: 'instant'\r\n});\r\n\r\n/**\r\n * Determines whether the page header is in desktop configuration\r\n * @returns true if page header is in a desktop configuration, false if mobile\r\n */\r\nconst isDesktop = () => {\r\n return window.innerWidth > largestMobileBreakpoint;\r\n}\r\n\r\n/**\r\n * Determines the current height of the sticky page header\r\n * @returns the sticky header height\r\n */\r\nconst getHeaderHeight = () => {\r\n return isDesktop() ? desktopHeaderHeight : mobileHeaderHeght;\r\n};\r\n\r\n/**\r\n * Interprets the manualOffset setting based on type and current device size\r\n * @param {*} manualOffset Any manual adjustments that are needed. @see {@link defaultScrollOptions.manualOffset} for more information\r\n * @returns A single value to be used for adjusting the final scroll position\r\n */\r\nconst getCurrentManualOffset = (manualOffset) => {\r\n if (!manualOffset) {\r\n return 0;\r\n }\r\n\r\n switch (typeof(manualOffset)) {\r\n case 'number':\r\n return manualOffset;\r\n case 'string':\r\n return parseInt(manualOffset);\r\n case 'object':\r\n if(isDesktop() && manualOffset.hasOwnProperty('desktop')) {\r\n return manualOffset.desktop;\r\n }\r\n\r\n if (!isDesktop() && manualOffset.hasOwnProperty('mobile')) {\r\n return manualOffset.mobile;\r\n }\r\n default:\r\n return 0;\r\n }\r\n}\r\n\r\n/**\r\n * Gets the final scroll position\r\n * @param {object} elementOffset The { left, top } position of the element relative to the top-left of the page\r\n * @param {object|number} manualOffset Any manual adjustments that are needed. @see {@link defaultScrollOptions.manualOffset} for more information\r\n * @param {boolean} correctForStickyHeader Whether to account for sticky page header in offset calculations @see {@link defaultScrollOptions.correctForStickyHeader} for more information\r\n * @returns The final {left, top} scroll position. Where we want to end up after the scroll operation.\r\n */\r\nconst getTotalOffset = (elementOffset, manualOffset, correctForStickyHeader) => {\r\n\r\n let totalOffset = {\r\n left: elementOffset.left, \r\n top: elementOffset.top + getCurrentManualOffset(manualOffset)\r\n };\r\n\r\n if (correctForStickyHeader) {\r\n totalOffset.top -= getHeaderHeight();\r\n }\r\n\r\n return totalOffset;\r\n}\r\n\r\n/**\r\n * Gets the anchor link id from the url\r\n * @param {string} url The url to get the anchor tag from. Defaults to browser url\r\n */\r\nexport const getFragmentFromUrl = (url) => {\r\n if(!url) {\r\n url = window.location.href;\r\n }\r\n const position = url.indexOf(\"#\");\r\n if(position === -1 || position === url.length - 1) {\r\n return null;\r\n }\r\n var hash = url.substring(url.indexOf(\"#\")+1);\r\n return hash;\r\n};\r\n\r\n/**\r\n * Jumps the user down the page to the position of the given element\r\n * @param {DomElement} element The element to jump to\r\n * @param {object} options The scroll options. @see {@link defaultScrollOptions} for more information\r\n * @returns \r\n */\r\n export const scrollToElement = (element, options) => {\r\n let fullOptions = Object.assign({}, defaultScrollOptions, options || {});\r\n\r\n // Get element's position relative to current scroll position\r\n const elementOffset = getOffset(element);\r\n\r\n // Adjust offset based on sticky header height and any manual adjustments desired\r\n const finalOptions = getTotalOffset(elementOffset, fullOptions.manualOffset, fullOptions.correctForStickyHeader);\r\n finalOptions.behavior = fullOptions.behavior;\r\n window.scrollBy(finalOptions);\r\n};\r\n\r\n/**\r\n * Jumps the user down the page to the position of the element with the given id\r\n * @param {string} id The id of the element to jump to\r\n * @param {object} options The scroll options. @see {@link defaultScrollOptions} for more information\r\n * @returns \r\n */\r\nexport const scrollToId = (id, options) => {\r\n const element = document.getElementById(id);\r\n if(!element) {\r\n return;\r\n }\r\n scrollToElement(element, options);\r\n};\r\n\r\n/**\r\n * Jumps the user to the anchor tag indicated by the given url\r\n * @param {string} url The url to get the anchor tag from. Defaults to browser url\r\n * @param {object} options The scroll options. @see {@link defaultScrollOptions} for more information\r\n */\r\n export const scrollToAnchorInUrl = (url, options)=> {\r\n const anchorId = getFragmentFromUrl(url);\r\n if(!anchorId) {\r\n return;\r\n }\r\n scrollToId(anchorId, options);\r\n};","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 12/18/2020 HJordan Initial create\r\n// 01/16/2020 HJordan Added logic to obtain SECTION filter for search based on URL\r\n// 01/27/2021 HJordan Updated searchQueryValidation to allow \"null\" as a valid entry (search by tag)\r\n// 04/18/2022 BBARRON 83828 Refactored mapping logic from url path to section\r\n// 04/27/2022 BBARRON 84447 Remove unused variable\r\n// 08/11/2022 BBARRON 90163 Update search section mapping for podcasts\r\n// 01/23/2023 BBARRON 98536 Handle multiple tags when getting from query string\r\n// 01/25/2023 BBARRON 98828 move search validation method to SearchValidation file\r\n// 02/01/2023 BBARRON 99334 explicitly specify property names in getInitialSearchParams() return object\r\n// 05/15/2023 BBARRON 105921 Ensure that content search pages with 'videos' in the url get mapped to the Videos secton\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n/**\r\n * Utility function which is used to update the \"query\" url parameter\r\n * on the window\r\n *\r\n * @param {string} value value to be set on the query url parameter\r\n */\r\nexport const setSearchQueryParam = value => {\r\n const params = new URLSearchParams(window.location.search);\r\n\r\n if (value) {\r\n params.set('query', value);\r\n } else {\r\n params.delete('query');\r\n }\r\n\r\n window.history.replaceState({}, '', `${window.location.pathname}?${params}`);\r\n};\r\n\r\n/**\r\n * Utility function which is used to update the \"tag\" url parameter\r\n * on the window\r\n *\r\n * @param {string} value value to be set on the tag url parameter\r\n */\r\nexport const setTagParam = value => {\r\n const params = new URLSearchParams(window.location.search);\r\n params.set('tag', value);\r\n window.history.replaceState({}, '', `${window.location.pathname}?${params}`);\r\n};\r\n\r\n/**\r\n * Utility function which is used to get the tag, section, and query\r\n * url parameters from the window\r\n *\r\n * In addition to checking URL params, the function will also check the\r\n * pathname of the URL to identify the current SECTION (Articles / Webinars) -\r\n * This logic will only evaluate if the section url param is not set\r\n *\r\n * @return {object} object containing the query, tags, and section url parameter values. tags is an array of strings\r\n */\r\nexport const getInitialSearchParams = () => {\r\n const params = new URLSearchParams(window.location.search);\r\n const query = params.get('query');\r\n const tagValue = params.get('tag');\r\n let sectionFromQueryString = params.get('section');\r\n\r\n // Don't add the 'all' tag here as a default. This is meant to hold only the tags that are found in the url query string.\r\n // If you do, it will trigger an unnecessary server-side search on page load, also tag list will default to expanded if any tag is found in the query string.\r\n let tagsFromQueryString = [];\r\n if (tagValue) {\r\n tagsFromQueryString = tagValue.split(',');\r\n }\r\n\r\n // Section is not specified in the query string, try to guess it from the url path\r\n let section = sectionFromQueryString;\r\n if (typeof section === \"undefined\" || section === null || section === '') {\r\n section = mapUrlPathToSection();\r\n }\r\n\r\n return { \r\n query: query, \r\n tags: tagsFromQueryString, \r\n section: section\r\n };\r\n};\r\n\r\n/**\r\n * Maps the url path to a section name. eg if path contains articles, \r\n * section is Articles. if path contains webinars, section is Webinars, etc.\r\n * @returns The section name or null\r\n */\r\nfunction mapUrlPathToSection() {\r\n // mapping from \"lowercase path value\" to \"Search Section Name\"\r\n const mapping = {\r\n 'articles': 'Articles',\r\n 'commentary': 'Commentary', // When the url contains \"commentary\" search the Commentary section\r\n 'news': 'NewsAndMedia', // When the url contains \"news\" search the NewsAndMedia section\r\n 'podcast': 'FaithInvesting', // When the url contains \"podcast\" search the FaithInvesting section\r\n 'videos': 'Videos', // When the url contains \"videos\" search the Videos section\r\n 'webinars': 'Webinars'\r\n }\r\n\r\n const path = window.location.pathname;\r\n const pathItems = path.split('/');\r\n for(var expectedPath in mapping) {\r\n if(pathItems.some(item => item.toLowerCase().includes(expectedPath))) {\r\n return mapping[expectedPath];\r\n }\r\n }\r\n return null;\r\n}","////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Modifications\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// Date Pgmr WR/IR# Description\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n// 11/02/2020 JJacob 49830 Initial Create\r\n// 02/28/2023 BBARRON 101078 Moved Sitecore script into this script, \r\n// Only enable next button on card click, not all buttons on page\r\n// Change dataset.wizard to dataset.action\r\n// 03/01/2023 BBARRON 101001 Simplify scrpt now that next/prevous buttons are removed\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport const wizardScripts = {\r\n loadScripts: () => {\r\n\r\n \r\n /**\r\n * Trigger an analytics event before taking user to their desired page\r\n * @param {*} evt \r\n */\r\n const handleCardClick = evt => {\r\n const card = evt.currentTarget;\r\n if (!card.href) {\r\n evt.preventDefault();\r\n return;\r\n }\r\n\r\n const action = card.dataset.action;\r\n if (!!action && window.dataLayer) {\r\n // Trigger the google analytics event\r\n window.dataLayer.push({ 'wizardName': action, 'wizardUrl': card.href, 'event': 'wizardLaunch' });\r\n }\r\n };\r\n\r\n\r\n // Wire up the card and next button click events\r\n if (document.getElementById('gs_wizard')) {\r\n const cards = document.querySelectorAll('.gs-wizard-content-card');\r\n cards.forEach(card => {\r\n card.addEventListener('click', handleCardClick);\r\n });\r\n }\r\n }\r\n};"],"sourceRoot":""}