{"version":3,"file":"script.js","sources":["../../../dev/components/finder/_script.js","../../../dev/components/search/_script.js","../../../dev/components/repeaters/_script.js","../../../dev/components/trip/dates-pricing/_script.js","../../../dev/components/enso/_script.js","../../../dev/components/video-wistia/_script.js","../../../dev/assets/js/utilities.js","../../../dev/components/modal/_script.js","../../../dev/components/hero/_video.js","../../../dev/components/modal/generic-dialog/_script.js","../../../dev/components/masthead/_script.js","../../../dev/components/masthead/nav/_script.js","../../../dev/components/lists/country-list/_country-list.js","../../../dev/assets/js/smartypants.js","../../../dev/assets/js/global-form-functions.js","../../../dev/components/modal/catalog/_script.js","../../../dev/components/modal/enews/_script.js","../../../dev/components/olark/_script.js","../../../dev/components/modal/message/_script.js","../../../dev/components/modal/refer/_script.js","../../../dev/components/modal/digital/_script.js","../../../dev/components/modal/youtube/_script.js","../../../dev/components/modal/eBook/_script.js","../../../dev/components/ctas/magic/_script.js","../../../dev/components/masthead/favorites/_script.js","../../../dev/templates/search-results/script.js"],"sourcesContent":["// to do : rewrite component using json to make it update in real time\n// to do : write test\nexport function tripFinder() {\n\tlet urlString;\n\n\t//Restrict datepicker to future dates only and set max date of 5 years from today\n\tfunction setMinMaxDates() {\n\t\tlet dtToday = new Date();\n\t\tlet month = dtToday.getMonth() + 1;\n\t\tlet day = dtToday.getDate();\n\t\tlet year = dtToday.getFullYear();\n\t\tif (month < 10) month = \"0\" + month.toString();\n\t\tif (day < 10) day = \"0\" + day.toString();\n\n\t\tlet minDate = year + \"-\" + month + \"-\" + day;\n\t\tlet maxDate = year + 5 + \"-\" + month + \"-\" + day;\n\n\t\t$(\".js-datepicker-start\").attr(\"min\", minDate);\n\t\t$(\".js-datepicker-start\").attr(\"max\", maxDate);\n\t\t$(\".js-datepicker-end\").attr(\"min\", minDate);\n\t\t$(\".js-datepicker-end\").attr(\"max\", maxDate);\n\t}\n\tsetMinMaxDates();\n\n\t//if user clicks in date field, hide placeholder, show input\n\tfunction datePlaceholderListener(placeholder, datepicker) {\n\t\tlet placeholderDiv = document.querySelector(placeholder);\n\t\tlet datepickerDiv = document.querySelector(datepicker);\n\n\t\tdatepickerDiv.addEventListener(\"click\", function () {\n\t\t\tdatepickerDiv.showPicker();\n\t\t});\n\n\t\tplaceholderDiv.addEventListener(\"click\", function () {\n\t\t\tshowDateInput(datepickerDiv);\n\t\t\thideDatePlaceholder(placeholderDiv);\n\t\t\tdatepickerDiv.showPicker();\n\n\t\t\tif (navigator.userAgent.match(\"Chrome\") || navigator.userAgent.match(\"Safari\")) {\n\t\t\t\tdatepickerDiv.focus();\n\t\t\t}\n\n\t\t\tif (navigator.userAgent.match(\"Safari\") || navigator.userAgent.match(\"Firefox\")) {\n\t\t\t\tdatepickerDiv.click();\n\t\t\t}\n\t\t});\n\n\t\tif (datepicker === \".js-datepicker-start\") {\n\t\t\tdatepickerDiv.addEventListener(\"change\", function () {\n\t\t\t\tlet searchStart = this.value;\n\t\t\t\tdocument.querySelector(\".js-datepicker-end\").setAttribute(\"min\", searchStart);\n\t\t\t});\n\t\t}\n\n\t\tif (navigator.userAgent.match(\"Chrome\") || navigator.userAgent.match(\"Safari\")) {\n\t\t\tdatepickerDiv.addEventListener(\"focusout\", function () {\n\t\t\t\tlet dateValue = this.value;\n\t\t\t\tif (dateValue == \"\") {\n\t\t\t\t\tplaceholderDiv.classList.remove(\"hide-date-placeholder\");\n\t\t\t\t\tdatepickerDiv.classList.remove(\"show-date-input\");\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tdatePlaceholderListener(\".js-placeholder-start\", \".js-datepicker-start\");\n\tdatePlaceholderListener(\".js-placeholder-end\", \".js-datepicker-end\");\n\n\t// If search results are null\n\tif ($(\".js-search-null\").parent().length < 2) {\n\t\t$(\".js-search-null\").show();\n\t}\n\n\t// FUNCTION - filterCountries\n\tfunction filterCountries(classArray) {\n\t\t// Reset\n\t\tlet resetTarget = \"#countries-dropdown [trip-finder='item']\";\n\t\tlet resetValue = document.querySelector(\"#dropdown-countries\");\n\t\t$(resetTarget).css(\"color\", \"\");\n\t\t$(resetTarget).css(\"pointer-events\", \"\");\n\t\tresetValue.value = \"\";\n\t\t$(\"#countries-dropdown\").find(\"[trip-finder~='label']\").text(\"By Country\");\n\t\t// Hide\n\t\t$(classArray).each(function () {\n\t\t\tlet thisTarget = \"#countries-dropdown [trip-finder='item']:not(.\" + this + \")\";\n\t\t\t$(thisTarget).css(\"color\", \"#ccc\");\n\t\t\t$(thisTarget).css(\"pointer-events\", \"none\");\n\t\t});\n\t}\n\t// FUNCTION - filterWildife\n\tfunction filterWildlife(classArray) {\n\t\t// Reset\n\t\tlet resetTarget = \"#wildlife-dropdown [trip-finder='item']\";\n\t\tlet resetValue = document.querySelector(\"#dropdown-wildlife\");\n\t\t$(resetTarget).css(\"color\", \"\");\n\t\t$(resetTarget).css(\"pointer-events\", \"\");\n\t\tresetValue.value = \"\";\n\t\t$(\"#wildlife-dropdown\").find(\"[trip-finder~='label']\").text(\"By Wildlife\");\n\t\t// Hide\n\t\t$(classArray).each(function () {\n\t\t\tlet thisTarget = \"#wildlife-dropdown [trip-finder='item']:not(.\" + this + \")\";\n\t\t\t$(thisTarget).css(\"color\", \"#ccc\");\n\t\t\t$(thisTarget).css(\"pointer-events\", \"none\");\n\t\t});\n\t}\n\t// FUNCTION - filterInterest\n\tfunction filterInterests(classArray) {\n\t\t// Reset\n\t\tlet resetTarget = \"#interest-dropdown [trip-finder='item']\";\n\t\tlet resetValue = document.querySelector(\"#dropdown-interest\");\n\t\t$(resetTarget).css(\"color\", \"\");\n\t\t$(resetTarget).css(\"pointer-events\", \"\");\n\t\tresetValue.value = \"\";\n\t\t$(\"#interest-dropdown\").find(\"[trip-finder~='label']\").text(\"By Interest\");\n\t\t// Hide\n\t\t$(classArray).each(function () {\n\t\t\tlet thisTarget = \"#interest-dropdown [trip-finder='item']:not(.\" + this + \")\";\n\t\t\t$(thisTarget).css(\"color\", \"#ccc\");\n\t\t\t$(thisTarget).css(\"pointer-events\", \"none\");\n\t\t});\n\t}\n\n\t// EVENT - Click on trip finder item, set trip finder label\n\t// When you select an item in the dropdown, its value will be set to the trip finder label\n\t$(\"[trip-finder='item']\").on(\"click\", function () {\n\t\tlet thisParentList = $(this).closest(\".js-dropdown\").attr(\"id\");\n\t\tlet classArray;\n\t\tif (thisParentList == \"regions-dropdown\") {\n\t\t\tclassArray = $(this).attr(\"id\").split(); // Must use split to force it into array\n\t\t\tfilterCountries(classArray);\n\t\t\tfilterWildlife(classArray);\n\t\t\tfilterInterests(classArray);\n\t\t} else if (thisParentList == \"countries-dropdown\") {\n\t\t\tclassArray = $(this).attr(\"class\").split(\" \");\n\t\t\tclassArray = classArray.filter(Boolean);\n\t\t\tfilterWildlife(classArray);\n\t\t\tfilterInterests(classArray);\n\t\t} else if (thisParentList == \"wildlife-dropdown\") {\n\t\t\tclassArray = $(this).attr(\"class\").split(\" \");\n\t\t\tclassArray = classArray.filter(Boolean);\n\t\t\tfilterInterests(classArray);\n\t\t}\n\t\tlet thisValue = $(this).attr(\"id\");\n\t\tlet thisText = $(this).text();\n\t\tlet thisLink = $(this).attr(\"trip-finder-link\");\n\n\t\t// Find closest dropdown and set find previous element and set label\n\t\t$(this).closest(\".js-dropdown\").prev().val(thisValue);\n\t\t$(this).parent().prevAll(\"[trip-finder~='label']\").text(thisText);\n\t\t$(this).closest(\".js-dropdown\").prev().attr(\"link\", thisLink);\n\t\t$(\"[trip-finder~='reset']\").trigger(\"click\");\n\t});\n\n\t// EVENT - Click search button\n\t$(\".js-search-button\").on(\"click\", function () {\n\t\t// FYI - On is the default value of the input#dropdown-x\n\t\t// If it's still set to on, change it to null so the search results work properly.\n\n\t\tlet region = $(\"#dropdown-regions\").val();\n\t\tlet regionLink = $(\"#dropdown-regions\").attr(\"link\");\n\t\tif (region == \"on\") {\n\t\t\tregion = \"\";\n\t\t}\n\t\tlet country = $(\"#dropdown-countries\").val();\n\t\tif (country == \"on\") {\n\t\t\tcountry = \"\";\n\t\t}\n\t\tlet wildlife = $(\"#dropdown-wildlife\").val();\n\t\tif (wildlife == \"on\") {\n\t\t\twildlife = \"\";\n\t\t}\n\t\tlet interest = $(\"#dropdown-interest\").val();\n\t\tif (interest == \"on\") {\n\t\t\tinterest = \"\";\n\t\t}\n\t\tlet searchStartDate = $(\"#dropdown-start-date\").val();\n\t\tif (searchStartDate == \"on\") {\n\t\t\tsearchStartDate = \"\";\n\t\t}\n\t\tlet searchEndDate = $(\"#dropdown-end-date\").val();\n\t\tif (searchEndDate == \"on\") {\n\t\t\tsearchEndDate = \"\";\n\t\t}\n\n\t\tif (region !== \"\" && country == \"\" && wildlife == \"\" && interest == \"\" && searchStartDate == \"\" && searchEndDate == \"\") {\n\t\t\twindow.location.href = regionLink;\n\t\t} else {\n\t\t\turlString = \"/search/?region=\" + region + \"&country=\" + country + \"&wildlife=\" + wildlife + \"&interest=\" + interest + \"&searchStartDate=\" + searchStartDate + \"&searchEndDate=\" + searchEndDate + \"&tripfinder=true\";\n\t\t\twindow.location.href = urlString;\n\t\t}\n\t});\n}\n\n//hide date placeholder\nexport function hideDatePlaceholder(placeholderDiv) {\n\tplaceholderDiv.classList.add(\"hide-date-placeholder\");\n}\n\n//show date input field\nexport function showDateInput(datepickerDiv) {\n\tdatepickerDiv.classList.add(\"show-date-input\");\n}\n","import { hideDatePlaceholder, showDateInput } from \"../finder/_script.js\";\n\nexport function searchResults() {\n\t// Selectors: grab search parameters from url to use in date search and to fill labels\n\tconst searchParameters = new URL(document.location).searchParams;\n\tconst region = searchParameters.get(\"region\");\n\tconst country = searchParameters.get(\"country\");\n\tconst wildlife = searchParameters.get(\"wildlife\");\n\tconst interest = searchParameters.get(\"interest\");\n\tconst tripFinder = searchParameters.get(\"tripfinder\");\n\tlet startDate = searchParameters.get(\"searchStartDate\");\n\tlet endDate = searchParameters.get(\"searchEndDate\");\n\n\t// Function: populate search labels\n\tfunction fillSearchLabels(parameter) {\n\t\tlet categoryID = parameter;\n\t\tif (categoryID) {\n\t\t\tlet dropdownItem = document.querySelector(`#${categoryID}`);\n\t\t\tif (dropdownItem) {\n\t\t\t\tdropdownItem.click();\n\t\t\t}\n\t\t}\n\t}\n\n\t// Function: format dates for label\n\tfunction reformatDate(date, datepickerClass) {\n\t\tif (date) {\n\t\t\tlet labelDiv = document.querySelector(datepickerClass);\n\t\t\tlabelDiv.value = date;\n\t\t\thideShowDate(datepickerClass);\n\t\t}\n\t}\n\n\t// Function: if date entered, remove placeholder and show input div with selected date\n\tfunction hideShowDate(datepickerClass) {\n\t\tif (reformatDate) {\n\t\t\tlet datePlaceholderClass = \"\";\n\t\t\tif (datepickerClass == \".js-datepicker-start\") {\n\t\t\t\tdatePlaceholderClass = \".js-placeholder-start\";\n\t\t\t}\n\t\t\tif (datepickerClass == \".js-datepicker-end\") {\n\t\t\t\tdatePlaceholderClass = \".js-placeholder-end\";\n\t\t\t}\n\n\t\t\tlet datePlaceholder = document.querySelector(datePlaceholderClass);\n\t\t\tlet dateInput = document.querySelector(datepickerClass);\n\n\t\t\t// call functions from components/finder/_script.js\n\t\t\thideDatePlaceholder(datePlaceholder);\n\t\t\tshowDateInput(dateInput);\n\t\t}\n\t}\n\n\t// Control flow: populate search labels on search results page if tripfinder was used\n\tif (tripFinder === true) {\n\t\tfillSearchLabels(region);\n\t\tfillSearchLabels(country);\n\t\tfillSearchLabels(wildlife);\n\t\tfillSearchLabels(interest);\n\t}\n\n\t// Control flow: format start and end search dates\n\treformatDate(startDate, \".js-datepicker-start\");\n\treformatDate(endDate, \".js-datepicker-end\");\n\n\t// Note: this code must execute from the search page: queries trip list generated by region, country, wildlife, and interest search for the date range selected\n\t// Selectors:\n\tconst tripLinks = document.querySelectorAll(\"[js-get-trip-href]\");\n\tconst errorGeneric = document.querySelector(\".js-search-error-generic\"); // for errors where search yields zero results\n\tlet linksArray = []; // to populate trip link list on page load\n\tlet linksArrayUpdated = []; // to be used to build new list based on date search\n\n\t// Build array of links\n\ttripLinks.forEach(function (trip) {\n\t\tlet link = trip.getAttribute(\"js-get-trip-href\");\n\t\tlinksArray.push(link);\n\t});\n\n\t// Function: query database with date parameters\n\tfunction dateSearch() {\n\t\t// check for zero trip results before proceeding with date range check\n\t\tif (linksArray.length < 1) {\n\t\t\terrorGeneric.classList.remove(\"hide\");\n\t\t\treturn;\n\t\t}\n\t\t// format default dates\n\t\tlet dtToday = new Date();\n\t\tlet month = dtToday.getMonth() + 1;\n\t\tlet day = dtToday.getDate();\n\t\tlet year = dtToday.getFullYear();\n\t\tif (month < 10) month = \"0\" + month.toString();\n\t\tif (day < 10) day = \"0\" + day.toString();\n\n\t\tlet minDate = year + \"-\" + month + \"-\" + day; // today\n\t\tlet maxDate = year + 5 + \"-\" + month + \"-\" + day; // 5 years from today\n\n\t\t// if user entered at least one date, see if both are set, if only one set the other to min or max, format search dates and make ajax call to compare to trip dates\n\t\tif (startDate || endDate) {\n\t\t\tif (!startDate) {\n\t\t\t\tstartDate = minDate;\n\t\t\t}\n\n\t\t\tif (!endDate) {\n\t\t\t\tendDate = maxDate;\n\t\t\t}\n\n\t\t\tfunction dateParser(date) {\n\t\t\t\tlet parsedDate = date.split(\"-\");\n\t\t\t\tlet year = parsedDate[0];\n\t\t\t\tlet month = parsedDate[1] - 1;\n\t\t\t\tlet day = parsedDate[2];\n\t\t\t\tlet formattedDate = new Date(year, month, day);\n\t\t\t\treturn formattedDate;\n\t\t\t}\n\n\t\t\tlet formattedStartDate = dateParser(startDate);\n\t\t\tlet formattedEndDate = dateParser(endDate);\n\n\t\t\t$.ajax({\n\t\t\t\turl: \"/_data/new-prices.json\",\n\t\t\t\tdataType: \"json\",\n\t\t\t\tsuccess: function (data) {\n\t\t\t\t\tconst allData = data.tripData;\n\t\t\t\t\tlet startRange = false;\n\t\t\t\t\tlet endRange = false;\n\n\t\t\t\t\tlinksArray.forEach(function (link) {\n\t\t\t\t\t\tlet results = allData.filter((d) => d.repeaterURL == link);\n\n\t\t\t\t\t\tresults.forEach(function (result) {\n\t\t\t\t\t\t\tlet tripURL = result.repeaterURL;\n\t\t\t\t\t\t\tlet departureDate = new Date(result.departure);\n\t\t\t\t\t\t\tlet returnDate = new Date(result.return);\n\n\t\t\t\t\t\t\tif (departureDate >= formattedStartDate) {\n\t\t\t\t\t\t\t\tstartRange = true;\n\t\t\t\t\t\t\t} else startRange = false;\n\t\t\t\t\t\t\tif (returnDate <= formattedEndDate) {\n\t\t\t\t\t\t\t\tendRange = true;\n\t\t\t\t\t\t\t} else endRange = false;\n\t\t\t\t\t\t\tif (startRange === true && endRange === true) {\n\t\t\t\t\t\t\t\tlinksArrayUpdated.push(tripURL);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\n\t\t\t\t\t// find trips that don't fall within date range and remove from trip repeater results\n\t\t\t\t\ttripLinks.forEach(function (tripLink) {\n\t\t\t\t\t\tlet linkURL = tripLink.getAttribute(\"href\");\n\t\t\t\t\t\tlet notIncludedLink = !linksArrayUpdated.includes(linkURL);\n\t\t\t\t\t\tif (notIncludedLink === true) {\n\t\t\t\t\t\t\ttripLink.closest(\"[repeater-trip]\").remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// if all trips removed, add error message with link to show results without date restriction, rebuild search url\n\t\t\t\t\tconst newParams = new URLSearchParams(location.search);\n\t\t\t\t\tnewParams.set(\"searchStartDate\", \"\");\n\t\t\t\t\tnewParams.set(\"searchEndDate\", \"\");\n\t\t\t\t\tconst errorDates = document.querySelector(\".js-search-error-date\");\n\n\t\t\t\t\tif (linksArrayUpdated.length < 1) {\n\t\t\t\t\t\terrorDates.classList.remove(\"hide\");\n\t\t\t\t\t}\n\n\t\t\t\t\tconst urlDiv = document.querySelector(\".js-date-search-reset\");\n\t\t\t\t\turlDiv.addEventListener(\"click\", function () {\n\t\t\t\t\t\terrorDates.classList.add(\"hide\");\n\t\t\t\t\t\twindow.location.search = newParams.toString();\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\terror: function () {\n\t\t\t\t\tconsole.log(\"error\");\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tdateSearch();\n}\n","// Function: set text on repeaters: Make it Private (non-Africa trips) or Make it Custom (Africa trips)\nexport function repeaterPrivateOrCustom() {\n\tlet repeaters = document.querySelectorAll(\"[js-show-private-or-custom].show\");\n\tlet repeaterParent;\n\tlet makeItPrivateSpan;\n\n\trepeaters.forEach((repeater) => {\n\t\trepeaterParent = repeater.closest(\"a[repeater-link]\");\n\n\t\tif (repeaterParent.href.includes(\"africa\") || repeaterParent.href.includes(\"botswana\")) {\n\t\t\tmakeItPrivateSpan = repeater.querySelector(\"span.custom\");\n\t\t} else {\n\t\t\tmakeItPrivateSpan = repeater.querySelector(\"span.private\");\n\t\t}\n\t\tmakeItPrivateSpan.classList.remove(\"hide\");\n\t});\n\n\t$(\"[repeater-target]\")\n\t\t.not(\"label\")\n\t\t.each(function () {\n\t\t\tvar thisHref = $(this).attr(\"href\");\n\t\t\tvar isLocalLink = thisHref.startsWith(\"/\"); // true or false\n\t\t\tvar isTarget = $(this).attr(\"repeater-target\");\n\t\t\tif (isTarget == \"yes\") {\n\t\t\t\tif ($(document).width() > 1024 && !isLocalLink) {\n\t\t\t\t\t$(this).attr(\"target\", \"_blank\");\n\t\t\t\t}\n\t\t\t}\n\t\t});\n}\n","// Hide header if text is empty\nexport function hideEmptyHeaders() {\n\t$(\"[dates~='text']\").each(function () {\n\t\tif (!$.trim($(this).html())) {\n\t\t\t$(this).hide();\n\t\t\t$(this).prev(\"h5\").hide();\n\t\t}\n\t});\n}\n\nexport function hideShowPricingAccordionsForAdmin() {\n\tconst pricingAccordions = document.querySelectorAll(\"[js-pricing-accordion]\");\n\tconst currentMonth = new Date().getMonth() + 1; // +1 for months 1-12 instead of 0-11\n\tconst currentYear = new Date().getFullYear();\n\n\tpricingAccordions.forEach((accordion) => {\n\t\tlet pricingYear = accordion.classList[1]; // pricing year;\n\t\tpricingYear = parseInt(pricingYear.replace(\"pricing-\", \"\")); // separate out year & make an int\n\n\t\tlet showForAdmin = false;\n\t\tconst yearsToShow = [currentYear, currentYear + 1, currentYear + 2, currentYear + 3]; // this year and the next 3 years\n\n\t\t// show last year for admin until march and any years in the yearsToShow array\n\t\tif ((pricingYear + 1 === currentYear && currentMonth < 3) || yearsToShow.includes(pricingYear)) showForAdmin = true;\n\n\t\tif (showForAdmin) accordion.setAttribute(\"js-show-for-admin\", \"block\");\n\t});\n}\n\nexport function hide_max_travelers_if_empty() {\n\tconst limitedToElement = document.querySelector(\"[js-hide-if-no-travelers]\");\n\tconst maxTravelers = document.querySelector(\"[js-get-max-travelers]\");\n\n\tif (!limitedToElement || !maxTravelers) return;\n\n\tif (!maxTravelers.textContent.trim()) limitedToElement.classList.add(\"hide\");\n}\n\nexport async function add_pricing_to_overview_pages() {\n\tconst pricingElement = document.querySelector(\"[js-override-tigress-price]\");\n\tif (!pricingElement) return;\n\n\tconst pricingSuffix = document.querySelector(\"[js-get-pricing-suffix]\");\n\n\tif (pricingElement.getAttribute(\"js-override-tigress-price\") === \"yes\") {\n\t\tnormalize_database_pricing(pricingElement);\n\t\treturn;\n\t}\n\n\tconst pricingData = await fetch_pricing_data();\n\tconst fromPrice = get_lowest_trip_price(pricingData, window.location.pathname, false);\n\n\tset_lowest_tigress_trip_price(pricingElement, fromPrice, pricingSuffix);\n}\n\nexport async function add_pricing_to_repeaters() {\n\tconst repeaterPricingElements = document.querySelectorAll(\"[js-get-repeater-trip-pricing].show\");\n\tconst pricingData = await fetch_pricing_data();\n\n\tfor (const repeater of repeaterPricingElements) {\n\t\tconst pricingElement = repeater.querySelector(\"[js-override-tigress-price]\");\n\t\tconst hrefElement = repeater.closest(\"[js-get-trip-href]\");\n\t\tif (!pricingElement || !hrefElement) continue;\n\n\t\tconst tripUrl = hrefElement.getAttribute(\"js-get-trip-href\");\n\t\tconst pricingSuffix = repeater.querySelector(\"[js-get-pricing-suffix]\");\n\n\t\tif (pricingElement.getAttribute(\"js-override-tigress-price\") === \"yes\") {\n\t\t\tnormalize_database_pricing(pricingElement);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst wiwTrip = hrefElement.hasAttribute(\"js-wiw-trip\") ? true : false;\n\t\tconst fromPrice = get_lowest_trip_price(pricingData, tripUrl, wiwTrip);\n\t\tset_lowest_tigress_trip_price(pricingElement, fromPrice, pricingSuffix);\n\t}\n}\n\nasync function fetch_pricing_data() {\n\ttry {\n\t\tconst response = await fetch(\"/_data/new-prices.json\");\n\t\tconst data = await response.json();\n\t\treturn data.tripData;\n\t} catch (error) {\n\t\tconsole.error(\"Error fetching prices:\", error);\n\t\treturn [];\n\t}\n}\n\nfunction get_lowest_trip_price(pricingData, url, wiwTrip) {\n\tconst currentDate = new Date();\n\tconst currentYear = currentDate.getFullYear();\n\tconst allYears = currentYear + 2; // look 2 years out per Maya\n\tconst prices = [];\n\n\tpricingData.forEach((trip) => {\n\t\tconst tripUrl = trip.repeaterURL;\n\t\tconst departureDate = new Date(trip.departure);\n\t\tconst departureYear = departureDate.getFullYear();\n\t\tconst notes = trip.notes;\n\n\t\tconst isMatchingUrl = tripUrl === url;\n\t\tconst isFutureDeparture = departureDate >= currentDate;\n\t\tconst isWithinAllowedYears = departureYear <= allYears;\n\t\tconst isWomenOnlyTrip = !wiwTrip || (notes && notes.includes(\"Women\"));\n\n\t\tif (isMatchingUrl && isFutureDeparture && isWithinAllowedYears && isWomenOnlyTrip) {\n\t\t\tconst priceMatch = trip.pricing.match(/\\$(\\d{1,3},\\d{3}|\\d+)/gm);\n\t\t\tif (priceMatch) priceMatch.forEach((price) => prices.push(Number(price.replace(\"$\", \"\").replace(\",\", \"\"))));\n\t\t}\n\t});\n\n\treturn prices.length ? Math.min(...prices) : null; // Return the lowest price or null if no valid prices found\n}\n\nfunction set_lowest_tigress_trip_price(pricingElement, fromPrice, pricingSuffix) {\n\tconst suffixText = pricingSuffix ? pricingSuffix.textContent : \"\";\n\n\tfromPrice ? (pricingElement.textContent = `From $${fromPrice} ${suffixText}`) : normalize_database_pricing(pricingElement);\n}\n\nfunction normalize_database_pricing(pricingElement) {\n\tconst pricingTextContent = pricingElement.textContent;\n\tpricingElement.textContent = pricingTextContent.replace(\"From\", \"\");\n\n\tif (pricingTextContent.includes(\"$\")) pricingElement.textContent = `From ${pricingTextContent}`;\n}\n","//\n\n// Is there a better way to handle this like [enso].js-enso-on?\n\n// Function - Modernize Enso\nexport function enso() {\n\tconst ensoElements = [...document.querySelectorAll(\".enso-overlay-link\")];\n\n\tif (!ensoElements) return;\n\tfor (const element of ensoElements) {\n\t\tlet ensoOverlayContentElement = element.closest(\".enso-overlay-content\");\n\t\tlet ensoElement = ensoOverlayContentElement.closest(\"[enso]\");\n\t\tcopyEnsoLinkToParentAttribute(element);\n\t\telement.remove();\n\t\tunWrap(ensoOverlayContentElement);\n\t\tensoOverlayContentElement.remove();\n\t\taddTabKeyDownEvent(ensoElement);\n\t}\n}\n\n// FUNCTION - Move Enso Link to parent element with enso attribute\nfunction copyEnsoLinkToParentAttribute(element) {\n\tlet getLink = element.getAttribute(\"onclick\");\n\tgetLink = getLink.replace('self.location.href=\"', \"\").replace('\"', \"\");\n\tlet targetEnso = element.closest(\"[enso]\");\n\tif (targetEnso) {\n\t\ttargetEnso.setAttribute(\"enso\", getLink);\n\t}\n}\n\n// Function - Upwrap element\nfunction unWrap(element) {\n\tconst parent = element.parentNode;\n\twhile (element.firstChild) {\n\t\tparent.insertBefore(element.firstChild, element);\n\t}\n}\n\n// Function - Add in tab keydown event\nfunction addTabKeyDownEvent(element) {\n\tlet overlayVisible = false;\n\tdocument.addEventListener(\"keydown\", (event) => {\n\t\tif (event.key === \"Tab\" && element) {\n\t\t\tevent.preventDefault();\n\t\t\toverlayVisible = !overlayVisible;\n\t\t\tif (overlayVisible) {\n\t\t\t\telement.classList.add(\"js-enso-on\");\n\t\t\t\taddEnsoClickListener(element);\n\t\t\t} else {\n\t\t\t\telement.classList.remove(\"js-enso-on\");\n\t\t\t\tremoveEnsoClickListener(element);\n\t\t\t}\n\t\t}\n\t});\n}\n\n// Function - Setup link href\nfunction setupLink(e) {\n\te.preventDefault();\n\tlet goToUrl = this.getAttribute(\"enso\"); // this was the key\n\twindow.location.href = goToUrl;\n}\n\n// Function - Add click event listener\nfunction addEnsoClickListener(element) {\n\telement.addEventListener(\"click\", setupLink, false);\n}\n\n// Function - Remove click event listener\nfunction removeEnsoClickListener(element) {\n\telement.removeEventListener(\"click\", setupLink);\n}\n","export function isWistiaVideoPlaying() {\n\tlet isVideoPlaying = false;\n\n\tfunction wistiaVideo() {\n\t\tconst videoID = document.querySelector(\".js-wistia-video-id\").textContent;\n\t\tconst wistiaSrc = `https://fast.wistia.net/embed/iframe/${videoID}?videoFoam=true`;\n\n\t\tif (wistiaSrc === \"https://fast.wistia.net/embed/iframe/?videoFoam=true\") {\n\t\t\treturn;\n\t\t}\n\n\t\tconst wistiaIframe = document.querySelector(\".js-wistia-video\");\n\t\twistiaIframe.setAttribute(\"src\", wistiaSrc);\n\n\t\twindow._wq = window._wq || [];\n\t\tconst videoTitles = document.querySelector(\".js-video\");\n\t\tvideoTitles.addEventListener(\"click\", function (ev) {\n\t\t\tvideoTitles.classList.add(\"hide\");\n\t\t\tplayVideo();\n\t\t});\n\t\tfunction playVideo() {\n\t\t\tlet playStatus;\n\t\t\t_wq.push({\n\t\t\t\tid: \"_all\",\n\t\t\t\tonReady: function (video) {\n\t\t\t\t\tvideo.play();\n\t\t\t\t\tvideo.bind(\"play\", function () {\n\t\t\t\t\t\tplayStatus = true;\n\t\t\t\t\t\tvideoPlayStatus(playStatus);\n\t\t\t\t\t});\n\t\t\t\t\tvideo.bind(\"pause\", function () {\n\t\t\t\t\t\tplayStatus = false;\n\t\t\t\t\t\tvideoPlayStatus(playStatus);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\twistiaVideo();\n\n\tfunction videoPlayStatus(status) {\n\t\tisVideoPlaying = status;\n\t}\n\treturn isVideoPlaying;\n}\n","import { isWistiaVideoPlaying } from \"../../components/video-wistia/_script.js\";\n\nexport function isAdmin() {\n\tconst ensoElement = document.querySelector(\"[enso]\");\n\tconst ensoElementAttribute = ensoElement.getAttribute(\"enso\");\n\treturn Boolean(ensoElementAttribute);\n}\n\nexport function showForAdmin() {\n\tif (!isAdmin()) return;\n\n\tif (window.matchMedia(\"(max-width : 768px)\").matches) return;\n\n\tconst elements = document.querySelectorAll(\"[js-show-for-admin]\");\n\tfor (const element of elements) {\n\t\tconst getDisplayType = element.getAttribute(\"js-show-for-admin\");\n\t\telement.classList.remove(\"hide\");\n\t\telement.style.display = `${getDisplayType}`; // to pick up edge cases during migration\n\t}\n}\n\nexport function cleanupAnchorTags() {\n\t// Remove a tag if href is missing or undefined\n\t$(\"a\").each(function () {\n\t\tif ($(this).attr(\"href\") == \"\" || $(this).attr(\"href\") == \"undefined\") {\n\t\t\t$(this).remove();\n\t\t}\n\t});\n}\n\n// Check all a links to find target = _blank see above\nexport function cleanupAnchorTagsBlankTarget() {\n\tdocument.querySelectorAll(\"a\").forEach(function (link) {\n\t\tif (!link.hasAttribute(\"href\")) link.remove();\n\n\t\tconst linkHref = link.getAttribute(\"href\");\n\n\t\t// Add _blank to all links that go to Monster Campaigns so they open on top of our pages instead of being redirected to Monsty\n\t\tif (linkHref && linkHref.includes(\"https://app.monstercampaigns.com/\")) {\n\t\t\tlink.setAttribute(\"target\", \"_blank\");\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove all _blank from a tags on mobile and tablet\n\t\tif (document.documentElement.clientWidth < 1025) {\n\t\t\tlink.setAttribute(\"target\", \"_self\");\n\t\t}\n\t});\n}\n\nexport function pushEvent(item, action, label) {\n\ttry {\n\t\tdataLayer.push({\n\t\t\tevent: item,\n\t\t\taction: action,\n\t\t\tlabel: label\n\t\t});\n\t\tconsole.log(\"Success: Pushed Event via data layer:\", item, action, label);\n\t} catch (error) {\n\t\tconsole.log(\"Failed: Pushed Event:\", item, action, label, \"-\", error);\n\t}\n}\n\nexport function pushEventFacebook() {\n\ttry {\n\t\tfbq(\"track\", \"Lead\");\n\t} catch (error) {\n\t\tconsole.log(\"Failed : pushEventFacebook\");\n\t}\n}\n\nexport function pushEventBing() {\n\ttry {\n\t\twindow.uetq = window.uetq || [];\n\t\twindow.uetq.push({\n\t\t\tec: \"Lead\",\n\t\t\tea: \"Catalog_Request\"\n\t\t});\n\t} catch (error) {\n\t\t// console.log(\"Failed : pushEventBing\");\n\t}\n}\n\n// Function: get user's device size. This function is intentionally duplicated here to be available for global use. Second instance lives in resize-img.js\nexport function getBrowserDevice() {\n\tif (window.matchMedia(\"(max-width : 767px)\").matches) return \"mobile\";\n\tif (window.matchMedia(\"(min-width : 768px) AND (max-width : 1023px)\").matches) return \"tablet\";\n\tif (window.matchMedia(\"(min-width : 1024px)\").matches) return \"desktop\";\n\treturn \"unsure\";\n}\n\n// EVENT - Check for country local storage, set if not already set\nexport async function saveUserCountryToLocalStorage() {\n\tlet userCountry = localStorage.getItem(\"country\");\n\tif (userCountry === null) {\n\t\tuserCountry = await setUserCountry();\n\t}\n}\n\n// set user country in local storage\nasync function setUserCountry() {\n\ttry {\n\t\tlet response = await fetch(\"https://ipinfo.io/json?token=5ddc6962f801d5\");\n\t\tlet data = await response.json();\n\t\tlet userCountry = data.country || \"unknown\";\n\t\tlocalStorage.setItem(\"country\", userCountry);\n\t\treturn userCountry;\n\t} catch (err) {\n\t\tconsole.error(\"Failed to fetch user country.\", err);\n\t\treturn \"unknown\"; // Return a default value in case of an error\n\t}\n}\n\n// Function: check if any modal is open\nexport function checkForOpenModals() {\n\tconst isOpen = sessionStorage.getItem(\"modalOpen\") === \"true\";\n\treturn isOpen;\n}\n\n// Function: check if a wistia video is playing\nexport function checkIfWistiaVideoPlaying() {\n\tconst wistiaVideo = document.querySelector(\".js-video\");\n\tif (wistiaVideo && isWistiaVideoPlaying() !== undefined) {\n\t\treturn true;\n\t} else {\n\t\treturn false;\n\t}\n}\n\n// vanilla wrapper to get cookie value\nexport function getCookie(name) {\n\tlet value = `; ${document.cookie}`;\n\tlet parts = value.split(`; ${name}=`);\n\tif (parts.length === 2) return parts.pop().split(\";\").shift();\n}\n\n// Utility to copy text to clipboard\nexport async function copyToClipboard(val) {\n\ttry {\n\t\tawait navigator.clipboard.writeText(val);\n\t} catch (err) {\n\t\tconsole.error(\"Failed to copy: \", err);\n\t}\n}\n\n// Utility to track browser size for Google Analytics -- are we using this?\nexport function browserSize() {\n\tlet width = window.innerWidth || document.body.clientWidth;\n\tlet height = window.innerHeight || document.body.clientHeight;\n\tlet size = width + \"x\" + height;\n\n\tlet browserSizeCookie = Cookies.get(\"browserSize\");\n\tif (browserSizeCookie === \"blocked\" || browserSizeCookie == null || browserSizeCookie != size) {\n\t\tbrowserSizeCookie = size;\n\t\tCookies.set(\"browserSize\", size, {\n\t\t\texpires: 365\n\t\t});\n\t\tpushEvent(\"Browser Size\", \"Range\", size);\n\t}\n}\n\n// Function: show hero photo credit if name has been entered in CMS\nexport function showHeroPhotoCredit() {\n\tconst photoCredit = document.querySelector(\"[js-hero-photo-credit]\");\n\tif (photoCredit) {\n\t\tconst creditText = photoCredit.textContent.trim();\n\t\tif (creditText.length > 2) {\n\t\t\tphotoCredit.classList.remove(\"hide\");\n\t\t} else {\n\t\t\tphotoCredit.classList.add(\"hide\");\n\t\t}\n\t}\n}\n\n// Need to run on page load but not a huge priority\nexport function setFavIcon() {\n\tconst favicon = document.querySelector(\"[js-set-favicon]\");\n\tconst mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\tif (!favicon) return;\n\tfunction updateFavicon() {\n\t\tfavicon.setAttribute(\"href\", mediaQuery.matches ? \"/assets/images/icons/favicon-dark-mode.png\" : \"/assets/images/icons/favicon-light-mode.png\");\n\t}\n\tupdateFavicon();\n\tmediaQuery.addEventListener(\"change\", updateFavicon);\n}\n\n// Track social icon clicks for GA\nexport function trackSocialClicks(links, area) {\n\tlet socialLinks = document.querySelectorAll(`[${links}]`);\n\tsocialLinks.forEach(function (link) {\n\t\tlink.addEventListener(\"click\", function () {\n\t\t\tlet platform = link.getAttribute(`${links}`);\n\t\t\tpushEvent(\"Clicks\", `Social ${area}`, `${platform}`);\n\t\t});\n\t});\n}\n\n// Functions: check if elements exist\nconst ensureElementExists = (elementSelector, limit) =>\n\tnew Promise((resolve, reject) => {\n\t\tlet count = 0;\n\t\tfunction waitForElement() {\n\t\t\tconst element = document.querySelector(elementSelector);\n\t\t\tif (element) return resolve(element);\n\t\t\tif (limit && count > limit) return false;\n\t\t\tcount += 1;\n\t\t\tsetTimeout(waitForElement, 100);\n\t\t}\n\t\twaitForElement();\n\t});\n\nexport const waitUntilElementExists = async (elementSelector, limit) => {\n\tconst response = await ensureElementExists(elementSelector, limit);\n\treturn response;\n};\n\nexport function addEnsoExample(selector) {\n\tconst element = document.querySelector(selector);\n\tconst elementText = element.innerText;\n\n\tif (element && elementText === \"\") element.classList.add(\"js-enso-example\");\n}\n\nexport function removeMissingImage() {\n\tconst images = document.querySelectorAll(\"[js-remove-missing-image]\");\n\timages.forEach((img) => {\n\t\tif (img.naturalWidth === 0) {\n\t\t\timg.remove();\n\t\t}\n\t});\n}\n","export function isDialogSupported() {\n\t// Directly check for the existence of HTMLDialogElement in the window\n\tif (!window.HTMLDialogElement) return false;\n\n\t// Check if 'show' and 'close' methods are part of the HTMLDialogElement's prototype\n\tconst dialogPrototype = window.HTMLDialogElement.prototype;\n\n\t// Return boolean\n\treturn typeof dialogPrototype.show === \"function\" && typeof dialogPrototype.close === \"function\";\n}\n","import { checkForOpenModals } from \"../../assets/js/utilities.js\";\n\nexport function observeAmbientVideo() {\n\tsessionStorage.setItem(\"modalOpen\", false);\n\n\t// select it\n\tconst videos = document.querySelectorAll(\"[js-ambient-video]\");\n\n\t// check it\n\tif (videos.length === 0) return;\n\n\t// func call to assign active video, return active video element\n\tlet activeVideo = assignActiveAmbientVideo(videos);\n\n\t// resize event listener to call func to reassign active video\n\twindow.addEventListener(\"resize\", () => {\n\t\tactiveVideo = assignActiveAmbientVideo(videos);\n\t});\n\n\t// visibility event listener to call func to pause video when tab is not active\n\tdocument.addEventListener(\"visibilitychange\", () => {\n\t\thandleVisibilityChange(activeVideo);\n\t});\n\n\t// create an observer instance\n\tlet observer = new IntersectionObserver(playOrPauseAmbientVideo, {\n\t\tthreshold: 0.5 // Adjust as necessary\n\t});\n\n\t// observe active video\n\tif (activeVideo) observer.observe(activeVideo);\n}\n\n// play or pause based on tab visibility\nfunction handleVisibilityChange(activeVideo) {\n\tif (checkForOpenModals()) return;\n\n\ttoggleAmbientVideo(!document.hidden, activeVideo);\n}\n\n// find the active video\nfunction assignActiveAmbientVideo(videos) {\n\tconst isMobile = window.matchMedia(\"(orientation: portrait)\").matches;\n\n\tconst activeVideo = Array.from(videos).find((video) => {\n\t\tconst deviceType = isMobile ? \"mobile\" : \"desktop\";\n\t\tconst videoAttribute = video.getAttribute(\"js-ambient-video\");\n\n\t\tif (videoAttribute !== deviceType) {\n\t\t\ttoggleAmbientVideo(false, video); // Pause the video if it's not for the current device type\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t});\n\n\tif (activeVideo) activeVideo.classList.add(\"active\");\n\n\treturn activeVideo;\n}\n\n// play or pause based on intersection and tab visibility\nfunction playOrPauseAmbientVideo(entries) {\n\tentries.forEach((entry) => {\n\t\tlet isModalOpen = checkForOpenModals();\n\t\tif (entry.isIntersecting && !document.hidden && !isModalOpen) {\n\t\t\ttoggleAmbientVideo(true, entry.target);\n\t\t} else {\n\t\t\ttoggleAmbientVideo(false, entry.target);\n\t\t}\n\t});\n}\n\nfunction isAmbientVideoPlaying(videoElement) {\n\treturn !videoElement.paused;\n}\n\nexport function toggleAmbientVideo(shouldPlay, videoElement = null) {\n\t// If a specific video element is provided, use it\n\tif (videoElement) {\n\t\tshouldPlay ? videoElement.play() : videoElement.pause();\n\t\treturn;\n\t}\n\t// Otherwise, find the active video\n\tconst activeVideo = document.querySelector(\"[js-ambient-video].active\");\n\n\tif (activeVideo) shouldPlay ? activeVideo.play() : activeVideo.pause();\n}\n","import { isDialogSupported } from \"../_script.js\";\nimport { pushEvent, isAdmin } from \"../../../assets/js/utilities.js\";\nimport { enso } from \"../../../components/enso/_script.js\";\nimport { copyToClipboard } from \"../../../assets/js/utilities.js\";\nimport { toggleAmbientVideo } from \"../../../components/hero/_video.js\";\n\nexport async function check_url_for_generic_modal() {\n\tlet querySearch = window.location.search;\n\tconst genericQueryPatterns = [/^\\?lightbox=\\/-lightboxes\\/.+/, /^\\?modal=\\/-lightboxes\\/.+/];\n\n\t// Check if the query string matches the generic patterns\n\tif (genericQueryPatterns.some((pattern) => pattern.test(querySearch))) {\n\t\tquerySearch = normalize_generic_modal_path(querySearch);\n\t\tconst targetModalSelector = `[js-modal-generic-url=\"${querySearch}\"]`;\n\t\tlet targetModal = document.querySelector(targetModalSelector);\n\t\tif (!targetModal) {\n\t\t\ttargetModal = await fetch_generic_modal_dialog(querySearch, targetModalSelector);\n\t\t}\n\t\tshowDialog(targetModal);\n\t\tadd_event_close_modal_via_backdrop(targetModal);\n\t\tadd_event_close_modal_via_button(targetModal);\n\t\tadd_event_close_modal_via_esc(targetModal);\n\t\tenso();\n\t}\n}\n\nexport function check_links_for_generic_modal() {\n\tconst genericLinks = document.querySelectorAll(\"a[href*='/-lightboxes/']\"); // find all generic links\n\tfor (const item of genericLinks) {\n\t\tif (item.hasAttribute(\"generic\")) continue; // skip if generic attribute exists, it means it's already been processed\n\t\titem.setAttribute(\"generic\", \"\");\n\t\titem.addEventListener(\"click\", async (event) => {\n\t\t\tevent.preventDefault();\n\t\t\tlet genericURL = item.getAttribute(\"href\");\n\t\t\tlet querySearch = normalize_generic_modal_path(genericURL);\n\t\t\tlet targetModalSelector = `[js-modal-generic-url=\"${querySearch}\"]`;\n\t\t\tlet targetModal = document.querySelector(targetModalSelector);\n\n\t\t\tif (event.shiftKey) {\n\t\t\t\tlet shiftClickUrl = `https://${window.location.hostname}${window.location.pathname}?modal=${querySearch}`;\n\t\t\t\tcopyToClipboard(shiftClickUrl);\n\t\t\t}\n\n\t\t\tif (!targetModal) {\n\t\t\t\ttargetModal = await fetch_generic_modal_dialog(querySearch, targetModalSelector);\n\t\t\t\ttargetModal = document.querySelector(targetModalSelector);\n\t\t\t}\n\t\t\tshowDialog(targetModal);\n\t\t\tadd_event_close_modal_via_backdrop(targetModal);\n\t\t\tadd_event_close_modal_via_button(targetModal);\n\t\t\tadd_event_close_modal_via_esc(targetModal);\n\t\t\tenso();\n\t\t});\n\t}\n}\n\nexport function show_modal_if_url_matches_modal_attribute() {\n\tconst currentPath = window.location.pathname;\n\tconst modal = document.querySelector(\"[js-modal-generic-url]\");\n\tif (modal && modal.getAttribute(\"js-modal-generic-url\") === currentPath) {\n\t\tenso();\n\t\tif (isAdmin()) {\n\t\t\tmodal.show(); // this method to open modal allows access to CMS navbar\n\t\t} else {\n\t\t\tshowDialog(modal);\n\t\t\tadd_event_close_modal_via_backdrop(modal);\n\t\t\tadd_event_close_modal_via_button(modal);\n\t\t\tadd_event_close_modal_via_esc(modal);\n\t\t}\n\t}\n}\n\n// Function to check the size of a single image in the browser and hide/show it if necessary\nfunction check_generic_modal_image_size(modal) {\n\tconst image = modal.querySelector(\"[js-util-check-img-size]\");\n\tconst imageURL = image.getAttribute(\"js-util-check-img-size\");\n\n\tfunction evaluateImageSize() {\n\t\timage.classList.remove(\"hide\");\n\t\timage.clientWidth < 400 ? image.classList.add(\"hide\") : image.classList.remove(\"hide\");\n\t}\n\n\tif (!imageURL.includes(\".\")) {\n\t\timage.remove();\n\t\treturn;\n\t}\n\n\timage.src = imageURL;\n\n\tif (image.complete) {\n\t\tevaluateImageSize();\n\t}\n\n\timage.addEventListener(\"load\", evaluateImageSize);\n\twindow.addEventListener(\"resize\", evaluateImageSize);\n\n\tevaluateImageSize();\n}\n\nfunction normalize_generic_modal_path(modalPath) {\n\tmodalPath = modalPath.replace(/.*\\?lightbox=/, \"\");\n\tmodalPath = modalPath.replace(/.*\\?modal=/, \"\");\n\tmodalPath = modalPath.replace(/.*:\\/\\/[^\\/]*\\/-lightboxes\\//, \"/-lightboxes/\");\n\tmodalPath = modalPath.replace(/#.*/, \"\");\n\tmodalPath = modalPath.replace(/[&?].*/, \"\");\n\treturn modalPath;\n}\n\nasync function fetch_generic_modal_dialog(querySearch, targetModalSelector) {\n\ttry {\n\t\tconst response = await fetch(querySearch);\n\t\tconst fetchedDialog = await response.text();\n\t\tdocument.body.insertAdjacentHTML(\"beforeend\", fetchedDialog);\n\t\tconst modal = document.querySelector(targetModalSelector);\n\t\tif (!modal) {\n\t\t\tthrow new Error(`Modal with selector \"${targetModalSelector}\" not found in the inserted HTML.`);\n\t\t}\n\t\tcdnifyImages();\n\t\treturn modal;\n\t} catch (err) {\n\t\tconsole.warn(\"Something went wrong.\", err);\n\t}\n}\n\nfunction showDialog(modal) {\n\tif (isDialogSupported()) {\n\t\tdocument.body.classList.add(\"modal-open\");\n\t\tmodal.showModal();\n\t} else {\n\t\tpushEvent(\"Dev\", \"Dialog\", \"Not Supported\");\n\t}\n\tsessionStorage.setItem(\"modalOpen\", true);\n\ttoggleAmbientVideo(false);\n\tcheck_generic_modal_image_size(modal);\n}\n\nfunction add_event_close_modal_via_backdrop(modal) {\n\tmodal.addEventListener(\"click\", (event) => {\n\t\tif (event.target === modal) {\n\t\t\tdocument.body.classList.remove(\"modal-open\");\n\t\t\tmodal.close();\n\t\t}\n\t});\n}\n\nfunction add_event_close_modal_via_button(modal) {\n\tconst genericModalClose = modal.querySelector(\"[js-modal-generic-close]\");\n\tgenericModalClose.addEventListener(\"click\", (event) => {\n\t\tevent.preventDefault();\n\t\tdocument.body.classList.remove(\"modal-open\");\n\t\tmodal.close();\n\t});\n}\n\n// Event : if escape key is pressed (but captures all close events)\nfunction add_event_close_modal_via_esc(modal) {\n\tmodal.addEventListener(\"close\", () => {\n\t\tdocument.body.classList.remove(\"modal-open\");\n\t\tmodal.close();\n\t\tsessionStorage.setItem(\"modalOpen\", false);\n\t\ttoggleAmbientVideo(true);\n\t});\n}\n\nexport function openModalsFromShortQuerystring() {\n\tconst urlParams = new URLSearchParams(window.location.search);\n\tconst modalParam = urlParams.get(\"modal\");\n\tconst modalTypes = [\"women\"];\n\n\tif (!modalParam || modalParam.includes(\"/accommodations/\")) return; // why do we need this?\n\n\t// open generic modals from short querystrings (ex. ?modal=women)\n\tif (modalTypes.includes(modalParam)) {\n\t\tlet modal = document.querySelector(`[href*='/-lightboxes/'][href*='${modalParam}']`); // this is looking for a link to lightbox and the param word in it\n\t\tif (modal) modal.click();\n\t\treturn;\n\t}\n}\n","// to do : write test\n// to do : review and refactor\nexport function showMastheadOnUpwardScroll() {\n\tdocument.addEventListener(\"readystatechange\", (event) => {\n\t\tif (event.target.readyState === \"complete\") {\n\t\t\tfunction scrollWatchForMasthead() {\n\t\t\t\tconst html = document.querySelector(\".js-scroll-trigger\");\n\t\t\t\tconst masthead = document.querySelector(\".js-scroll-target\");\n\t\t\t\tconst megaReset = document.querySelector(\"#mega-reset\");\n\t\t\t\tconst heroGradient = document.querySelector(\"[gradient]\");\n\t\t\t\tlet gradient = heroGradient.getAttribute(\"gradient\");\n\t\t\t\tconst scrollUpPostionBuffer = 0.25;\n\t\t\t\tconst scrollDownPostionBuffer = -0.15;\n\t\t\t\tlet scrollUpPositionTarget = 0;\n\t\t\t\tlet scrollDownPositionTarget = scrollDownPostionBuffer;\n\t\t\t\tconst mastheadFavoritesInput = document.querySelector(\"[js-click-masthead-favorites]\");\n\t\t\t\tconst magicCTA = document.querySelector(\"[magic]\");\n\n\t\t\t\tfunction getGradientValue() {\n\t\t\t\t\tif (gradient === \"auto\") {\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tgradient = heroGradient.getAttribute(\"gradient\");\n\t\t\t\t\t\t\tif (gradient === \"auto\") {\n\t\t\t\t\t\t\t\tgetGradientValue();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 100);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tgetGradientValue(); // sneaky little recursive hack to get gradient once that code final runs\n\n\t\t\t\t// Plugin: https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.create()\n\t\t\t\tScrollTrigger.create({\n\t\t\t\t\ttrigger: html,\n\t\t\t\t\tonUpdate: (self) => toggleMasthead(self.direction)\n\t\t\t\t});\n\n\t\t\t\tfunction setScrollBufferPosition(position) {\n\t\t\t\t\treturn position + scrollDownPostionBuffer;\n\t\t\t\t}\n\n\t\t\t\tfunction toggleMasthead(direction) {\n\t\t\t\t\t// direction key : -1 up, 1 down\n\t\t\t\t\t// Plugin: https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.positionInViewport()\n\t\t\t\t\tlet position = ScrollTrigger.positionInViewport(html, \"top\");\n\n\t\t\t\t\t// IMPORTANT: masthead and magicCTA are moving together; when masthead is showing, magicCTA is repositioned to lower on the page\n\n\t\t\t\t\t// Scrolling up, set scrollDownTarget\n\t\t\t\t\tif (direction === -1 && position > scrollUpPositionTarget) {\n\t\t\t\t\t\tmasthead.classList.remove(\"js-masthead-hide\");\n\t\t\t\t\t\tmasthead.classList.add(\"js-masthead-show\");\n\t\t\t\t\t\tscrollDownPositionTarget = position + scrollDownPostionBuffer;\n\t\t\t\t\t\tmagicCTA.classList.remove(\"js-reposition-magic\", \"js-default-magic-position\");\n\t\t\t\t\t}\n\n\t\t\t\t\t// Scrolling down, set scrollUpTarget\n\t\t\t\t\tif (direction === 1 && position < scrollDownPositionTarget) {\n\t\t\t\t\t\tmegaReset.checked = true;\n\t\t\t\t\t\tmasthead.classList.add(\"js-masthead-hide\");\n\t\t\t\t\t\tmasthead.classList.remove(\"js-masthead-show\");\n\t\t\t\t\t\tmastheadFavoritesInput.checked = false;\n\t\t\t\t\t\tscrollUpPositionTarget = position + scrollUpPostionBuffer;\n\t\t\t\t\t\tif (magicCTA.getAttribute(\"js-position\") === \"js-default-magic-position\") {\n\t\t\t\t\t\t\tmagicCTA.classList.add(\"js-default-magic-position\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Reset Masthead\n\t\t\t\t\tif (position === 0) {\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tmasthead.classList.remove(\"js-masthead-show\");\n\t\t\t\t\t\t}, 500);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tscrollWatchForMasthead();\n\t\t}\n\t});\n}\n","import { pushEvent } from \"../../../assets/js/utilities.js\";\nimport { toggleAmbientVideo } from \"../../../components/hero/_video.js\";\n\n// does not make sense that this is in this folder\n// split for mobile and desktop\nexport function mobileSiteNavHandler() {\n\tconst mobileNavToggleLinks = document.querySelectorAll(\"[js-click-toggle]\"); // this attribute also exists on modal close buttons\n\tconst modalReset = document.querySelector(\"#modal-reset\");\n\n\tmobileNavToggleLinks.forEach((link) => {\n\t\tlink.addEventListener(\"click\", function () {\n\t\t\tlet targetElementName = link.getAttribute(\"js-click-toggle\");\n\t\t\tlet targetElementNameToTitle = targetElementName.charAt(0).toUpperCase() + targetElementName.slice(1);\n\t\t\tif (targetElementName) {\n\t\t\t\tpushEvent(\"Misc\", `${targetElementNameToTitle} Mobile Nav`, \"Clicked\");\n\t\t\t}\n\t\t\tmodalReset.setAttribute(\"modal-toggle\", targetElementName);\n\t\t\tsessionStorage.setItem(\"modalOpen\", false);\n\n\t\t\ttoggleAmbientVideo(true);\n\t\t});\n\t});\n}\n","export const countryList = [\n\t{ code: \"AF\", name: \"Afghanistan\" },\n\t{ code: \"AX\", name: \"Åland Islands\" },\n\t{ code: \"AL\", name: \"Albania\" },\n\t{ code: \"DZ\", name: \"Algeria\" },\n\t{ code: \"AS\", name: \"American Samoa\" },\n\t{ code: \"AD\", name: \"Andorra\" },\n\t{ code: \"AO\", name: \"Angola\" },\n\t{ code: \"AI\", name: \"Anguilla\" },\n\t{ code: \"AQ\", name: \"Antarctica\" },\n\t{ code: \"AG\", name: \"Antigua and Barbuda\" },\n\t{ code: \"AR\", name: \"Argentina\" },\n\t{ code: \"AM\", name: \"Armenia\" },\n\t{ code: \"AW\", name: \"Aruba\" },\n\t{ code: \"AU\", name: \"Australia\" },\n\t{ code: \"AT\", name: \"Austria\" },\n\t{ code: \"AZ\", name: \"Azerbaijan\" },\n\t{ code: \"BS\", name: \"Bahamas\" },\n\t{ code: \"BH\", name: \"Bahrain\" },\n\t{ code: \"BD\", name: \"Bangladesh\" },\n\t{ code: \"BB\", name: \"Barbados\" },\n\t{ code: \"BY\", name: \"Belarus\" },\n\t{ code: \"BE\", name: \"Belgium\" },\n\t{ code: \"BZ\", name: \"Belize\" },\n\t{ code: \"BJ\", name: \"Benin\" },\n\t{ code: \"BM\", name: \"Bermuda\" },\n\t{ code: \"BT\", name: \"Bhutan\" },\n\t{ code: \"BO\", name: \"Bolivia (Plurinational State of)\" },\n\t{ code: \"BQ\", name: \"Bonaire, Sint Eustatius and Saba\" },\n\t{ code: \"BA\", name: \"Bosnia and Herzegovina\" },\n\t{ code: \"BW\", name: \"Botswana\" },\n\t{ code: \"BV\", name: \"Bouvet Island\" },\n\t{ code: \"BR\", name: \"Brazil\" },\n\t{ code: \"IO\", name: \"British Indian Ocean Territory\" },\n\t{ code: \"BN\", name: \"Brunei Darussalam\" },\n\t{ code: \"BG\", name: \"Bulgaria\" },\n\t{ code: \"BF\", name: \"Burkina Faso\" },\n\t{ code: \"BI\", name: \"Burundi\" },\n\t{ code: \"CV\", name: \"Cabo Verde\" },\n\t{ code: \"KH\", name: \"Cambodia\" },\n\t{ code: \"CM\", name: \"Cameroon\" },\n\t{ code: \"CA\", name: \"Canada\" },\n\t{ code: \"KY\", name: \"Cayman Islands\" },\n\t{ code: \"CF\", name: \"Central African Republic\" },\n\t{ code: \"TD\", name: \"Chad\" },\n\t{ code: \"CL\", name: \"Chile\" },\n\t{ code: \"CN\", name: \"China\" },\n\t{ code: \"CX\", name: \"Christmas Island\" },\n\t{ code: \"CC\", name: \"Cocos (Keeling) Islands\" },\n\t{ code: \"CO\", name: \"Colombia\" },\n\t{ code: \"KM\", name: \"Comoros\" },\n\t{ code: \"CG\", name: \"Congo\" },\n\t{ code: \"CD\", name: \"Congo (Democratic Republic of the)\" },\n\t{ code: \"CK\", name: \"Cook Islands\" },\n\t{ code: \"CR\", name: \"Costa Rica\" },\n\t{ code: \"CI\", name: \"Côte d'Ivoire\" },\n\t{ code: \"HR\", name: \"Croatia\" },\n\t{ code: \"CU\", name: \"Cuba\" },\n\t{ code: \"CW\", name: \"Curaçao\" },\n\t{ code: \"CY\", name: \"Cyprus\" },\n\t{ code: \"CZ\", name: \"Czech Republic\" },\n\t{ code: \"DK\", name: \"Denmark\" },\n\t{ code: \"DJ\", name: \"Djibouti\" },\n\t{ code: \"DM\", name: \"Dominica\" },\n\t{ code: \"DO\", name: \"Dominican Republic\" },\n\t{ code: \"EC\", name: \"Ecuador\" },\n\t{ code: \"EG\", name: \"Egypt\" },\n\t{ code: \"SV\", name: \"El Salvador\" },\n\t{ code: \"GQ\", name: \"Equatorial Guinea\" },\n\t{ code: \"ER\", name: \"Eritrea\" },\n\t{ code: \"EE\", name: \"Estonia\" },\n\t{ code: \"SZ\", name: \"Eswatini\" },\n\t{ code: \"ET\", name: \"Ethiopia\" },\n\t{ code: \"FK\", name: \"Falkland Islands (Malvinas)\" },\n\t{ code: \"FO\", name: \"Faroe Islands\" },\n\t{ code: \"FJ\", name: \"Fiji\" },\n\t{ code: \"FI\", name: \"Finland\" },\n\t{ code: \"FR\", name: \"France\" },\n\t{ code: \"GF\", name: \"French Guiana\" },\n\t{ code: \"PF\", name: \"French Polynesia\" },\n\t{ code: \"TF\", name: \"French Southern Territories\" },\n\t{ code: \"GA\", name: \"Gabon\" },\n\t{ code: \"GM\", name: \"Gambia\" },\n\t{ code: \"GE\", name: \"Georgia\" },\n\t{ code: \"DE\", name: \"Germany\" },\n\t{ code: \"GH\", name: \"Ghana\" },\n\t{ code: \"GI\", name: \"Gibraltar\" },\n\t{ code: \"GR\", name: \"Greece\" },\n\t{ code: \"GL\", name: \"Greenland\" },\n\t{ code: \"GD\", name: \"Grenada\" },\n\t{ code: \"GP\", name: \"Guadeloupe\" },\n\t{ code: \"GU\", name: \"Guam\" },\n\t{ code: \"GT\", name: \"Guatemala\" },\n\t{ code: \"GG\", name: \"Guernsey\" },\n\t{ code: \"GN\", name: \"Guinea\" },\n\t{ code: \"GW\", name: \"Guinea-Bissau\" },\n\t{ code: \"GY\", name: \"Guyana\" },\n\t{ code: \"HT\", name: \"Haiti\" },\n\t{ code: \"HM\", name: \"Heard Island and McDonald Islands\" },\n\t{ code: \"VA\", name: \"Holy See\" },\n\t{ code: \"HN\", name: \"Honduras\" },\n\t{ code: \"HK\", name: \"Hong Kong\" },\n\t{ code: \"HU\", name: \"Hungary\" },\n\t{ code: \"IS\", name: \"Iceland\" },\n\t{ code: \"IN\", name: \"India\" },\n\t{ code: \"ID\", name: \"Indonesia\" },\n\t{ code: \"IR\", name: \"Iran (Islamic Republic of)\" },\n\t{ code: \"IQ\", name: \"Iraq\" },\n\t{ code: \"IE\", name: \"Ireland\" },\n\t{ code: \"IM\", name: \"Isle of Man\" },\n\t{ code: \"IL\", name: \"Israel\" },\n\t{ code: \"IT\", name: \"Italy\" },\n\t{ code: \"JM\", name: \"Jamaica\" },\n\t{ code: \"JP\", name: \"Japan\" },\n\t{ code: \"JE\", name: \"Jersey\" },\n\t{ code: \"JO\", name: \"Jordan\" },\n\t{ code: \"KZ\", name: \"Kazakhstan\" },\n\t{ code: \"KE\", name: \"Kenya\" },\n\t{ code: \"KI\", name: \"Kiribati\" },\n\t{ code: \"KP\", name: \"Korea (Democratic People's Republic of)\" },\n\t{ code: \"KR\", name: \"Korea (Republic of)\" },\n\t{ code: \"KW\", name: \"Kuwait\" },\n\t{ code: \"KG\", name: \"Kyrgyzstan\" },\n\t{ code: \"LA\", name: \"Lao People's Democratic Republic\" },\n\t{ code: \"LV\", name: \"Latvia\" },\n\t{ code: \"LB\", name: \"Lebanon\" },\n\t{ code: \"LS\", name: \"Lesotho\" },\n\t{ code: \"LR\", name: \"Liberia\" },\n\t{ code: \"LY\", name: \"Libya\" },\n\t{ code: \"LI\", name: \"Liechtenstein\" },\n\t{ code: \"LT\", name: \"Lithuania\" },\n\t{ code: \"LU\", name: \"Luxembourg\" },\n\t{ code: \"MO\", name: \"Macao\" },\n\t{ code: \"MG\", name: \"Madagascar\" },\n\t{ code: \"MW\", name: \"Malawi\" },\n\t{ code: \"MY\", name: \"Malaysia\" },\n\t{ code: \"MV\", name: \"Maldives\" },\n\t{ code: \"ML\", name: \"Mali\" },\n\t{ code: \"MT\", name: \"Malta\" },\n\t{ code: \"MH\", name: \"Marshall Islands\" },\n\t{ code: \"MQ\", name: \"Martinique\" },\n\t{ code: \"MR\", name: \"Mauritania\" },\n\t{ code: \"MU\", name: \"Mauritius\" },\n\t{ code: \"YT\", name: \"Mayotte\" },\n\t{ code: \"MX\", name: \"Mexico\" },\n\t{ code: \"FM\", name: \"Micronesia (Federated States of)\" },\n\t{ code: \"MD\", name: \"Moldova (Republic of)\" },\n\t{ code: \"MC\", name: \"Monaco\" },\n\t{ code: \"MN\", name: \"Mongolia\" },\n\t{ code: \"ME\", name: \"Montenegro\" },\n\t{ code: \"MS\", name: \"Montserrat\" },\n\t{ code: \"MA\", name: \"Morocco\" },\n\t{ code: \"MZ\", name: \"Mozambique\" },\n\t{ code: \"MM\", name: \"Myanmar\" },\n\t{ code: \"NA\", name: \"Namibia\" },\n\t{ code: \"NR\", name: \"Nauru\" },\n\t{ code: \"NP\", name: \"Nepal\" },\n\t{ code: \"NL\", name: \"Netherlands\" },\n\t{ code: \"NC\", name: \"New Caledonia\" },\n\t{ code: \"NZ\", name: \"New Zealand\" },\n\t{ code: \"NI\", name: \"Nicaragua\" },\n\t{ code: \"NE\", name: \"Niger\" },\n\t{ code: \"NG\", name: \"Nigeria\" },\n\t{ code: \"NU\", name: \"Niue\" },\n\t{ code: \"NF\", name: \"Norfolk Island\" },\n\t{ code: \"MK\", name: \"North Macedonia\" },\n\t{ code: \"MP\", name: \"Northern Mariana Islands\" },\n\t{ code: \"NO\", name: \"Norway\" },\n\t{ code: \"OM\", name: \"Oman\" },\n\t{ code: \"PK\", name: \"Pakistan\" },\n\t{ code: \"PW\", name: \"Palau\" },\n\t{ code: \"PS\", name: \"Palestine, State of\" },\n\t{ code: \"PA\", name: \"Panama\" },\n\t{ code: \"PG\", name: \"Papua New Guinea\" },\n\t{ code: \"PY\", name: \"Paraguay\" },\n\t{ code: \"PE\", name: \"Peru\" },\n\t{ code: \"PH\", name: \"Philippines\" },\n\t{ code: \"PN\", name: \"Pitcairn\" },\n\t{ code: \"PL\", name: \"Poland\" },\n\t{ code: \"PT\", name: \"Portugal\" },\n\t{ code: \"PR\", name: \"Puerto Rico\" },\n\t{ code: \"QA\", name: \"Qatar\" },\n\t{ code: \"RE\", name: \"Réunion\" },\n\t{ code: \"RO\", name: \"Romania\" },\n\t{ code: \"RU\", name: \"Russian Federation\" },\n\t{ code: \"RW\", name: \"Rwanda\" },\n\t{ code: \"BL\", name: \"Saint Barthélemy\" },\n\t{ code: \"SH\", name: \"Saint Helena, Ascension and Tristan da Cunha\" },\n\t{ code: \"KN\", name: \"Saint Kitts and Nevis\" },\n\t{ code: \"LC\", name: \"Saint Lucia\" },\n\t{ code: \"MF\", name: \"Saint Martin (French part)\" },\n\t{ code: \"PM\", name: \"Saint Pierre and Miquelon\" },\n\t{ code: \"VC\", name: \"Saint Vincent and the Grenadines\" },\n\t{ code: \"WS\", name: \"Samoa\" },\n\t{ code: \"SM\", name: \"San Marino\" },\n\t{ code: \"ST\", name: \"Sao Tome and Principe\" },\n\t{ code: \"SA\", name: \"Saudi Arabia\" },\n\t{ code: \"SN\", name: \"Senegal\" },\n\t{ code: \"RS\", name: \"Serbia\" },\n\t{ code: \"SC\", name: \"Seychelles\" },\n\t{ code: \"SL\", name: \"Sierra Leone\" },\n\t{ code: \"SG\", name: \"Singapore\" },\n\t{ code: \"SX\", name: \"Sint Maarten (Dutch part)\" },\n\t{ code: \"SK\", name: \"Slovakia\" },\n\t{ code: \"SI\", name: \"Slovenia\" },\n\t{ code: \"SB\", name: \"Solomon Islands\" },\n\t{ code: \"SO\", name: \"Somalia\" },\n\t{ code: \"ZA\", name: \"South Africa\" },\n\t{ code: \"GS\", name: \"South Georgia and the South Sandwich Islands\" },\n\t{ code: \"SS\", name: \"South Sudan\" },\n\t{ code: \"ES\", name: \"Spain\" },\n\t{ code: \"LK\", name: \"Sri Lanka\" },\n\t{ code: \"SD\", name: \"Sudan\" },\n\t{ code: \"SR\", name: \"Suriname\" },\n\t{ code: \"SJ\", name: \"Svalbard and Jan Mayen\" },\n\t{ code: \"SE\", name: \"Sweden\" },\n\t{ code: \"CH\", name: \"Switzerland\" },\n\t{ code: \"SY\", name: \"Syrian Arab Republic\" },\n\t{ code: \"TW\", name: \"Taiwan, Province of China\" },\n\t{ code: \"TJ\", name: \"Tajikistan\" },\n\t{ code: \"TZ\", name: \"Tanzania, United Republic of\" },\n\t{ code: \"TH\", name: \"Thailand\" },\n\t{ code: \"TL\", name: \"Timor-Leste\" },\n\t{ code: \"TG\", name: \"Togo\" },\n\t{ code: \"TK\", name: \"Tokelau\" },\n\t{ code: \"TO\", name: \"Tonga\" },\n\t{ code: \"TT\", name: \"Trinidad and Tobago\" },\n\t{ code: \"TN\", name: \"Tunisia\" },\n\t{ code: \"TR\", name: \"Turkey\" },\n\t{ code: \"TM\", name: \"Turkmenistan\" },\n\t{ code: \"TC\", name: \"Turks and Caicos Islands\" },\n\t{ code: \"TV\", name: \"Tuvalu\" },\n\t{ code: \"UG\", name: \"Uganda\" },\n\t{ code: \"UA\", name: \"Ukraine\" },\n\t{ code: \"AE\", name: \"United Arab Emirates\" },\n\t{ code: \"GB\", name: \"United Kingdom of Great Britain and Northern Ireland\" },\n\t{ code: \"US\", name: \"United States\" },\n\t{ code: \"UM\", name: \"United States Minor Outlying Islands\" },\n\t{ code: \"UY\", name: \"Uruguay\" },\n\t{ code: \"UZ\", name: \"Uzbekistan\" },\n\t{ code: \"VU\", name: \"Vanuatu\" },\n\t{ code: \"VE\", name: \"Venezuela (Bolivarian Republic of)\" },\n\t{ code: \"VN\", name: \"Viet Nam\" },\n\t{ code: \"VG\", name: \"Virgin Islands (British)\" },\n\t{ code: \"VI\", name: \"Virgin Islands (U.S.)\" },\n\t{ code: \"WF\", name: \"Wallis and Futuna\" },\n\t{ code: \"EH\", name: \"Western Sahara\" },\n\t{ code: \"YE\", name: \"Yemen\" },\n\t{ code: \"ZM\", name: \"Zambia\" },\n\t{ code: \"ZW\", name: \"Zimbabwe\" }\n];\n","// Function : Smarty : Select Address\nexport function selectAddress(streetVal, cityVal, stateVal, zipVal, smarty) {\n\tlet userCountry = localStorage.getItem(\"country\") || \"unknown\";\n\tif (userCountry !== \"US\") return;\n\n\tsmarty.streets.forEach((street) => {\n\t\tstreet.value = streetVal;\n\t});\n\tsmarty.cities.forEach((city) => {\n\t\tcity.value = cityVal;\n\t});\n\tsmarty.states.forEach((state) => {\n\t\tstate.value = stateVal;\n\t});\n\tsmarty.zips.forEach((zip) => {\n\t\tzip.value = zipVal;\n\t});\n\tsmarty.countries.forEach((country) => {\n\t\tcountry.value = \"United States\";\n\t});\n\temptyMenu(smarty);\n}\n\n// Function : Empty Element\nexport function emptyMenu(smarty) {\n\tsmarty.menus.forEach((menu) => {\n\t\tvar children = Array.prototype.slice.call(menu.childNodes);\n\t\tchildren.forEach(function (child) {\n\t\t\tmenu.removeChild(child);\n\t\t});\n\t});\n}\n\n// Function : Smarty : Build Menu\nexport function buildAddressMenu(suggestions, smarty) {\n\temptyMenu(smarty);\n\tsuggestions.forEach(function (suggestion) {\n\t\tsmarty.menus.forEach((menu) => {\n\t\t\tlet div = document.createElement(\"div\");\n\t\t\tdiv.setAttribute(\"smarty\", \"selector\");\n\t\t\tdiv.className = \"js-smarty-selector\";\n\t\t\tdiv.innerHTML = `${suggestion.street_line} ${suggestion.city}, ${suggestion.state} ${suggestion.zipcode}`;\n\t\t\tdiv.addEventListener(\"click\", () => selectAddress(suggestion.street_line, suggestion.city, suggestion.state, suggestion.zipcode, smarty));\n\t\t\tmenu.appendChild(div);\n\t\t});\n\t});\n}\n\nexport function initSmarty(form) {\n\tlet smarty = {};\n\t// Create Object : Smarty : Selectors\n\tsmarty.menus = document.querySelectorAll(`${form} .js-smarty-menu`);\n\tsmarty.streets = document.querySelectorAll(`${form} .js-smarty-street`);\n\tsmarty.suites = document.querySelectorAll(`${form} .js-smarty-street-2`);\n\tsmarty.cities = document.querySelectorAll(`${form} .js-smarty-city`);\n\tsmarty.states = document.querySelectorAll(`${form} .js-smarty-state`);\n\tsmarty.zips = document.querySelectorAll(`${form} .js-smarty-zip`);\n\tsmarty.countries = document.querySelectorAll(`${form} .js-smarty-country`);\n\n\tfunction suggestNow(street, smarty) {\n\t\tif (street.value.length < 4) {\n\t\t\treturn;\n\t\t}\n\t\tif (street.value) {\n\t\t\tsmartySuggestions(street.value, smarty);\n\t\t}\n\t}\n\n\t// Function : Smarty : Ajax Post to Smarty Streets\n\tfunction smartySuggestions(search, smarty) {\n\t\tlet ref = `${location.protocol}//${window.location.hostname}`;\n\t\tfetch(`https://us-autocomplete-pro.api.smartystreets.com/lookup?key=91583922427951116&search=${search}&max_results=5`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: {\n\t\t\t\thost: \"us-autocomplete-pro.api.smartystreets.com\",\n\t\t\t\treferer: ref\n\t\t\t}\n\t\t})\n\t\t\t.then(function (response) {\n\t\t\t\treturn response.json();\n\t\t\t})\n\t\t\t.then(function (data) {\n\t\t\t\tif (data.suggestions) {\n\t\t\t\t\tbuildAddressMenu(data.suggestions, smarty);\n\t\t\t\t} else {\n\t\t\t\t\temptyMenu(smarty);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(function (err) {\n\t\t\t\tconsole.warn(\"Something went wrong.\", err);\n\t\t\t});\n\t}\n\n\t// Event : Smarty : Handle typing into street address\n\tsmarty.streets.forEach((street) => {\n\t\tvar current = -1;\n\n\t\tstreet.addEventListener(\n\t\t\t\"keyup\",\n\t\t\t_.throttle(function (event) {\n\t\t\t\tif (street.value.length < 4 || street.value.length > 25) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (event.keyCode === 38 || event.keyCode === 40 || event.keyCode === 13) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsuggestNow(street, smarty);\n\t\t\t}, 1250)\n\t\t);\n\n\t\tstreet.addEventListener(\"keyup\", function (event) {\n\t\t\tif (street.value.length < 4) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.keyCode === 38) {\n\t\t\t\tvar checkExist = setInterval(function () {\n\t\t\t\t\tif (street.nextElementSibling.hasChildNodes() === true) {\n\t\t\t\t\t\tclearInterval(checkExist);\n\t\t\t\t\t}\n\t\t\t\t}, 100);\n\t\t\t\tif (street.nextElementSibling.hasChildNodes() === true) {\n\t\t\t\t\tif (current === 0) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tstreet.nextElementSibling.children[current].classList.remove(\"focus\");\n\t\t\t\t\tcurrent--;\n\t\t\t\t\tstreet.nextElementSibling.children[current].classList.add(\"focus\");\n\t\t\t\t}\n\t\t\t} else if (event.keyCode === 40) {\n\t\t\t\tvar checkExist = setInterval(function () {\n\t\t\t\t\tif (street.nextElementSibling.hasChildNodes() === true) {\n\t\t\t\t\t\tclearInterval(checkExist);\n\t\t\t\t\t}\n\t\t\t\t}, 100);\n\t\t\t\tif (street.nextElementSibling.hasChildNodes() === true) {\n\t\t\t\t\tif (current === street.nextElementSibling.children.length - 1) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (current > -1) {\n\t\t\t\t\t\tstreet.nextElementSibling.children[current].classList.remove(\"focus\");\n\t\t\t\t\t}\n\t\t\t\t\tcurrent++;\n\t\t\t\t\tstreet.nextElementSibling.children[current].classList.add(\"focus\");\n\t\t\t\t}\n\t\t\t} else if (event.keyCode === 13) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (street.nextElementSibling.children[current].classList.contains(\"focus\")) {\n\t\t\t\t\tvar simulateClick = function (elem) {\n\t\t\t\t\t\t// Create our event (with options)\n\t\t\t\t\t\tvar evt = new MouseEvent(\"click\", {\n\t\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\t\tcancelable: true,\n\t\t\t\t\t\t\tview: window\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// If cancelled, don't dispatch our event\n\t\t\t\t\t\tvar canceled = !elem.dispatchEvent(evt);\n\t\t\t\t\t};\n\t\t\t\t\tsimulateClick(street.nextElementSibling.children[current]);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\tcurrent = -1;\n\t\t\t}\n\t\t});\n\t});\n\n\t// Event : Smarty : When suite or city field gains focus\n\tsmarty.suites.forEach((suite) => {\n\t\tsuite.addEventListener(\"focus\", function () {\n\t\t\temptyMenu(smarty);\n\t\t});\n\t});\n\n\tsmarty.cities.forEach((city) => {\n\t\tcity.addEventListener(\"focus\", function () {\n\t\t\temptyMenu(smarty);\n\t\t});\n\t});\n}\n","let urlParamstoCookiesList = [\"gclid\", \"msclkid\", \"fbclid\", \"utmterm\", \"cid\"];\n\nexport function setOptsOnMarketoForm() {\n\tdocument.querySelector(\"#optInNHA\").value = true;\n\tdocument.querySelector(\"#optInWebinar\").value = true;\n\tdocument.querySelector(\"#optInStories\").value = true;\n\tdocument.querySelector(\"#optInSurveys\").value = true;\n\tdocument.querySelector(\"#optInTripDrips\").value = true;\n\tdocument.querySelector(\"#optInSalesperson\").value = true;\n}\n\nexport function setSMSOptsOnMarketoForm() {\n\tdocument.querySelector(\"#optInSMS\").value = true;\n}\n\nexport function isFormValid(formName) {\n\tvar invalidCount = $(formName).find(\":invalid\").length;\n\tif (invalidCount > 0) {\n\t\t$(formName).find(\":invalid\").addClass(\"js-invalid\");\n\t\treturn false;\n\t} else {\n\t\treturn true;\n\t}\n}\n\nexport function isNewsletterChecked(formName) {\n\treturn document.querySelector(`${formName} ${formName}-requestNewsletter`).checked;\n}\n\nexport function isSMSOptinChecked(formName) {\n\treturn document.querySelector(`${formName} ${formName}-Optin-SMS`).checked;\n}\n\n// Add event listener to name input to remove special characters\nexport function initJsFormatName() {\n\tconst nameInputs = document.querySelectorAll(\"[js-format-name]\");\n\n\tif (!nameInputs) return;\n\n\tnameInputs.forEach((input) => {\n\t\tinput.addEventListener(\"blur\", () => {\n\t\t\tencodeSpecialChars(input);\n\t\t});\n\t});\n}\n\nfunction encodeSpecialChars(input) {\n\tlet inputValue = input.value;\n\n\tif (inputValue.match(/&/g)) input.value = inputValue.replace(/&/g, \"and\");\n\n\tif (inputValue.match(/[!@#$%^*(),.?\":{}|<>]/g)) input.value = inputValue.replace(/[!@#$%^*(),.?\":{}|<>]/g, \"\");\n}\n\n// Add event listener to phone input\nexport function initJsFormatPhone() {\n\t// select it\n\tconst phoneInputs = document.querySelectorAll(\"[js-format-phone]\");\n\n\t// check it\n\tif (!phoneInputs) return;\n\n\t// handle it\n\tphoneInputs.forEach((input) => {\n\t\tinput.addEventListener(\"blur\", () => {\n\t\t\tformatAndValidatePhoneNumber(input);\n\t\t});\n\t});\n}\n\n// Format and validate phone numbers\nexport function formatAndValidatePhoneNumber(phoneInput) {\n\tlet phoneNumber = phoneInput.value.replace(/\\D/g, \"\");\n\n\tif (phoneNumber.length >= 3) {\n\t\tphoneNumber = \"(\" + phoneNumber.substr(0, 3) + \") \" + phoneNumber.substr(3);\n\t\tif (phoneNumber.length > 9) {\n\t\t\tphoneNumber = phoneNumber.slice(0, 9) + \"-\" + phoneNumber.slice(9);\n\t\t}\n\t}\n\n\tphoneInput.value = phoneNumber;\n\n\tif (phoneInput.hasAttribute(\"required\")) {\n\t\tconst phonePattern = /^\\(\\d{3}\\) \\d{3}-\\d{4}$/;\n\t\tif (!phonePattern.test(phoneNumber)) {\n\t\t\tphoneInput.classList.add(\"js-invalid\");\n\t\t\tphoneInput.setCustomValidity(\"invalid\");\n\t\t} else {\n\t\t\tphoneInput.classList.remove(\"js-invalid\");\n\t\t\tphoneInput.setCustomValidity(\"\");\n\t\t}\n\t} else {\n\t\tphoneInput.classList.remove(\"js-invalid\");\n\t\tphoneInput.setCustomValidity(\"\");\n\t}\n}\n\nexport function setNewsletterCheckbox() {\n\tlet listOfCheckboxes = document.querySelectorAll(\".js-set-by-country\");\n\tlistOfCheckboxes.forEach((element) => {\n\t\telement.setAttribute(\"checked\", \"checked\");\n\t});\n}\n\n// BUG? This may break if two ctas are used without a page refresh\n// Also this code is confusing especially the [].forEach .... is this using lodash or vanilla js\nexport function specificTarget(inputID, labelFor, listName, targetName) {\n\tvar targetList = document.querySelectorAll(`${inputID}, ${labelFor}, ${listName}`);\n\t[].forEach.call(targetList, function (target) {\n\t\tif ($(target).is('[list^=\"replace\"]') && $(target).is('[id^=\"replace\"]')) {\n\t\t\t$(target).attr(\"list\", $(target).attr(\"list\").replace(\"replace\", `${targetName}`));\n\t\t\t$(target).attr(\"id\", $(target).attr(\"id\").replace(\"replace\", `${targetName}`));\n\t\t} else if ($(target).is('[id^=\"replace\"]')) {\n\t\t\t$(target).attr(\"id\", $(target).attr(\"id\").replace(\"replace\", `${targetName}`));\n\t\t} else if ($(target).is('[for^=\"replace\"]')) {\n\t\t\t$(target).attr(\"for\", $(target).attr(\"for\").replace(\"replace\", `${targetName}`));\n\t\t}\n\t});\n}\n\nexport function mktoButtonClick() {\n\t$(\".mktoButton\").first().click();\n}\n\nexport function pushUtmToMarketoForm() {\n\ttry {\n\t\tdocument.querySelector(\"#utmcampaign\").value = utmObject.utmcampaign || \"\";\n\t\tdocument.querySelector(\"#utmcontent\").value = utmObject.utmcontent || \"\";\n\t\tdocument.querySelector(\"#utmmedium\").value = utmObject.utmmedium || \"\";\n\t\tdocument.querySelector(\"#utmsource\").value = utmObject.utmsource || \"\";\n\t\tdocument.querySelector(\"#utmterm\").value = utmObject.utmterm || \"\";\n\n\t\t$(\"#gclid\").val(utmObject.gclid || \"\");\n\t\t$(\"#fbclid\").val(utmObject.fbclid || \"\");\n\t\t$(\"#msclkid\").val(utmObject.msclkid || \"\");\n\t\t$(\"#cid\").val(utmObject.cid || \"\");\n\t} catch (error) {\n\t\tconsole.error(\"Error: \", error);\n\t}\n}\n\nexport function initMarketoFormBasics(formName) {\n\t// First Name\n\tdocument.querySelector(\"#LastName\").value = document.querySelector(`${formName} ${formName}-last_name`).value;\n\tdocument.querySelector(\"#FirstName\").value = document.querySelector(`${formName} ${formName}-first_name`).value;\n\tdocument.querySelector(\"#Email\").value = document.querySelector(`${formName} ${formName}-email`).value;\n\tdocument.querySelector(\"#LeadSource\").value = \"www.nathab.com\";\n\n\t// Set Click IDs from Cookie, or param if cookie is missing\n\turlParamstoCookiesList.forEach(function (parameter) {\n\t\t$(`#${parameter}`).val(utmObject[parameter]);\n\t});\n\n\t// Set Recent Conversion Action\n\tdocument.querySelector(\"#recentConversionAction\").value = document.querySelector(`${formName} [rca~=\"value\"]`).value;\n\n\t// ReferredAt = document.URL;\n\tdocument.querySelector(\"#requestedAt\").value = document.URL;\n\n\t// Referring Website from cookie\n\t$(\"#referringWebsite\").val(utmObject.referringWebsite || \"\");\n}\n\nexport function initMarketoFormCatalogBasic(formName) {\n\tdocument.querySelector(\"#Address\").value = document.querySelector(`${formName} ${formName}-pdfRequestHomeStreet`).value;\n\tdocument.querySelector(\"#addressLine2\").value = document.querySelector(`${formName} ${formName}-pdfRequestHomeStreet2`).value;\n\tdocument.querySelector(\"#City\").value = document.querySelector(`${formName} ${formName}-pdfRequestHomeCity`).value;\n\tdocument.querySelector(\"#State\").value = document.querySelector(`${formName} ${formName}-pdfRequestHomeState`).value;\n\tdocument.querySelector(\"#PostalCode\").value = document.querySelector(`${formName} ${formName}-pdfRequestHomeZIP`).value;\n\tvar countryValue = $(formName).find(`${formName}-pdfRequestHomeCountry`).val();\n\tdocument.querySelector(\"#Country\").value = countryValue;\n\tif (document.querySelector(`${formName} ${formName}-informationRequestPhone` != null)) {\n\t\tdocument.querySelector(\"#Phone\").value = document.querySelector(`${formName} ${formName}-informationRequestPhone`).value;\n\t}\n}\n\nexport function initMarketoFormCatalogExtra(formName) {\n\tdocument.querySelector(\"#temp8CatReferralSource\").value = document.querySelector(`${formName} ${formName}-find-nathab`).value;\n\tdocument.querySelector(\"#temp9CatReferralName\").value = document.querySelector(`${formName} ${formName}-friend-referral`).value;\n\tdocument.querySelector(\"#temp10CatPartySize\").value = document.querySelector(`${formName} ${formName}-party-size`).value;\n\tdocument.querySelector(\"#temp11CatBudget\").value = document.querySelector(`${formName} ${formName}-trip-budget`).value;\n\tdocument.querySelector(\"#temp12CatAvailability\").value = document.querySelector(`${formName} ${formName}-seasonYearInfo`).value;\n\tdocument.querySelector(\"#temp13CatTripSpecifics\").value = document.querySelector(`${formName} ${formName}-itinRequest`).value;\n\n\tif (document.querySelector(`${formName} ${formName}-company_name` != null)) {\n\t\tdocument.querySelector(\"#Company\").value = document.querySelector(`${formName} ${formName}-company_name`).value;\n\t}\n\n\t// Previous traveled checkboxes\n\tif (document.querySelector(`${formName} ${formName}-previously-traveled-africa`).checked) {\n\t\tdocument.querySelector(\"#previousTravelinAfrica\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-previously-traveled-alaska`).checked) {\n\t\tdocument.querySelector(\"#previousTravelinAlaska\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-previously-traveled-antarctica`).checked) {\n\t\tdocument.querySelector(\"#previousTravelinAntarctica\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-previously-traveled-arctic`).checked) {\n\t\tdocument.querySelector(\"#previousTravelinArctic\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-previously-traveled-asia`).checked) {\n\t\tdocument.querySelector(\"#previousTravelinAsia\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-previously-traveled-central-america`).checked) {\n\t\tdocument.querySelector(\"#previousTravelinCentralAmerica\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-previously-traveled-galapagos`).checked) {\n\t\tdocument.querySelector(\"#previousTravelinGalapagos\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-previously-traveled-south-america`).checked) {\n\t\tdocument.querySelector(\"#previousTravelinSouthAmerica\").value = true;\n\t}\n\n\t// Interests Checkboxes\n\tif (document.querySelector(`${formName} ${formName}-destination-polar-bears`).checked) {\n\t\tdocument.querySelector(\"#interestinPolarBears\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-africa`).checked) {\n\t\tdocument.querySelector(\"#interestinAfrica\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-galapagos`).checked) {\n\t\tdocument.querySelector(\"#interestinGalapagos\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-northern`).checked) {\n\t\tdocument.querySelector(\"#interestinAlaskaNorth\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-central-america`).checked) {\n\t\tdocument.querySelector(\"#interestinCentralAmerica\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-national-parks`).checked) {\n\t\tdocument.querySelector(\"#interestinUSNatlParks\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-asia-pacific`).checked) {\n\t\tdocument.querySelector(\"#interestinAsiaPacific\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-south-america`).checked) {\n\t\tdocument.querySelector(\"#interestinSouthAmerica\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-europe`).checked) {\n\t\tdocument.querySelector(\"#interestinEurope\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-destination-antarctica`).checked) {\n\t\tdocument.querySelector(\"#interestinPolar\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-interest-general-nature`).checked) {\n\t\tdocument.querySelector(\"#interestinGeneralNature\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-interest-nature-photography`).checked) {\n\t\tdocument.querySelector(\"#interestinPhoto\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-interest-family`).checked) {\n\t\tdocument.querySelector(\"#interestinFamily\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-interest-hiking-kayaking`).checked) {\n\t\tdocument.querySelector(\"#interestinActive\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-interest-cruising`).checked) {\n\t\tdocument.querySelector(\"#interestinCruises\").value = true;\n\t}\n\tif (document.querySelector(`${formName} ${formName}-interest-custom`).checked) {\n\t\tdocument.querySelector(\"#interestinCustom\").value = true;\n\t}\n\n\t// Travel Frequency\n\tvar travelFrequency = document.querySelectorAll(`${formName} [name='travel-frequency']`);\n\ttravelFrequency.forEach((radio) => {\n\t\tif (radio.checked) {\n\t\t\tdocument.querySelector(\"#temp15CatTravelFrequency\").value = radio.value;\n\t\t}\n\t});\n}\n\nexport function initMarketoFormOptins() {\n\tdocument.querySelector(\"#optInNHA\").value = true;\n\tdocument.querySelector(\"#optInWebinar\").value = true;\n\tdocument.querySelector(\"#optInStories\").value = true;\n\tdocument.querySelector(\"#optInSurveys\").value = true;\n\tdocument.querySelector(\"#optInTripDrips\").value = true;\n\tdocument.querySelector(\"#optInSalesperson\").value = true;\n}\n\nexport function toggleButtonDisabled(button) {\n\tbutton.setAttribute(\"disabled\", \"true\");\n\tsetTimeout(function () {\n\t\tbutton.removeAttribute(\"disabled\");\n\t}, 15000);\n}\n\nexport function isThisSpam(formName) {\n\tvar fields = [\"first_name\", \"last_name\"];\n\tfor (const field of fields) {\n\t\tlet target = `${formName}-${field}`;\n\t\tvar spamCheck = document.querySelector(`${formName} ${target}`).value;\n\t\tif (spamCheck.match(/[!@#$%^&*(),.?\":{}|<>]/g)) {\n\t\t\treturn true;\n\t\t}\n\t}\n}\n\nexport function validateForm(formName) {\n\tvar invalidCount = $(formName).find(\":invalid\").length;\n\tif (invalidCount > 0) {\n\t\t$(formName).find(\":invalid\").addClass(\"js-invalid\");\n\t\treturn false;\n\t} else {\n\t\treturn true;\n\t}\n}\n\nexport function setRequiredFields(formName) {\n\t$(formName).find(\"[js-required]\").attr(\"required\", \"\");\n}\n\nexport function unSetRequiredFields(formName) {\n\t$(formName).find(\"[js-required]\").removeAttr(\"required\");\n}\n\n// Disable sibling(ish) checkboxes after x checkbox is checked\nexport function limitCheckboxes(form) {\n\tlet arrayOfCheckboxLists = document.querySelectorAll(`${form} [js-limit]`); // sort of vague\n\tarrayOfCheckboxLists.forEach((checkboxList) => {\n\t\tlet max = parseInt(checkboxList.getAttribute(\"js-limit\"), 10);\n\t\tlet arrayOfCheckboxes = checkboxList.querySelectorAll(\"input[type='checkbox']\");\n\t\tlet totalChecked = 0;\n\n\t\tarrayOfCheckboxes.forEach((checkbox) => {\n\t\t\tcheckbox.addEventListener(\"change\", () => {\n\t\t\t\tif (checkbox.checked) {\n\t\t\t\t\ttotalChecked++;\n\t\t\t\t} else {\n\t\t\t\t\ttotalChecked--;\n\t\t\t\t}\n\t\t\t\tif (totalChecked > max) {\n\t\t\t\t\tcheckbox.checked = false;\n\t\t\t\t\ttotalChecked--;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t});\n}\n\nexport function updateFormButtonText(formName) {\n\tvar originalButtonText = $(formName).find(\".js-button-submit\").text();\n\t$(formName).find(\".js-button-submit\").prop(\"disabled\", \"true\");\n\tsetTimeout(function () {\n\t\t$(formName).find(\".js-button-submit\").text(\"Saving ...\");\n\t}, 500);\n\tsetTimeout(function () {\n\t\t$(formName).find(\".js-button-submit\").text(\"Thank You!\");\n\t}, 2000);\n\tsetTimeout(function () {\n\t\t$(formName).find(\".js-button-submit\").text(originalButtonText);\n\t\t$(formName).find(\".js-button-submit\").prop(\"disabled\", \"\");\n\t}, 5000);\n}\n","// Import dependencies:\n// - List of countries\n// - Helper functions for formatting, validation, and interaction with Marketo forms\nimport { countryList } from \"../../../components/lists/country-list/_country-list.js\";\nimport { initSmarty } from \"../../../assets/js/smartypants.js\";\nimport { setOptsOnMarketoForm, setSMSOptsOnMarketoForm, isSMSOptinChecked, isFormValid, isNewsletterChecked, initJsFormatPhone, initJsFormatName, setNewsletterCheckbox, specificTarget, mktoButtonClick, pushUtmToMarketoForm, initMarketoFormBasics, initMarketoFormCatalogBasic, initMarketoFormCatalogExtra, initMarketoFormOptins, toggleButtonDisabled, isThisSpam, validateForm, setRequiredFields, unSetRequiredFields, limitCheckboxes, updateFormButtonText } from \"../../../assets/js/global-form-functions.js\";\nimport { pushEvent, pushEventFacebook, pushEventBing, saveUserCountryToLocalStorage } from \"../../../assets/js/utilities.js\";\nimport { toggleAmbientVideo } from \"../../../components/hero/_video.js\";\n\n// Asynchronous function to handle the catalog modal form interactions\nexport async function modalCatalog() {\n\t// Save the user's country to local storage (assumes an async operation, e.g., API call)\n\tawait saveUserCountryToLocalStorage();\n\n\t// Retrieve the user's country from local storage, default to \"unknown\" if not set\n\tlet userCountry = localStorage.getItem(\"country\") || \"unknown\";\n\n\t// Store the current page URL for future reference\n\tlet pageURL = document.URL;\n\n\t// Initialize the catalog object to hold various form elements and properties\n\tlet catalog = new Object();\n\tlet enewsChecked, smsChecked;\n\tcatalog.formName = \"#form-catalog\"; // Form selector\n\tcatalog.newsletter = false; // Newsletter subscription status\n\tcatalog.smsElementParent = document.querySelector(\".js-sms-checkbox-catalog\"); // Parent element for SMS checkbox\n\tcatalog.smsElement = document.querySelector(\"[js-catalog-sms]\"); // SMS checkbox element\n\tcatalog.phoneElementInput = document.querySelector(\"[js-catalog-phone-toggle]\"); // Phone input element\n\tcatalog.phoneElementLabel = document.querySelector('[for~=\"form-catalog-phone\"]'); // Phone label element\n\tcatalog.locationSelector = \"js-catalog-location\"; // Selector for location elements\n\tcatalog.locationFirstElement = document.querySelector(`[${catalog.locationSelector}]`); // First location element\n\tcatalog.locationAllElements = document.querySelectorAll(`[${catalog.locationSelector}]`); // All location elements\n\tcatalog.locationValue = \"Unknown\"; // Default location value\n\tcatalog.firstInput = document.querySelector(\"[catalog-form-label]\"); // First input field in the form\n\n\t// Elements for different form screens (required, optional, thank you)\n\tlet catalogScreenRequired = document.querySelector(\".js-catalog-required\"),\n\t\tcatalogScreenOptional = document.querySelector(\".js-catalog-optional\"),\n\t\tcatalogScreenThankYou = document.querySelector(\".js-catalog-thankyou\");\n\n\t// Initialize phone and name formatting functions\n\tinitJsFormatPhone();\n\tinitJsFormatName();\n\n\t// Function to handle changes to the SMS checkbox\n\tfunction smsCheckbox() {\n\t\tcatalog.smsElement.addEventListener(\"input\", function () {\n\t\t\tif (this.checked) {\n\t\t\t\t// If SMS checkbox is checked, make the phone input required\n\t\t\t\tcatalog.phoneElementInput.setAttribute(\"required\", \"\");\n\t\t\t\tcatalog.phoneElementLabel.setAttribute(\"catalog-form-label\", \"required\");\n\t\t\t} else {\n\t\t\t\t// If unchecked, remove the required attribute\n\t\t\t\tcatalog.phoneElementInput.removeAttribute(\"required\");\n\t\t\t\tcatalog.phoneElementLabel.setAttribute(\"catalog-form-label\", \"\");\n\t\t\t}\n\t\t});\n\t}\n\n\t// Add event listener to all elements with the locationSelector attribute\n\tcatalog.locationAllElements.forEach((element) => {\n\t\telement.addEventListener(\"click\", function () {\n\t\t\t// Set a session storage flag indicating the modal is open\n\t\t\tsessionStorage.setItem(\"modalOpen\", true);\n\n\t\t\t// Pause ambient video when modal is opened\n\t\t\ttoggleAmbientVideo(false);\n\n\t\t\t// Populate country input fields with the user's country if known\n\t\t\tconst countryInput = document.querySelectorAll(`${catalog.formName} .js-smarty-country`);\n\t\t\tif (userCountry !== \"unknown\") {\n\t\t\t\tcountryInput.forEach((input) => {\n\t\t\t\t\tconst country = countryList.filter((country) => userCountry === country.code);\n\t\t\t\t\tinput.value = country[0].name;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Set newsletter checkbox for users in specific countries and show SMS checkbox if necessary\n\t\t\tif (userCountry === \"US\") {\n\t\t\t\tsetNewsletterCheckbox();\n\t\t\t\tinitSmarty(catalog.formName);\n\t\t\t\tcatalog.smsElementParent.classList.remove(\"hide\");\n\t\t\t\tsmsCheckbox();\n\t\t\t} else if (userCountry === \"IN\" || userCountry === \"AU\") {\n\t\t\t\tsetNewsletterCheckbox();\n\t\t\t}\n\n\t\t\t// Initialize the Marketo form if it has not been loaded\n\t\t\tif (checkMarketoForm() === false) {\n\t\t\t\tinitMarketoForm();\n\t\t\t}\n\n\t\t\t// Update catalog location value based on the clicked element's attribute\n\t\t\tif (catalog.locationValue !== \"URL\") {\n\t\t\t\tcatalog.locationValue = element.getAttribute(catalog.locationSelector);\n\t\t\t}\n\n\t\t\t// Push an event for tracking purposes\n\t\t\tpushEvent(\"Catalog\", catalog.locationValue, \"Open\");\n\n\t\t\t// Focus on the first input field after a short delay\n\t\t\tsetTimeout(() => {\n\t\t\t\tcatalog.firstInput.focus();\n\t\t\t}, 1000);\n\t\t});\n\t});\n\n\t// Handle clicks on links that have a hash or lightbox-related URL\n\tlet linksWithHash = document.querySelectorAll(\"a[href^='#']\");\n\tlet linksWithHashNormalized = [];\n\tlinksWithHash.forEach((link) => {\n\t\tlet href = link.getAttribute(\"href\").toLowerCase();\n\t\tif (href.includes(\"#catalog\")) {\n\t\t\tlinksWithHashNormalized.push(link);\n\t\t}\n\t});\n\tlet linksWithLightbox = document.querySelectorAll(\"a[href~='?lightbox=catalog']\");\n\tlet linksCombined = [...linksWithHashNormalized, ...linksWithLightbox];\n\n\t// If matching links exist, add click event listeners to them\n\tif (linksCombined.length > 0) {\n\t\taddClickEvents(linksCombined);\n\t\tfunction addClickEvents(list) {\n\t\t\tlist.forEach((element) => {\n\t\t\t\telement.addEventListener(\"click\", function (e) {\n\t\t\t\t\te.preventDefault(); // Prevent default link behavior\n\t\t\t\t\tcatalog.locationValue = \"Link\"; // Set location to \"Link\"\n\t\t\t\t\tcatalog.locationFirstElement.click(); // Trigger the modal open event\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\t// Automatically open modal if URL contains specific hash or query parameters\n\tif (pageURL.indexOf(\"#catalog\") > 0 || pageURL.indexOf(\"#Catalog\") > 0 || window.location.search.match(/lightbox\\=catalog/i)) {\n\t\tcatalog.locationValue = \"URL\"; // Set location to \"URL\"\n\t\tcatalog.locationFirstElement.click(); // Trigger the modal open event\n\t}\n\n\t// Show or hide the \"Who Referred You?\" input based on the selected referral option\n\tlet referralOptions = document.querySelector(\".js-show-hide-who-referred\");\n\tlet friendReferralInput = document.querySelector(\".js-show-hide-me\");\n\n\treferralOptions.addEventListener(\"input\", function () {\n\t\tlet referralChoice = referralOptions.value;\n\t\tif (referralChoice === \"Friend\") {\n\t\t\tfriendReferralInput.classList.remove(\"hide\");\n\t\t} else {\n\t\t\tfriendReferralInput.classList.add(\"hide\");\n\t\t}\n\t});\n\n\t// Event listener for submitting the required form\n\tdocument.querySelector(\".js-catalog-button-required\").addEventListener(\"click\", function (e) {\n\t\te.preventDefault(); // Prevent form submission\n\t\tpostFormCatalog(); // Call form submission function\n\t});\n\n\t// Event listener for submitting the optional form\n\tdocument.querySelector(\".js-catalog-button-optional\").addEventListener(\"click\", function (e) {\n\t\te.preventDefault(); // Prevent form submission\n\t\tpostFormOptional(); // Call form submission function\n\t});\n\n\t// Function to create a unique ID using a specific pattern\n\tfunction createUniqueID() {\n\t\treturn \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n\t\t\tlet r = (Math.random() * 16) | 0,\n\t\t\t\tv = c == \"x\" ? r : (r & 0x3) | 0x8;\n\t\t\treturn v.toString(16);\n\t\t});\n\t}\n\n\t// Generate a unique ID for form tracking\n\tlet uniqueFormId = createUniqueID();\n\n\t// Copy fields from the catalog form to the Marketo form\n\tfunction copyCatalogFieldsToMarketoForm() {\n\t\tlet fieldsToCopyArray = document.querySelectorAll(`${catalog.formName} [mrkto-field]`);\n\t\tfieldsToCopyArray.forEach((field) => {\n\t\t\tlet mrktoFieldSelector = field.getAttribute(\"mrkto-field\");\n\t\t\tif (field.value) {\n\t\t\t\tdocument.querySelector(mrktoFieldSelector).value = field.value;\n\t\t\t}\n\t\t});\n\t}\n\n\t// Copy checkbox fields from the catalog form to the Marketo form\n\tfunction pushToMarketoCatalogOptional(formName) {\n\t\tlet checkboxesToCopyArray = document.querySelectorAll(`${catalog.formName} [mrkto-checkbox]`);\n\t\tcheckboxesToCopyArray.forEach((checkbox) => {\n\t\t\tlet mrktoCheckboxSelector = checkbox.getAttribute(\"mrkto-checkbox\");\n\t\t\tif (checkbox.checked) {\n\t\t\t\tdocument.querySelector(mrktoCheckboxSelector).value = checkbox.value;\n\t\t\t}\n\t\t});\n\n\t\tlet travelFrequency = document.querySelectorAll(`${formName} [name='travel-frequency']`);\n\t\ttravelFrequency.forEach((radio) => {\n\t\t\tif (radio.checked) {\n\t\t\t\tdocument.querySelector(\"#temp15CatTravelFrequency\").value = radio.value;\n\t\t\t}\n\t\t});\n\t}\n\n\t// Function to handle the submission of the required form\n\tfunction postFormCatalog() {\n\t\tlet retryLimit = 3, // Max number of retries for form submission\n\t\t\tretryAttempt = 0;\n\n\t\t// Validate the form, exit if invalid\n\t\tlet isValid = isFormValid(catalog.formName);\n\t\tif (isValid === false) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if the form is spam, exit if true\n\t\tif (isThisSpam(catalog.formName) === true) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Disable the submit button\n\t\ttoggleButtonDisabled(document.querySelector(\".js-catalog-button-required\"));\n\n\t\t// Retry initializing the Marketo form if not loaded\n\t\tif (checkMarketoForm() === false && retryAttempt < retryLimit) {\n\t\t\tinitMarketoForm(function () {\n\t\t\t\tretryAttempt++;\n\t\t\t\tpostFormCatalog();\n\t\t\t});\n\t\t}\n\n\t\t// Submit the form using Marketo\n\t\tMktoForms2.whenReady(function () {\n\t\t\tenewsChecked = isNewsletterChecked(catalog.formName);\n\t\t\tsmsChecked = isSMSOptinChecked(catalog.formName);\n\n\t\t\tpushUtmToMarketoForm(); // Add UTM parameters to the Marketo form\n\t\t\tdocument.querySelector(\"#catalogOptionalFieldIndicator\").value = false;\n\t\t\tdocument.querySelector(\"#requestedAt\").value = document.URL;\n\t\t\tdocument.querySelector(\"#LeadSource\").value = \"www.nathab.com\";\n\t\t\tdocument.querySelector(\"#uniqueVisitorID\").value = uniqueFormId;\n\t\t\tdocument.querySelector(\"#temp\").value = \"CatRequestIsTrue\";\n\t\t\tdocument.querySelector(\"#sourceDetail\").value = \"Catalog Request\";\n\t\t\tdocument.querySelector(\"#recentConversionAction\").value = \"Catalog Request\";\n\t\t\tdocument.querySelector(\"#referringWebsite\").value = utmObject.referringWebsite || \"\";\n\t\t\tdocument.querySelector(\"#isCatalogRequested\").value = true;\n\n\t\t\t// Copy form fields to Marketo form\n\t\t\tcopyCatalogFieldsToMarketoForm(catalog.formName);\n\n\t\t\t// Set Marketo form options for email and SMS signups\n\t\t\tif (enewsChecked === true) {\n\t\t\t\tdocument.querySelector(\"#isEmailSignup\").value = true;\n\t\t\t\tsetOptsOnMarketoForm();\n\t\t\t}\n\t\t\tif (smsChecked === true) {\n\t\t\t\tdocument.querySelector(\"#isSMSSignup\").value = true;\n\t\t\t\tsetSMSOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\t// Submit the Marketo form\n\t\t\tmarketoSubmitFormCatalog();\n\n\t\t\tlet optins = \"\";\n\n\t\t\t// Set form options for email and SMS signups, if selected\n\t\t\tif (isNewsletterChecked(catalog.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isEmailSignup\").value = true;\n\t\t\t\toptins += \" eNews,\";\n\t\t\t\tsetOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\tif (isSMSOptinChecked(catalog.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isSMSSignup\").value = true;\n\t\t\t\toptins += \" SMS\";\n\t\t\t\tsetSMSOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\t// Set optins string for analytics event\n\t\t\toptins = optins || \" no optins\";\n\t\t\toptins = optins.endsWith(\",\") ? optins.slice(0, -1) : optins;\n\n\t\t\t// Push event to analytics platforms\n\t\t\tlet pushEventString = `Submitted Page 1 w/${optins}`;\n\t\t\tpushEvent(\"Catalog\", catalog.locationValue, pushEventString);\n\n\t\t\t// Push events to analytics platforms\n\t\t\tpushEventFacebook();\n\t\t\tpushEventBing();\n\n\t\t\t// Limit the number of checkboxes that can be selected\n\t\t\tlimitCheckboxes(catalog.formName);\n\n\t\t\t// Show the optional form screen after a delay\n\t\t\tsetTimeout(() => {\n\t\t\t\tcatalogScreenRequired.classList.add(\"hide\");\n\t\t\t\tcatalogScreenOptional.classList.remove(\"hide\");\n\t\t\t}, 2750);\n\t\t});\n\t}\n\n\t// Function to handle the submission of the optional form\n\tfunction postFormOptional() {\n\t\tlet retryLimit = 3, // Max number of retries for form submission\n\t\t\tretryAttempt = 0;\n\t\tlet optins = \"\";\n\n\t\t// Retry initializing the Marketo form if not loaded\n\t\tif (checkMarketoForm() === false && retryAttempt < retryLimit) {\n\t\t\tinitMarketoForm(function () {\n\t\t\t\tretryAttempt++;\n\t\t\t\tpostFormOptional();\n\t\t\t});\n\t\t}\n\n\t\t// Disable the submit button\n\t\ttoggleButtonDisabled(document.querySelector(\".js-catalog-button-optional\"));\n\n\t\t// Set values for various Marketo form fields\n\t\tdocument.querySelector(\"#catalogOptionalFieldIndicator\").value = true;\n\t\tdocument.querySelector(\"#requestedAt\").value = document.URL;\n\t\tdocument.querySelector(\"#LeadSource\").value = \"www.nathab.com\";\n\t\tdocument.querySelector(\"#uniqueVisitorID\").value = uniqueFormId;\n\t\tdocument.querySelector(\"#temp\").value = \"CatRequestIsTrue\";\n\t\tdocument.querySelector(\"#sourceDetail\").value = \"Catalog Request\";\n\t\tdocument.querySelector(\"#recentConversionAction\").value = \"Catalog Request\";\n\t\tdocument.querySelector(\"#referringWebsite\").value = utmObject.referringWebsite || \"\";\n\t\tdocument.querySelector(\"#isCatalogRequested\").value = true;\n\n\t\t// Copy form fields to Marketo form\n\t\tcopyCatalogFieldsToMarketoForm(catalog.formName);\n\n\t\t// Push UTM parameters to the Marketo form\n\t\tpushUtmToMarketoForm();\n\n\t\t// Copy optional form fields to Marketo form\n\t\tpushToMarketoCatalogOptional(catalog.formName);\n\n\t\t// Set form options for email and SMS signups, if selected\n\t\tif (isNewsletterChecked(catalog.formName) === true) {\n\t\t\tdocument.querySelector(\"#isEmailSignup\").value = true;\n\t\t\toptins += \" eNews,\";\n\t\t\tsetOptsOnMarketoForm();\n\t\t}\n\n\t\tif (isSMSOptinChecked(catalog.formName) === true) {\n\t\t\tdocument.querySelector(\"#isSMSSignup\").value = true;\n\t\t\toptins += \" SMS\";\n\t\t\tsetSMSOptsOnMarketoForm();\n\t\t}\n\n\t\t// Set optins string for analytics event\n\t\toptins = optins || \" no optins\";\n\t\toptins = optins.endsWith(\",\") ? optins.slice(0, -1) : optins;\n\n\t\t// Push event to analytics platforms\n\t\tlet pushEventString = `Submitted Page 2`;\n\t\tpushEvent(\"Catalog\", catalog.locationValue, pushEventString);\n\n\t\t// Submit the Marketo form\n\t\tmarketoSubmitFormCatalog();\n\t\tpushEventFacebook();\n\t\tpushEventBing();\n\n\t\t// Show the thank you screen after a delay\n\t\tsetTimeout(function () {\n\t\t\tcatalogScreenOptional.classList.add(\"hide\");\n\t\t\tcatalogScreenThankYou.classList.remove(\"hide\");\n\t\t\tcatalogScreenThankYou.scrollTop = 0;\n\t\t}, 3000);\n\t}\n\n\t// Function to submit the Marketo form\n\tfunction marketoSubmitFormCatalog() {\n\t\tif (checkMarketoForm() === false) {\n\t\t\tpushEvent(\"Marketo\", \"Form\", \"Not Loaded during marketoSubmitForm()\");\n\t\t}\n\n\t\t// When Marketo form is ready, submit it\n\t\tMktoForms2.whenReady(function (form) {\n\t\t\tform.submit();\n\t\t});\n\t}\n}\n","import { initJsFormatPhone, initJsFormatName, setNewsletterCheckbox, setOptsOnMarketoForm, isFormValid, pushUtmToMarketoForm, toggleButtonDisabled, isThisSpam } from \"../../../assets/js/global-form-functions.js\";\nimport { isSMSOptinChecked, setSMSOptsOnMarketoForm } from \"../../../assets/js/global-form-functions.js\";\nimport { pushEvent, pushEventFacebook, pushEventBing, saveUserCountryToLocalStorage } from \"../../../assets/js/utilities.js\";\nimport { toggleAmbientVideo } from \"../../../components/hero/_video.js\";\n\nexport async function modalEnews() {\n\tawait saveUserCountryToLocalStorage();\n\tlet userCountry = localStorage.getItem(\"country\") || \"unknown\";\n\n\tlet pageURL = document.URL;\n\tlet enews = new Object();\n\tenews.formName = \"#form-enews\";\n\tenews.eventAction = \"\";\n\tenews.smsElementParent = document.querySelector(\".js-sms-checkbox-enews\");\n\tenews.smsElement = document.querySelector(\"[js-enews-sms]\");\n\tenews.phoneElementInput = document.querySelector(\"[js-enews-phone-toggle]\");\n\tenews.phoneElementLabel = document.querySelector('[for~=\"form-enews-phone\"]');\n\tenews.locationSelector = \"js-enews-location\";\n\tenews.locationFirstElement = document.querySelector(`[${enews.locationSelector}]`);\n\tenews.locationAllElements = document.querySelectorAll(`[${enews.locationSelector}]`);\n\tenews.locationValue = \"Unknown\";\n\tenews.firstInput = document.querySelector(\"[enews-form-label]\");\n\n\tlet eNewsScreenRequired = document.querySelector(\".js-enews-required\"),\n\t\teNewsScreenThankYou = document.querySelector(\".js-enews-thankyou\");\n\n\tinitJsFormatPhone();\n\tinitJsFormatName();\n\n\t// EVENT - Populate modal with email from inline enews input\n\tconst populateEmail = () => {\n\t\tconst inlineEmail = document.getElementById(\"enews-inline-email\");\n\t\tconst modalEmail = document.getElementById(\"form-enews-email\");\n\t\tmodalEmail.value = inlineEmail.value;\n\t};\n\n\t// Event - When SMS checkbox changes do stuff\n\tfunction smsCheckbox() {\n\t\tenews.smsElement.addEventListener(\"input\", function () {\n\t\t\tif (this.checked) {\n\t\t\t\tenews.phoneElementInput.setAttribute(\"required\", \"\");\n\t\t\t\tenews.phoneElementLabel.setAttribute(\"enews-form-label\", \"required\");\n\t\t\t} else {\n\t\t\t\tenews.phoneElementInput.removeAttribute(\"required\");\n\t\t\t\tenews.phoneElementLabel.setAttribute(\"enews-form-label\", \"\");\n\t\t\t\tenews.phoneElementInput.classList.remove(\"js-invalid\");\n\t\t\t}\n\t\t});\n\t}\n\n\t// EVENT - Add event listener to all elements with the locationSelector\n\tenews.locationAllElements.forEach((element) => {\n\t\telement.addEventListener(\"click\", function (e) {\n\t\t\tsessionStorage.setItem(\"modalOpen\", true);\n\n\t\t\t// pause ambient video when modal is opened\n\t\t\ttoggleAmbientVideo(false);\n\n\t\t\tif (userCountry === \"US\") {\n\t\t\t\tsetNewsletterCheckbox();\n\t\t\t\tenews.smsElementParent.classList.remove(\"hide\");\n\t\t\t\tsmsCheckbox();\n\t\t\t}\n\t\t\tif (checkMarketoForm() === false) {\n\t\t\t\tinitMarketoForm();\n\t\t\t}\n\t\t\tif (enews.locationValue !== \"URL\") {\n\t\t\t\tenews.locationValue = element.getAttribute(enews.locationSelector);\n\t\t\t}\n\t\t\tpushEvent(\"eNews\", enews.locationValue, \"Open\");\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tenews.firstInput.focus();\n\t\t\t}, 1000);\n\t\t});\n\t});\n\n\tenews.locationAllElements.forEach((el) => {\n\t\tif (el.getAttribute(\"js-enews-location\") === \"Bottom\") {\n\t\t\tel.addEventListener(\"click\", function (e) {\n\t\t\t\tpopulateEmail();\n\t\t\t});\n\t\t}\n\t});\n\n\t// EVENT - Check for #enews or in URL\n\tlet linksWithHash = document.querySelectorAll(\"a[href^='#']\");\n\tlet linksWithHashNormalized = [];\n\tlinksWithHash.forEach((link) => {\n\t\tlet href = link.getAttribute(\"href\").toLowerCase();\n\t\tif (href.includes(\"#enews\")) {\n\t\t\tlinksWithHashNormalized.push(link);\n\t\t}\n\t});\n\n\tlet linksWithLightbox = document.querySelectorAll(\"a[href~='?lightbox=enews']\");\n\tlet linksCombined = [...linksWithHashNormalized, ...linksWithLightbox];\n\taddClickEvents(linksCombined);\n\tfunction addClickEvents(list) {\n\t\tlist.forEach((element) => {\n\t\t\telement.addEventListener(\"click\", function (e) {\n\t\t\t\te.preventDefault();\n\t\t\t\tenews.locationValue = \"Link\";\n\t\t\t\tenews.locationFirstElement.click();\n\t\t\t});\n\t\t});\n\t}\n\t// EVENT - Check for #hash or ?lightbox=value in URL\n\tif (pageURL.indexOf(\"#enews\") > 0 || pageURL.indexOf(\"#eNews\") > 0 || window.location.search.match(/lightbox\\=enews/i)) {\n\t\tenews.locationValue = \"URL\"; //default\n\t\tenews.locationFirstElement.click();\n\t}\n\n\t// EVENT - Handle submit of required form\n\tdocument.querySelector(\".js-enews-button-required\").addEventListener(\"click\", function (e) {\n\t\te.preventDefault();\n\t\tpostFormEnews();\n\t});\n\n\tfunction setEnewsBasicsOnMarketoForm() {\n\t\tdocument.querySelector(\"#sourceDetail\").value = enews.locationValue;\n\t\tdocument.querySelector(\"#requestedAt\").value = document.URL;\n\t\tdocument.querySelector(\"#LeadSource\").value = \"www.nathab.com\";\n\t\tdocument.querySelector(\"#recentConversionAction\").value = \"Email Sign-Up\";\n\t\tdocument.querySelector(\"#referringWebsite\").value = utmObject.referringWebsite || \"\";\n\t}\n\n\tfunction copyNewsletterFieldsToMarketoForm() {\n\t\tlet fieldsToCopyArray = document.querySelectorAll(`${enews.formName} [mrkto-field]`);\n\t\tfieldsToCopyArray.forEach((field) => {\n\t\t\tlet mrktoFieldSelector = field.getAttribute(\"mrkto-field\");\n\t\t\tif (field.value) {\n\t\t\t\tdocument.querySelector(mrktoFieldSelector).value = field.value;\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction postFormEnews() {\n\t\tlet retryLimit = 3,\n\t\t\tretryAttempt = 0;\n\n\t\t// Validate form\n\t\tlet isValid = isFormValid(enews.formName);\n\t\tif (isValid === false) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for spam\n\t\tif (isThisSpam(enews.formName) === true) {\n\t\t\treturn;\n\t\t}\n\n\t\ttoggleButtonDisabled(document.querySelector(\".js-enews-button-required\"));\n\n\t\t// Check if marketo form has been loaded, if not retry with limits\n\t\tif (checkMarketoForm() === false && retryAttempt < retryLimit) {\n\t\t\tinitMarketoForm(function () {\n\t\t\t\tretryAttempt++;\n\t\t\t\tpostFormEnews();\n\t\t\t});\n\t\t}\n\n\t\tMktoForms2.whenReady(function () {\n\t\t\tlet optins = \"\";\n\n\t\t\tpushUtmToMarketoForm(); // function lives in global\n\n\t\t\tdocument.querySelector(\"#isEmailSignup\").value = true;\n\n\t\t\tsetEnewsBasicsOnMarketoForm(enews.formName);\n\n\t\t\tcopyNewsletterFieldsToMarketoForm(enews.formName);\n\n\t\t\tsetOptsOnMarketoForm();\n\n\t\t\tif (isSMSOptinChecked(enews.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isSMSSignup\").value = true;\n\t\t\t\toptins += \" SMS\";\n\t\t\t\tsetSMSOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\toptins = optins || \" no optins\"; // if empty string, set to no optins\n\t\t\tlet pushEventString = `Submitted w/${optins}`;\n\n\t\t\tpushEvent(\"eNews\", enews.locationValue, pushEventString);\n\n\t\t\tmarketoSubmitFormEnews();\n\t\t\tpushEventFacebook();\n\t\t\tpushEventBing();\n\n\t\t\tsetTimeout(() => {\n\t\t\t\teNewsScreenRequired.classList.add(\"hide\");\n\t\t\t\teNewsScreenThankYou.classList.remove(\"hide\");\n\t\t\t\teNewsScreenThankYou.scrollTop = 0;\n\t\t\t}, 2750);\n\t\t});\n\t}\n\n\tfunction marketoSubmitFormEnews() {\n\t\tif (checkMarketoForm() === false) {\n\t\t\tpushEvent(\"Marketo\", \"Form\", \"Not Loaded during marketoSubmitForm()\");\n\t\t}\n\n\t\tMktoForms2.whenReady(function (form) {\n\t\t\tform.submit();\n\t\t});\n\t}\n}\n","import { pushEvent, getCookie, getBrowserDevice, checkForOpenModals, checkIfWistiaVideoPlaying, waitUntilElementExists } from \"../../assets/js/utilities.js\";\n\nexport function olarkLoader() {\n\tlet isChatBoxOpen = false;\n\tlet modalAndVideoCheck = true;\n\tlet isOperatorAvailable = \"blocked\"; // default state\n\tlet chatCookieCheck;\n\tconst browserDevice = getBrowserDevice();\n\tconst chatCookieMaxAge = \"43200\"; // 43200 seconds = 12 hours\n\tconst userActionAutopopDelay = 15000; // 15 seconds\n\n\tdocument.addEventListener(\"readystatechange\", (event) => {\n\t\tif (event.target.readyState === \"complete\") {\n\t\t\tconst chatButtonDesktop = document.querySelector(\".js-chat-button-desktop\");\n\t\t\tconst chatButtonMobileBanner = document.querySelector(\".js-chat-banner-mobile\");\n\t\t\tconst chatButtonMobile = document.querySelector(\".js-chat-button-mobile\");\n\t\t\tconst chatMobileDrawerLabel = document.querySelector(\"[js-click-toggle~='contact']\");\n\t\t\tconst chatMobileDrawerToggle = document.querySelector(\"[js-close-chat]\");\n\n\t\t\tolark(\"api.chat.onReady\", function () {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tisOperatorAvailable = checkChatStatus();\n\t\t\t\t\tautoPopChatAfterXSeconds(isOperatorAvailable); // function call for 90 second auto popup\n\t\t\t\t\tif (isOperatorAvailable !== \"blocked\" && browserDevice !== \"mobile\") {\n\t\t\t\t\t\tchatButtonDesktop.classList.remove(\"hide\");\n\t\t\t\t\t} else if (isOperatorAvailable !== \"blocked\" && browserDevice == \"mobile\") {\n\t\t\t\t\t\tchatButtonMobileBanner.classList.remove(\"hide\");\n\t\t\t\t\t\tchatButtonMobile.classList.remove(\"hide\");\n\t\t\t\t\t}\n\t\t\t\t}, 2000);\n\t\t\t\tolark(\"api.box.shrink\");\n\t\t\t});\n\n\t\t\t// For when the box is expanded either from a button click or operator initiated\n\t\t\tolark(\"api.box.onExpand\", function () {\n\t\t\t\tisChatBoxOpen = true;\n\t\t\t\tif (browserDevice !== \"mobile\") {\n\t\t\t\t\tchatButtonDesktop.classList.add(\"hide\");\n\t\t\t\t}\n\t\t\t\tif (browserDevice === \"mobile\") {\n\t\t\t\t\tchatMobileDrawerLabel.click();\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tolark(\"api.box.expand\");\n\t\t\t\t\t}, 100);\n\t\t\t\t}\n\n\t\t\t\t// check if session has been set to remove consent message\n\t\t\t\tlet showConsent = sessionStorage.getItem(\"showConsent\");\n\t\t\t\tif (showConsent === \"false\") {\n\t\t\t\t\tconst consentMessageDiv = document.querySelector(\".olark-gdpr-consent-message\");\n\t\t\t\t\tif (consentMessageDiv) {\n\t\t\t\t\t\tconsentMessageDiv.remove();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// When chat is opened, call function to decide if enews consent box is displayed and gets pre-checked\n\t\t\t\tshouldEmailConsentBeDisplayed();\n\t\t\t});\n\n\t\t\tolark(\"api.box.onShow\", function () {\n\t\t\t\tisChatBoxOpen = true;\n\t\t\t\tchatButtonDesktop.classList.add(\"hide\");\n\t\t\t});\n\n\t\t\t// For when the box is shrunk either from a button click\n\t\t\tolark(\"api.box.onShrink\", function () {\n\t\t\t\tisChatBoxOpen = false;\n\t\t\t\tchatButtonDesktop.classList.remove(\"hide\");\n\t\t\t\tchatButtonDesktop.classList.remove(\"animate__animated\");\n\n\t\t\t\tif (browserDevice == \"mobile\") {\n\t\t\t\t\tchatMobileDrawerToggle.click();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tolark(\"api.box.onHide\", function () {\n\t\t\t\tisChatBoxOpen = false;\n\t\t\t\tchatButtonDesktop.classList.remove(\"hide\");\n\t\t\t\tchatButtonDesktop.classList.remove(\"animate__animated\");\n\n\t\t\t\tif (browserDevice == \"mobile\") {\n\t\t\t\t\tchatMobileDrawerToggle.click();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// For when the operator sends a message on mobile only\n\t\t\tolark(\"api.chat.onMessageToVisitor\", function (event) {\n\t\t\t\tisOperatorAvailable = checkChatStatus();\n\t\t\t\tif (browserDevice === \"mobile\" && isOperatorAvailable) {\n\t\t\t\t\tolark(\"api.box.expand\");\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Callback if operator is available\n\t\t\tolark(\"api.chat.onOperatorsAvailable\", function () {\n\t\t\t\tisOperatorAvailable = checkChatStatus();\n\t\t\t\tautoPopChatAfterXSeconds(isOperatorAvailable);\n\t\t\t});\n\n\t\t\t// Disappear consent button on first message to operator when chat is online\n\t\t\tolark(\"api.chat.onMessageToOperator\", function (e) {\n\t\t\t\tconst consentMessageDiv = document.querySelector(\".olark-gdpr-consent-message\");\n\t\t\t\tconsentMessageDiv.remove();\n\t\t\t\t// set session so div is removed when user goes to a new page\n\t\t\t\tsessionStorage.setItem(\"showConsent\", \"false\");\n\t\t\t});\n\n\t\t\t// CLICK LISTENERS\n\t\t\t// Add click listener to mobile button on contact drawer\n\t\t\tchatButtonMobile.addEventListener(\"click\", function (e) {\n\t\t\t\tolark(\"api.box.expand\");\n\t\t\t});\n\n\t\t\t// Add click listener to mobile banner\n\t\t\tchatButtonMobileBanner.addEventListener(\"click\", function (e) {\n\t\t\t\tchatMobileDrawerLabel.click();\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tolark(\"api.box.expand\");\n\t\t\t\t}, 100);\n\t\t\t\tpushEvent(\"Olark_Chat\", \"Button Click\", \"Mobile\");\n\t\t\t});\n\n\t\t\t// Add click listener to desktop button\n\t\t\tchatButtonDesktop.addEventListener(\"click\", function (e) {\n\t\t\t\tolark(\"api.box.expand\");\n\t\t\t\tpushEvent(\"Olark_Chat\", \"Button Click\", \"Desktop\");\n\t\t\t});\n\n\t\t\t// check for session value in case user went to different page before the 15 second timeout allowed chat to autopop after user action\n\t\t\tchatCookieCheck = cookieValueCheck(\"chatAutoPopupSession\");\n\t\t\tif (chatCookieCheck > userActionAutopopDelay) {\n\t\t\t\topenChat(isOperatorAvailable);\n\t\t\t\t// set auto popup cookies to prevent more auto popups\n\t\t\t\tsetAutoPopupCookie(\"chatAutoPopup\", chatCookieMaxAge);\n\t\t\t}\n\t\t}\n\t});\n\n\t// MAIN FUNCTIONS FOR EMAIL CONSENT BOX\n\tfunction shouldEmailConsentBeDisplayed() {\n\t\tconst consentMessageDiv = document.querySelector(\".olark-gdpr-consent-message\");\n\t\tconst consentButton = document.querySelector(\".olark-gdpr-consent-checkbox\");\n\n\t\tif (consentButton && consentButton.classList.contains(\"olark-gdpr-consent-checked\")) {\n\t\t\tconsentMessageDiv.remove();\n\t\t}\n\t\tconst onlineStartChatButton = document.querySelector(\".olark-button.olark-survey-form-submit\"); // when chat is online, this exists and email consent is displayed\n\t\tconst offlineNextButton = document.querySelector(\".olark-button.olark-survey-form-nav\"); // when chat is offline, this exists and email consent is not displayed\n\n\t\t// when chat is online, listen for chat start button and call function to decide if enews consent gets checked and set cookies so no autopop happens\n\t\tif (onlineStartChatButton) {\n\t\t\tonlineStartChatButton.addEventListener(\"click\", function () {\n\t\t\t\tpreCheckConsent(\"online\");\n\t\t\t\tsetAutoPopupCookie(\"chatAutoPopup\", chatCookieMaxAge);\n\t\t\t\tsetAutoPopupCookie(\"chatAutoPopupBlock\", chatCookieMaxAge);\n\t\t\t});\n\t\t}\n\n\t\t// when chat is offline, add click listener, call function to decide if enews consent gets checked and call next function\n\t\tif (offlineNextButton) {\n\t\t\tofflineNextButton.addEventListener(\"click\", offlinePageTwo);\n\t\t\tpreCheckConsent(\"offline\");\n\t\t}\n\t}\n\n\t// Precheck email consent box for users in US, India, and Australia when chat is online and add privacy policy\n\tfunction preCheckConsent(chatStatus) {\n\t\tlet consentButtonClass;\n\t\tlet consentMessageDivClass;\n\t\tconst privacyPolicy = 'Privacy Policy';\n\n\t\tif (chatStatus === \"online\") {\n\t\t\tconsentButtonClass = \".olark-gdpr-consent-checkbox\";\n\t\t\tconsentMessageDivClass = \".olark-gdpr-consent-message\";\n\t\t}\n\t\tif (chatStatus === \"offline\") {\n\t\t\tconsentButtonClass = \".olark-survey-form-input.olark-survey-form-checkbox\";\n\t\t\tconsentMessageDivClass = \".olark-survey-form-input-wrap\";\n\t\t}\n\n\t\twaitUntilElementExists(consentButtonClass).then(countryCheck);\n\t\twaitUntilElementExists(consentMessageDivClass).then(insertPrivacyPolicy);\n\n\t\tfunction countryCheck() {\n\t\t\tlet userCountry = localStorage.getItem(\"country\") || \"unknown\";\n\t\t\tconst consentButton = document.querySelector(consentButtonClass);\n\t\t\tif (userCountry === \"US\" || userCountry === \"IN\" || userCountry === \"AU\") {\n\t\t\t\tif (consentButton.checked === false) {\n\t\t\t\t\tconsentButton.click();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction insertPrivacyPolicy() {\n\t\t\tconst consentMessageDiv = document.querySelector(consentMessageDivClass);\n\t\t\tconst privacyPolicyElement = document.querySelector(\".js-chat-button-privacy\");\n\t\t\tif (!privacyPolicyElement) {\n\t\t\t\tconsentMessageDiv.insertAdjacentHTML(\"beforeend\", privacyPolicy);\n\t\t\t}\n\t\t}\n\t}\n\n\t// When chat is offline, switch mailbox icon to eNews icon on page 2\n\tfunction offlinePageTwo() {\n\t\tdocument.querySelector(\".olark-button\").removeEventListener(\"click\", offlinePageTwo);\n\t\tconst mailboxIconClass = \".olark-survey-form-emoji-wrap svg\";\n\t\twaitUntilElementExists(mailboxIconClass).then(iconSwitch);\n\n\t\tfunction iconSwitch() {\n\t\t\tconst mailboxIcon = document.querySelector(mailboxIconClass);\n\t\t\tconst enewsIcon = '';\n\t\t\tconst enewsIconElement = document.querySelector(\".js-chat-enews-icon\");\n\t\t\tif (!enewsIconElement) {\n\t\t\t\tmailboxIcon.insertAdjacentHTML(\"beforebegin\", enewsIcon);\n\t\t\t}\n\t\t}\n\t}\n\n\t// MAIN FUNCTIONS TO AUTO POPUP CHAT\n\t// Initial 90 second chat auto popup\n\tfunction autoPopChatAfterXSeconds(isOperatorAvailable) {\n\t\tconst autopopDelay = 90000; // 90 seconds\n\t\t// const autopopDelay = 15000; // 15 seconds for testing\n\n\t\t// auto popup chat only on desktop && if operator is online\n\t\tif (browserDevice !== \"desktop\" || isOperatorAvailable !== true) {\n\t\t\treturn;\n\t\t}\n\n\t\t// autopop only if chat is online, autopop blocking cookie is not set, and at least 90 seconds have passed\n\t\tlet chatCookieCheck = cookieValueCheck(\"chatAutoPopup\");\n\t\tif (getCookie(\"chatAutoPopupBlock\") === \"true\" || chatCookieCheck < autopopDelay) {\n\t\t\treturn;\n\t\t}\n\n\t\t// set cookie if not already set\n\t\tif (chatCookieCheck === \"none\") {\n\t\t\tsetAutoPopupCookie(\"chatAutoPopup\", chatCookieMaxAge);\n\t\t\treturn;\n\t\t}\n\n\t\t// if no modal is open and no video is playing, auto pop chat and set cookies\n\t\tmodalAndVideoCheck = callOpenModalAndVideoFunctions();\n\t\tif (modalAndVideoCheck === false) {\n\t\t\topenChat(isOperatorAvailable);\n\t\t\tsetAutoPopupCookie(\"chatAutoPopup\", \"0\"); //remove (expire) cookie so other auto popup works\n\t\t\tsetAutoPopupCookie(\"chatAutoPopupBlock\", chatCookieMaxAge);\n\t\t}\n\t}\n}\n\n// User-action-initiated chat auto popup occurs after user submits Ask a Question, Send Us a Message, or downloads PDF forms or opens a date or pricing accordion\nexport function autoPopChatUserAction(inputID) {\n\tconst inputDiv = document.querySelector(inputID);\n\tconst bodyDiv = document.querySelector(\"body\");\n\tconst userActionAutopopDelay = 15000; // 15 seconds\n\tlet modalInputDiv;\n\tlet accordionInputDiv;\n\n\t// auto popup chat only on desktop && if operator is online\n\tlet isOperatorAvailable = checkChatStatus();\n\tif (getBrowserDevice() !== \"desktop\" || isOperatorAvailable !== true) {\n\t\treturn;\n\t}\n\n\t// assign variable whether modal or accordion to determine how chat auto popup is executed\n\tif (inputDiv.hasAttribute(\"accordion\")) {\n\t\taccordionInputDiv = inputDiv;\n\t} else {\n\t\tmodalInputDiv = inputDiv;\n\t}\n\n\t// if input that triggered function is an open modal, add click listener to know when it's closed\n\tif (modalInputDiv && modalInputDiv.checked) {\n\t\tbodyDiv.addEventListener(\"click\", shouldChatAutoPop);\n\t}\n\n\t// if input that triggered function is an open accordion, call chat auto popup to open on top of accordion\n\tif (accordionInputDiv) {\n\t\tshouldChatAutoPop();\n\t}\n\n\tfunction shouldChatAutoPop() {\n\t\tconst chatCookieMaxAge = \"43200\"; // 43200 seconds = 12 hours\n\n\t\t// don't auto popup chat if the form is still open\n\t\tif (modalInputDiv && modalInputDiv.checked) {\n\t\t\treturn;\n\t\t}\n\t\t// don't auto popup chat if user action autopop has happened within 12 hours (both cookies have a value)\n\t\tlet chatCookieCheck = cookieValueCheck(\"chatAutoPopup\");\n\t\tif (chatCookieCheck !== \"none\" && getCookie(\"chatAutoPopupBlock\") === \"true\") {\n\t\t\treturn;\n\t\t}\n\t\t// don't auto popup chat if any modal is open or video is playing\n\t\tlet modalAndVideoCheck = callOpenModalAndVideoFunctions();\n\t\tif (modalAndVideoCheck === true) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (modalInputDiv || (accordionInputDiv && accordionInputDiv.checked)) {\n\t\t\t// set session in case user goes to a new page before chat is auto popped\n\t\t\tsessionStorage.setItem(\"chatAutoPopupSession\", Number(Date.now()));\n\n\t\t\t// 15 second delay\n\t\t\tsetTimeout(function () {\n\t\t\t\t// need to recheck this in case modal or video opened after Thank You message closed and before chat is popped\n\t\t\t\tmodalAndVideoCheck = callOpenModalAndVideoFunctions();\n\t\t\t\tif (modalAndVideoCheck === true) {\n\t\t\t\t\tbodyDiv.addEventListener(\"click\", () => {\n\t\t\t\t\t\tmodalAndVideoCloseTimerForAccordion(isOperatorAvailable);\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (getCookie(\"chatAutoPopupBlock\") === \"true\") return;\n\n\t\t\t\topenChat(isOperatorAvailable);\n\t\t\t\tif (chatCookieCheck === \"none\") {\n\t\t\t\t\tsetAutoPopupCookie(\"chatAutoPopup\", chatCookieMaxAge);\n\t\t\t\t}\n\t\t\t\tsetAutoPopupCookie(\"chatAutoPopupBlock\", chatCookieMaxAge);\n\n\t\t\t\t// remove listener on all accordions after the first one is opened and triggers chat auto popup\n\t\t\t\tif (accordionInputDiv && accordionInputDiv.checked) {\n\t\t\t\t\tremoveAccordionClickListener();\n\t\t\t\t}\n\t\t\t}, userActionAutopopDelay);\n\t\t}\n\t}\n}\n\n// AUTO POPUP HELPER FUNCTIONS\n// Check online/offline chat status\nfunction checkChatStatus() {\n\tconst chatButtonDesktop = document.querySelector(\".js-chat-button-desktop\");\n\tif (chatButtonDesktop.classList.contains(\"chatoff\")) {\n\t\treturn false;\n\t}\n\tconst olarkTopBarText = document.querySelector(\".olark-top-bar-text\");\n\tif (!olarkTopBarText) {\n\t\treturn \"blocked\"; // olark not rendered so likely blocking 3rd party cookies\n\t}\n\n\tif (olarkTopBarText.textContent.toLowerCase().includes(\"offline\")) {\n\t\treturn false;\n\t} else {\n\t\treturn true;\n\t}\n}\n\n// As a pre-condition to auto popping chat, call functions to check if any modal is open or a video is playing\nexport function callOpenModalAndVideoFunctions() {\n\tlet isModalOpen = checkForOpenModals();\n\tlet wistiaVideoPlayStatus = checkIfWistiaVideoPlaying();\n\tif (isModalOpen === false && wistiaVideoPlayStatus === false) {\n\t\treturn false;\n\t} else {\n\t\treturn true;\n\t}\n}\n\n// Remove click listeners on all accordions after one has been opened and triggered chat auto pop\nfunction removeAccordionClickListener() {\n\tconst datesAndPricingAccordions = document.querySelectorAll('[accordion=\"checkbox\"]');\n\tdatesAndPricingAccordions.forEach(function (accordion) {\n\t\taccordion.removeEventListener(\"click\", accordionClickListener);\n\t});\n}\n\n// Timer function in case user has opened modal/video after accordion timer is set and before chat popup happens to pop chat after modal/video is closed\nfunction modalAndVideoCloseTimerForAccordion(isOperatorAvailable) {\n\tconst closeTimerDelay = 1500; // 1.5 second delay\n\tconst bodyDiv = document.querySelector(\"body\");\n\n\tconst modalAndVideoCheck = callOpenModalAndVideoFunctions();\n\tif (modalAndVideoCheck === false) {\n\t\tsetTimeout(function () {\n\t\t\topenChat(isOperatorAvailable);\n\t\t\tbodyDiv.removeEventListener(\"click\", () => {\n\t\t\t\tmodalAndVideoCloseTimerForAccordion(isOperatorAvailable);\n\t\t\t});\n\t\t\tremoveAccordionClickListener(); // remove listener on all accordions after the first one is open and triggers chat auto popup\n\t\t\tlet chatCookieCheck = cookieValueCheck();\n\t\t\tif (chatCookieCheck === \"none\") {\n\t\t\t\tsetAutoPopupCookie(\"chatAutoPopup\", chatCookieMaxAge);\n\t\t\t}\n\t\t\tsetAutoPopupCookie(\"chatAutoPopupBlock\", chatCookieMaxAge);\n\t\t}, closeTimerDelay);\n\t}\n}\n\n// UTILITY FUNCTIONS\n// Utility function to check cookie or session\nfunction cookieValueCheck(cookie) {\n\tlet currentTime = Number(Date.now());\n\tlet currentCookieValue;\n\tif (cookie === \"chatAutoPopupSession\") {\n\t\tcurrentCookieValue = sessionStorage.getItem(\"chatAutoPopupSession\") || currentTime;\n\t} else {\n\t\tcurrentCookieValue = Number(getCookie(`${cookie}`) || currentTime);\n\t}\n\tlet timeDiff = currentTime - currentCookieValue;\n\tif (cookie === \"chatAutoPopupSession\") {\n\t\treturn timeDiff;\n\t}\n\tif (currentCookieValue === currentTime) {\n\t\treturn \"none\";\n\t} else {\n\t\treturn timeDiff;\n\t}\n}\n\n// Utility function to set cookie\nfunction setAutoPopupCookie(cookie, expiration) {\n\tlet currentTime = Number(Date.now());\n\tlet autoPopupCookieValue;\n\tif (cookie === \"chatAutoPopup\") {\n\t\tautoPopupCookieValue = currentTime;\n\t}\n\tif (cookie === \"chatAutoPopupBlock\") {\n\t\tautoPopupCookieValue = \"true\";\n\t}\n\tdocument.cookie = `${cookie}=${autoPopupCookieValue}; path=/; domain=nathab.com; max-age=${expiration}`; // 43200 = 12 hour expiration, seconds\n}\n\n// Utility function to auto open chat, clear session, and push event\nfunction openChat(isOperatorAvailable) {\n\tif (isOperatorAvailable !== true) return;\n\tolark(\"api.box.expand\");\n\tpushEvent(\"Olark_Chat\", \"Auto Popup\");\n\tsessionStorage.removeItem(\"chatAutoPopupSession\");\n\n\tconst chatButtonStartChatClass = \".olark-button.olark-survey-form-submit\";\n\twaitUntilElementExists(chatButtonStartChatClass).then(chatStartClickListener);\n\n\tfunction chatStartClickListener() {\n\t\tconst chatButtonStartChat = document.querySelector(chatButtonStartChatClass);\n\t\tchatButtonStartChat.addEventListener(\"click\", function (e) {\n\t\t\tpushEvent(\"Olark_Chat\", \"Auto Popup\", \"Chat Started\");\n\t\t});\n\t}\n}\n// Utility function to check whether chat box open\nexport function isChatOpen() {\n\tconst olarkContainer = document.querySelector(\"#olark-container\");\n\tlet isChatBoxOpen = false;\n\n\tif (olarkContainer && !olarkContainer.classList.contains(\"olark-hidden\")) {\n\t\tisChatBoxOpen = true;\n\t}\n\n\treturn isChatBoxOpen;\n}\n\n// add click listener and auto popup chat when accordion is opened, gets called after dates accordion is dynamically built\nexport function autoPopupChatAccordionClickListener() {\n\tconst datesAndPricingAccordions = document.querySelectorAll('[accordion=\"checkbox\"]');\n\tdatesAndPricingAccordions.forEach(function (accordion) {\n\t\taccordion.addEventListener(\"click\", accordionClickListener);\n\t});\n}\n\nfunction accordionClickListener(event) {\n\tif (event.target.checked) {\n\t\tlet accordionID = event.target.getAttribute(\"id\");\n\t\tautoPopChatUserAction(`input[id=\"${accordionID}\"]`); // NOW THAT OLARK IS WRAPPED IN FUNCTION, THIS ISN'T AVAILABLE FOR USE HERE\n\t}\n}\n","import { pushEvent, pushEventFacebook, pushEventBing, saveUserCountryToLocalStorage } from \"../../../assets/js/utilities.js\";\nimport { autoPopChatUserAction } from \"../../olark/_script.js\";\nimport { initJsFormatName, setOptsOnMarketoForm, isFormValid, isNewsletterChecked, setNewsletterCheckbox, pushUtmToMarketoForm, toggleButtonDisabled, isThisSpam } from \"../../../assets/js/global-form-functions.js\";\nimport { isSMSOptinChecked, setSMSOptsOnMarketoForm } from \"../../../assets/js/global-form-functions.js\";\nimport { toggleAmbientVideo } from \"../../../components/hero/_video.js\";\n\nexport async function modalMessage() {\n\tawait saveUserCountryToLocalStorage();\n\tlet userCountry = localStorage.getItem(\"country\") || \"unknown\";\n\n\tlet pageURL = document.URL;\n\tlet message = new Object();\n\tmessage.formName = \"#form-message\";\n\tmessage.newsletter = false;\n\tmessage.smsElementParent = document.querySelector(\".js-sms-checkbox-message\");\n\tmessage.smsElement = document.querySelector(\"[js-message-sms]\");\n\tmessage.phoneElementInput = document.querySelector(\"[js-message-phone-toggle]\");\n\tmessage.phoneElementLabel = document.querySelector('[for~=\"form-message-phone\"]');\n\tmessage.locationSelector = \"js-message-location\";\n\tmessage.locationFirstElement = document.querySelector(`[${message.locationSelector}]`);\n\tmessage.locationAllElements = document.querySelectorAll(`[${message.locationSelector}]`);\n\tmessage.firstInput = document.querySelector(\"[message-form-label]\");\n\n\tlet messageScreenRequired = document.querySelector(\".js-message-required\"),\n\t\tmessageScreenThankYou = document.querySelector(\".js-message-thankyou\");\n\n\tinitJsFormatName();\n\n\t// Event - When SMS checkbox changes do stuff\n\tfunction smsCheckbox() {\n\t\tmessage.smsElement.addEventListener(\"input\", function () {\n\t\t\tif (this.checked) {\n\t\t\t\tmessage.phoneElementInput.setAttribute(\"required\", \"\");\n\t\t\t\tmessage.phoneElementLabel.setAttribute(\"message-form-label\", \"required\");\n\t\t\t} else {\n\t\t\t\tmessage.phoneElementInput.removeAttribute(\"required\");\n\t\t\t\tmessage.phoneElementLabel.setAttribute(\"message-form-label\", \"\");\n\t\t\t\tmessage.phoneElementInput.classList.remove(\"js-invalid\");\n\t\t\t}\n\t\t});\n\t}\n\n\t// EVENT - Add event listener to all elements with the locationSelector\n\tmessage.locationAllElements.forEach((element) => {\n\t\telement.addEventListener(\"click\", function (e) {\n\t\t\tsessionStorage.setItem(\"modalOpen\", true);\n\n\t\t\t// pause ambient video when modal is opened\n\t\t\ttoggleAmbientVideo(false);\n\n\t\t\t//check eNews box for users in US, India, and Australia\n\t\t\tif (userCountry === \"US\" || userCountry === \"IN\" || userCountry === \"AU\") {\n\t\t\t\tsetNewsletterCheckbox();\n\t\t\t\tmessage.smsElementParent.classList.remove(\"hide\");\n\t\t\t\tsmsCheckbox();\n\t\t\t}\n\t\t\tif (checkMarketoForm() === false) {\n\t\t\t\tinitMarketoForm();\n\t\t\t}\n\t\t\tpushEvent(\"Misc\", \"Info Request\", \"Open\");\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tmessage.firstInput.focus();\n\t\t\t}, 1000);\n\t\t});\n\t});\n\n\t// EVENT - Check for #message or in URL\n\tlet linksWithHash = document.querySelectorAll(\"a[href^='#']\");\n\tlet linksWithHashNormalized = [];\n\tlinksWithHash.forEach((link) => {\n\t\tlet href = link.getAttribute(\"href\").toLowerCase();\n\t\tif (href.includes(\"#message\")) {\n\t\t\tlinksWithHashNormalized.push(link);\n\t\t}\n\t});\n\tlet linksWithLightbox = document.querySelectorAll(\"a[href~='?lightbox=message']\");\n\tlet linksCombined = [...linksWithHashNormalized, ...linksWithLightbox];\n\taddClickEvents(linksCombined);\n\tfunction addClickEvents(list) {\n\t\tlist.forEach((element) => {\n\t\t\telement.addEventListener(\"click\", function (e) {\n\t\t\t\te.preventDefault();\n\t\t\t\tmessage.locationFirstElement.click();\n\t\t\t});\n\t\t});\n\t}\n\n\t// EVENT - Check for #hash or ?lightbox=value in URL\n\tif (pageURL.indexOf(\"#message\") > 0 || window.location.search.match(/lightbox\\=message/i)) {\n\t\tmessage.locationFirstElement.click();\n\t}\n\n\t// EVENT - Handle submit of required form\n\tdocument.querySelector(\".js-message-button-required\").addEventListener(\"click\", function (e) {\n\t\te.preventDefault();\n\t\tpostFormmessage();\n\t\tautoPopChatUserAction(\"#modal-message\"); // NOW THAT OLARK IS WRAPPED IN FUNCTION, THIS ISN'T AVAILABLE FOR USE HERE\n\t});\n\n\tfunction copymessageFieldsToMarketoForm() {\n\t\tlet fieldsToCopyArray = document.querySelectorAll(`${message.formName} [mrkto-field]`);\n\t\tfieldsToCopyArray.forEach((field) => {\n\t\t\tlet mrktoFieldSelector = field.getAttribute(\"mrkto-field\");\n\t\t\tif (field.value) {\n\t\t\t\tdocument.querySelector(mrktoFieldSelector).value = field.value;\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction postFormmessage() {\n\t\tlet retryLimit = 3,\n\t\t\tretryAttempt = 0;\n\n\t\t// Validate form\n\t\tlet isValid = isFormValid(message.formName);\n\t\tif (isValid === false) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for spam\n\t\tif (isThisSpam(message.formName) === true) {\n\t\t\treturn;\n\t\t}\n\n\t\ttoggleButtonDisabled(document.querySelector(\".js-message-button-required\"));\n\n\t\t// Check if marketo form has been loaded, if not retry with limits\n\t\tif (checkMarketoForm() === false && retryAttempt < retryLimit) {\n\t\t\tinitMarketoForm(function () {\n\t\t\t\tretryAttempt++;\n\t\t\t\tpostFormmessage();\n\t\t\t});\n\t\t}\n\n\t\tMktoForms2.whenReady(function () {\n\t\t\tlet optins = \"\";\n\n\t\t\tpushUtmToMarketoForm(); // function lives in global\n\n\t\t\tdocument.querySelector(\"#requestedAt\").value = document.URL;\n\t\t\tdocument.querySelector(\"#LeadSource\").value = \"www.nathab.com\";\n\t\t\tdocument.querySelector(\"#sourceDetail\").value = \"Send Us a Message\";\n\t\t\tdocument.querySelector(\"#recentConversionAction\").value = \"Send Us a Message\";\n\t\t\tdocument.querySelector(\"#referringWebsite\").value = utmObject.referringWebsite || \"\";\n\t\t\tdocument.querySelector(\"#isSendMessage\").value = true;\n\n\t\t\tcopymessageFieldsToMarketoForm(message.formName); // Used for both required and optional\n\n\t\t\tif (isNewsletterChecked(message.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isEmailSignup\").value = true;\n\t\t\t\toptins += \" eNews\";\n\t\t\t\tsetOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\tif (isSMSOptinChecked(message.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isSMSSignup\").value = true;\n\t\t\t\toptins += \" SMS\";\n\t\t\t\tsetSMSOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\t// stupid edge case just to get a comma in the string\n\t\t\toptins = optins.replace(\"eNews SMS\", \"eNews, SMS\");\n\n\t\t\toptins = optins || \" no optins\"; // if empty string, set to no optins\n\t\t\tlet pushEventString = `Submitted w/${optins}`;\n\n\t\t\tpushEvent(\"Misc\", `Info Request`, pushEventString);\n\n\t\t\tmarketoSubmitFormMessage();\n\n\t\t\tpushEventFacebook();\n\t\t\tpushEventBing();\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tmessageScreenRequired.classList.add(\"hide\");\n\t\t\t\tmessageScreenThankYou.classList.remove(\"hide\");\n\t\t\t\tmessageScreenThankYou.scrollTop = 0;\n\t\t\t}, 2750);\n\t\t});\n\t}\n\n\tfunction marketoSubmitFormMessage() {\n\t\tif (checkMarketoForm() === false) {\n\t\t\tpushEvent(\"Marketo\", \"Form\", \"Not Loaded during marketoSubmitForm()\");\n\t\t}\n\n\t\tMktoForms2.whenReady(function (form) {\n\t\t\tform.submit();\n\t\t});\n\t}\n}\n","import { countryList } from \"../../../components/lists/country-list/_country-list.js\";\nimport { initSmarty } from \"../../../assets/js/smartypants.js\";\nimport { initJsFormatName, setOptsOnMarketoForm, isFormValid, isNewsletterChecked, setNewsletterCheckbox, pushUtmToMarketoForm, toggleButtonDisabled, isThisSpam } from \"../../../assets/js/global-form-functions.js\";\nimport { pushEvent, pushEventFacebook, pushEventBing, saveUserCountryToLocalStorage } from \"../../../assets/js/utilities.js\";\nimport { isSMSOptinChecked, setSMSOptsOnMarketoForm } from \"../../../assets/js/global-form-functions.js\";\n\nexport async function modalRefer() {\n\tawait saveUserCountryToLocalStorage();\n\tlet userCountry = localStorage.getItem(\"country\") || \"unknown\";\n\n\tlet pageURL = document.URL;\n\tlet refer = new Object();\n\trefer.formName = \"#form-refer\";\n\trefer.newsletter = false;\n\trefer.locationSelector = \"js-refer-location\";\n\trefer.smsElementParent = document.querySelector(\".js-sms-checkbox-refer\");\n\trefer.smsElement = document.querySelector(\"[js-refer-sms]\");\n\trefer.phoneElementInput = document.querySelector(\"[js-refer-phone-toggle]\");\n\trefer.phoneElementLabel = document.querySelector('[for~=\"form-refer-phone\"]');\n\trefer.locationFirstElement = document.querySelector(`[${refer.locationSelector}]`);\n\trefer.locationAllElements = document.querySelectorAll(`[${refer.locationSelector}]`);\n\trefer.firstInput = document.querySelector(\"[refer-form-label]\");\n\n\tlet referScreenRequired = document.querySelector(\".js-refer-required\"),\n\t\treferScreenThankYou = document.querySelector(\".js-refer-thankyou\");\n\n\tinitJsFormatName();\n\n\t// Event - When SMS checkbox changes do stuff\n\trefer.smsElement.addEventListener(\"input\", function () {\n\t\tif (this.checked) {\n\t\t\trefer.phoneElementInput.setAttribute(\"required\", \"\");\n\t\t\trefer.phoneElementLabel.setAttribute(\"refer-form-label\", \"required\");\n\t\t} else {\n\t\t\trefer.phoneElementInput.removeAttribute(\"required\");\n\t\t\trefer.phoneElementLabel.setAttribute(\"refer-form-label\", \"\");\n\t\t\trefer.phoneElementInput.classList.remove(\"js-invalid\");\n\t\t}\n\t});\n\n\t// EVENT - Add event listener to all elements with the locationSelector\n\trefer.locationAllElements.forEach((element) => {\n\t\telement.addEventListener(\"click\", function () {\n\t\t\tconst countryInput = document.querySelectorAll(`${refer.formName} .js-smarty-country`);\n\t\t\tif (userCountry !== \"unknown\") {\n\t\t\t\tcountryInput.forEach((input) => {\n\t\t\t\t\tconst country = countryList.filter((country) => userCountry === country.code);\n\t\t\t\t\tinput.value = country[0].name;\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (userCountry === \"US\") {\n\t\t\t\tsetNewsletterCheckbox();\n\t\t\t\tinitSmarty(refer.formName);\n\t\t\t\trefer.smsElementParent.classList.remove(\"hide\");\n\t\t\t} else if (userCountry === \"IN\" || userCountry === \"AU\") {\n\t\t\t\tsetNewsletterCheckbox();\n\t\t\t}\n\t\t\tif (checkMarketoForm() === false) {\n\t\t\t\tinitMarketoForm();\n\t\t\t}\n\t\t\tpushEvent(\"Misc\", \"Refer a Friend\", \"Open\");\n\n\t\t\tsetTimeout(() => {\n\t\t\t\trefer.firstInput.focus();\n\t\t\t}, 1000);\n\t\t});\n\t});\n\n\t// EVENT - Check for #refer or in URL\n\tlet linksWithHash = document.querySelectorAll(\"a[href^='#']\");\n\tlet linksWithHashNormalized = [];\n\tlinksWithHash.forEach((link) => {\n\t\tlet href = link.getAttribute(\"href\").toLowerCase();\n\t\tif (href.includes(\"#refer\")) {\n\t\t\tlinksWithHashNormalized.push(link);\n\t\t}\n\t});\n\tlet linksWithLightbox = document.querySelectorAll(\"a[href~='?lightbox=refer']\");\n\tlet linksCombined = [...linksWithHashNormalized, ...linksWithLightbox];\n\taddClickEvents(linksCombined);\n\tfunction addClickEvents(list) {\n\t\tlist.forEach((element) => {\n\t\t\telement.addEventListener(\"click\", function (e) {\n\t\t\t\te.preventDefault();\n\t\t\t\trefer.locationFirstElement.click();\n\t\t\t});\n\t\t});\n\t}\n\n\t// EVENT - Check for #hash or ?lightbox=value in URL\n\tif (pageURL.indexOf(\"#refer\") > 0 || window.location.search.match(/lightbox\\=refer/i)) {\n\t\trefer.locationFirstElement.click();\n\t}\n\n\t// EVENT - Handle submit of required form\n\tdocument.querySelector(\".js-refer-button-required\").addEventListener(\"click\", function (e) {\n\t\te.preventDefault();\n\t\tpostFormRefer();\n\t});\n\n\tfunction copyReferFieldsToMarketoForm() {\n\t\tlet fieldsToCopyArray = document.querySelectorAll(`${refer.formName} [mrkto-field]`);\n\t\tfieldsToCopyArray.forEach((field) => {\n\t\t\tlet mrktoFieldSelector = field.getAttribute(\"mrkto-field\");\n\t\t\tif (field.value) {\n\t\t\t\tdocument.querySelector(mrktoFieldSelector).value = field.value;\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction postFormRefer() {\n\t\tlet retryLimit = 3,\n\t\t\tretryAttempt = 0;\n\n\t\t// Validate form\n\t\tlet isValid = isFormValid(refer.formName);\n\t\tif (isValid === false) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for spam\n\t\tif (isThisSpam(refer.formName) === true) {\n\t\t\treturn;\n\t\t}\n\n\t\ttoggleButtonDisabled(document.querySelector(\".js-refer-button-required\"));\n\n\t\t// Check if marketo form has been loaded, if not retry with limits\n\t\tif (checkMarketoForm() === false && retryAttempt < retryLimit) {\n\t\t\tinitMarketoForm(function () {\n\t\t\t\tretryAttempt++;\n\t\t\t\tpostFormRefer();\n\t\t\t});\n\t\t}\n\n\t\tMktoForms2.whenReady(function () {\n\t\t\tlet optins = \"\";\n\n\t\t\tpushUtmToMarketoForm(); // function lives in global\n\n\t\t\tdocument.querySelector(\"#requestedAt\").value = document.URL;\n\t\t\tdocument.querySelector(\"#LeadSource\").value = \"www.nathab.com\";\n\t\t\tdocument.querySelector(\"#sourceDetail\").value = \"Refer a Friend\";\n\t\t\tdocument.querySelector(\"#recentConversionAction\").value = \"Refer a Friend\";\n\t\t\tdocument.querySelector(\"#referringWebsite\").value = utmObject.referringWebsite || \"\";\n\t\t\tdocument.querySelector(\"#isFriendReferred\").value = true;\n\n\t\t\tcopyReferFieldsToMarketoForm(refer.formName); // Used for both required and optional\n\n\t\t\tif (isNewsletterChecked(refer.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isEmailSignup\").value = true;\n\t\t\t\toptins += \" eNews\";\n\t\t\t\tsetOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\tif (isSMSOptinChecked(refer.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isSMSSignup\").value = true;\n\t\t\t\toptins += \" SMS\";\n\t\t\t\tsetSMSOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\t// stupid edge case just to get a comma in the string\n\t\t\toptins = optins.replace(\"eNews SMS\", \"eNews, SMS\");\n\n\t\t\toptins = optins || \" no optins\"; // if empty string, set to no optins\n\t\t\tlet pushEventString = `Submitted w/${optins}`;\n\n\t\t\tpushEvent(\"Misc\", `Refer a Friend`, pushEventString);\n\t\t\tmarketoSubmitFormRefer();\n\n\t\t\tpushEventFacebook();\n\t\t\tpushEventBing();\n\n\t\t\tsetTimeout(() => {\n\t\t\t\treferScreenRequired.classList.add(\"hide\");\n\t\t\t\treferScreenThankYou.classList.remove(\"hide\");\n\t\t\t\treferScreenThankYou.scrollIntoView(\"true\");\n\t\t\t}, 2750);\n\t\t});\n\t}\n\n\tfunction marketoSubmitFormRefer() {\n\t\tif (checkMarketoForm() === false) {\n\t\t\tpushEvent(\"Marketo\", \"Form\", \"Not Loaded during marketoSubmitForm()\");\n\t\t}\n\n\t\tMktoForms2.whenReady(function (form) {\n\t\t\tform.submit();\n\t\t});\n\t}\n}\n","import { initSmarty } from \"../../../assets/js/smartypants.js\";\nimport { initJsFormatName, setOptsOnMarketoForm, isFormValid, isNewsletterChecked, setNewsletterCheckbox, pushUtmToMarketoForm, toggleButtonDisabled, isThisSpam, limitCheckboxes } from \"../../../assets/js/global-form-functions.js\";\nimport { pushEvent, pushEventFacebook, pushEventBing, saveUserCountryToLocalStorage } from \"../../../assets/js/utilities.js\";\nimport { isSMSOptinChecked, setSMSOptsOnMarketoForm } from \"../../../assets/js/global-form-functions.js\";\nimport { toggleAmbientVideo } from \"../../../components/hero/_video.js\";\n\nexport async function modalDigital() {\n\tawait saveUserCountryToLocalStorage();\n\tlet userCountry = localStorage.getItem(\"country\") || \"unknown\";\n\n\tlet pageURL = document.URL;\n\tlet digital = new Object();\n\tdigital.formName = \"#form-digital\";\n\tdigital.newsletter = false;\n\tdigital.smsElementParent = document.querySelector(\".js-sms-checkbox-digital\");\n\tdigital.smsElement = document.querySelector(\"[js-digital-sms]\");\n\tdigital.phoneElementInput = document.querySelector(\"[js-digital-phone-toggle]\");\n\tdigital.phoneElementLabel = document.querySelector('[for~=\"form-digital-phone\"]');\n\tdigital.locationSelector = \"js-digital-location\";\n\tdigital.locationFirstElement = document.querySelector(`[${digital.locationSelector}]`);\n\tdigital.locationAllElements = document.querySelectorAll(`[${digital.locationSelector}]`);\n\tdigital.firstInput = document.querySelector(\"[digital-form-label]\");\n\n\tlet digitalScreenRequired = document.querySelector(\".js-digital-required\"),\n\t\tdigitalScreenThankYou = document.querySelector(\".js-digital-thankyou\");\n\n\tinitJsFormatName();\n\n\t// Event - When SMS checkbox changes do stuff\n\tfunction smsCheckbox() {\n\t\tdigital.smsElement.addEventListener(\"input\", function () {\n\t\t\tif (this.checked) {\n\t\t\t\tdigital.phoneElementInput.setAttribute(\"required\", \"\");\n\t\t\t\tdigital.phoneElementLabel.setAttribute(\"digital-form-label\", \"required\");\n\t\t\t} else {\n\t\t\t\tdigital.phoneElementInput.removeAttribute(\"required\");\n\t\t\t\tdigital.phoneElementLabel.setAttribute(\"digital-form-label\", \"\");\n\t\t\t\tdigital.phoneElementInput.classList.remove(\"js-invalid\");\n\t\t\t}\n\t\t});\n\t}\n\n\t// EVENT - Add event listener to all elements with the locationSelector\n\tdigital.locationAllElements.forEach((element) => {\n\t\telement.addEventListener(\"click\", function () {\n\t\t\tsessionStorage.setItem(\"modalOpen\", true);\n\n\t\t\t// pause ambient video when modal is opened\n\t\t\ttoggleAmbientVideo(false);\n\n\t\t\t//check eNews box for users in US, India, and Australia\n\t\t\tif (userCountry === \"US\") {\n\t\t\t\tsetNewsletterCheckbox();\n\t\t\t\tinitSmarty(digital.formName);\n\t\t\t\tdigital.smsElementParent.classList.remove(\"hide\");\n\t\t\t\tsmsCheckbox();\n\t\t\t} else if (userCountry === \"IN\" || userCountry === \"AU\") {\n\t\t\t\tsetNewsletterCheckbox();\n\t\t\t}\n\t\t\tif (checkMarketoForm() === false) {\n\t\t\t\tinitMarketoForm();\n\t\t\t}\n\t\t\tlimitCheckboxes(digital.formName);\n\t\t\tpushEvent(\"Misc\", \"Digital Catalog\", \"Open\");\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tdigital.firstInput.focus();\n\t\t\t}, 1000);\n\t\t});\n\t});\n\n\t// EVENT - Check for #digital or in URL\n\tlet linksWithHash = document.querySelectorAll(\"a[href^='#']\");\n\tlet linksWithHashNormalized = [];\n\tlinksWithHash.forEach((link) => {\n\t\tlet href = link.getAttribute(\"href\").toLowerCase();\n\t\tif (href.includes(\"#digital\")) {\n\t\t\tlinksWithHashNormalized.push(link);\n\t\t}\n\t});\n\tlet linksWithLightbox = document.querySelectorAll(\"a[href~='?lightbox=digital']\");\n\tlet linksCombined = [...linksWithHashNormalized, ...linksWithLightbox];\n\taddClickEvents(linksCombined);\n\tfunction addClickEvents(list) {\n\t\tlist.forEach((element) => {\n\t\t\telement.addEventListener(\"click\", function (e) {\n\t\t\t\te.preventDefault();\n\t\t\t\tdigital.locationFirstElement.click();\n\t\t\t});\n\t\t});\n\t}\n\n\t// EVENT - Check for #hash or ?lightbox=value in URL\n\tif (pageURL.indexOf(\"#digital\") > 0 || window.location.search.match(/lightbox\\=digital/i)) {\n\t\tdigital.locationFirstElement.click();\n\t}\n\n\t// EVENT - Handle submit of required form\n\tdocument.querySelector(\".js-digital-button-required\").addEventListener(\"click\", function (e) {\n\t\te.preventDefault();\n\t\tpostFormdigital();\n\t});\n\n\tfunction copydigitalFieldsToMarketoForm() {\n\t\tlet fieldsToCopyArray = document.querySelectorAll(`${digital.formName} [mrkto-field]`);\n\t\tfieldsToCopyArray.forEach((field) => {\n\t\t\tlet mrktoFieldSelector = field.getAttribute(\"mrkto-field\");\n\t\t\tif (field.value) {\n\t\t\t\tdocument.querySelector(mrktoFieldSelector).value = field.value;\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction postFormdigital() {\n\t\tlet retryLimit = 3,\n\t\t\tretryAttempt = 0;\n\n\t\t// Validate form\n\t\tlet isValid = isFormValid(digital.formName);\n\t\tif (isValid === false) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for spam\n\t\tif (isThisSpam(digital.formName) === true) {\n\t\t\treturn;\n\t\t}\n\n\t\ttoggleButtonDisabled(document.querySelector(\".js-digital-button-required\"));\n\n\t\t// Check if marketo form has been loaded, if not retry with limits\n\t\tif (checkMarketoForm() === false && retryAttempt < retryLimit) {\n\t\t\tinitMarketoForm(function () {\n\t\t\t\tretryAttempt++;\n\t\t\t\tpostFormdigital();\n\t\t\t});\n\t\t}\n\n\t\tMktoForms2.whenReady(function () {\n\t\t\tlet optins = \"\";\n\n\t\t\tpushUtmToMarketoForm(); // function lives in global\n\t\t\tdocument.querySelector(\"#requestedAt\").value = document.URL;\n\t\t\tdocument.querySelector(\"#LeadSource\").value = \"www.nathab.com\";\n\t\t\tdocument.querySelector(\"#sourceDetail\").value = \"Digital Catalog Request\";\n\t\t\tdocument.querySelector(\"#recentConversionAction\").value = \"Digital Catalog Request\";\n\t\t\tdocument.querySelector(\"#referringWebsite\").value = utmObject.referringWebsite || \"\";\n\t\t\tdocument.querySelector(\"#isDigitalCatalog\").value = true;\n\n\t\t\tcopydigitalFieldsToMarketoForm(digital.formName); // Used for both required and optional\n\n\t\t\tif (isNewsletterChecked(digital.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isEmailSignup\").value = true;\n\t\t\t\toptins += \" eNews\";\n\t\t\t\tsetOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\tif (isSMSOptinChecked(digital.formName) === true) {\n\t\t\t\tdocument.querySelector(\"#isSMSSignup\").value = true;\n\t\t\t\toptins += \" SMS\";\n\t\t\t\tsetSMSOptsOnMarketoForm();\n\t\t\t}\n\n\t\t\t// stupid edge case just to get a comma in the string\n\t\t\toptins = optins.replace(\"eNews SMS\", \"eNews, SMS\");\n\n\t\t\toptins = optins || \" no optins\"; // if empty string, set to no optins\n\t\t\tlet pushEventString = `Submitted w/${optins}`;\n\n\t\t\tpushEvent(\"Misc\", `Digital Catalog`, pushEventString);\n\n\t\t\tlet checkboxesToCopyArray = document.querySelectorAll(`${digital.formName} [mrkto-checkbox]`);\n\t\t\tcheckboxesToCopyArray.forEach((checkbox) => {\n\t\t\t\tlet mrktoCheckboxSelector = checkbox.getAttribute(\"mrkto-checkbox\");\n\t\t\t\tif (checkbox.checked) {\n\t\t\t\t\tdocument.querySelector(mrktoCheckboxSelector).value = checkbox.value;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tmarketoSubmitFormDigital();\n\n\t\t\tpushEventFacebook();\n\t\t\tpushEventBing();\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tdigitalScreenRequired.classList.add(\"hide\");\n\t\t\t\tdigitalScreenThankYou.classList.remove(\"hide\");\n\t\t\t\tdigitalScreenThankYou.scrollTop = 0;\n\t\t\t}, 2750);\n\t\t});\n\t}\n\n\tfunction marketoSubmitFormDigital() {\n\t\tif (checkMarketoForm() === false) {\n\t\t\tpushEvent(\"Marketo\", \"Form\", \"Not Loaded during marketoSubmitForm()\");\n\t\t}\n\n\t\tMktoForms2.whenReady(function (form) {\n\t\t\tform.submit();\n\t\t});\n\n\t\twindow.open(\"https://issuu.com/natural-habitat-adventures/docs/2025-26_travel-catalog_nat-hab?fr=sYmI5YTc2OTAwNDU\", \"_blank\");\n\t}\n}\n","import { isDialogSupported } from \"../_script.js\";\nimport { copyToClipboard } from \"../../../assets/js/utilities.js\";\nimport { toggleAmbientVideo } from \"../../../components/hero/_video.js\";\n\nexport function modalYoutube() {\n\tconst youtubeModal = document.querySelector(\"[youtube-modal]\");\n\tconst youtubeModalClose = document.querySelector(\"[youtube-modal-close]\");\n\tconst youtubeLinks = document.querySelectorAll(\"a[href*='youtube.com']:not([nomodal])\");\n\tconst youtubeIframe = document.querySelector(\"[youtube-modal-iframe]\");\n\tconst unsetSrc = \"\";\n\n\t// Function - check url for youtube\n\tfunction checkUrlForYoutube() {\n\t\tlet querystring = new URLSearchParams(window.location.search);\n\t\tlet modalParam = querystring.get(\"modal\");\n\t\tlet lightboxParam = querystring.get(\"lightbox\");\n\t\tlet youtubeSrc = \"\";\n\n\t\t// Check if either modal or lightbox parameter contains \"youtube.com\"\n\t\tif (modalParam && modalParam.includes(\"youtube.com\")) {\n\t\t\tyoutubeSrc = modalParam;\n\t\t} else if (lightboxParam && lightboxParam.includes(\"youtube.com\")) {\n\t\t\tyoutubeSrc = lightboxParam;\n\t\t}\n\t\t// If youtubeSrc has been set, decode and open the YouTube modal\n\t\tif (!youtubeSrc) return;\n\t\tyoutubeSrc = decodeURIComponent(youtubeSrc);\n\t\topenYoutubeModal(youtubeSrc);\n\t}\n\tcheckUrlForYoutube();\n\n\t// Event : check for youtube links\n\tfunction checkLinksForYoutube() {\n\t\tyoutubeLinks.forEach((item) => {\n\t\t\tlet href = item.getAttribute(\"href\");\n\t\t\tif (href.includes(\"@nathab\") || href.includes(\"@naturewebinars\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\titem.addEventListener(\"click\", (event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tlet youtubeSrc = item.getAttribute(\"href\");\n\t\t\t\tyoutubeSrc = youtubeSrc.replace(/(^.*\\?lightbox=)/i, \"\");\n\t\t\t\tyoutubeSrc = youtubeSrc.replace(/(^.*\\?modal=)/i, \"\");\n\t\t\t\tif (event.shiftKey) {\n\t\t\t\t\tlet shiftClickUrl = `https://${window.location.hostname}${window.location.pathname}?modal=${youtubeSrc}`;\n\t\t\t\t\tcopyToClipboard(shiftClickUrl);\n\t\t\t\t}\n\t\t\t\topenYoutubeModal(`${youtubeSrc}`);\n\t\t\t});\n\t\t});\n\t}\n\tcheckLinksForYoutube();\n\n\t// Function - Open Youtube Modal\n\tfunction openYoutubeModal(src) {\n\t\tsetSrc(src);\n\t\tif (youtubeModal.hasAttribute(\"open\")) return;\n\t\tif (!isDialogSupported()) {\n\t\t\tyoutubeModal.setAttribute(\"open\", \"\");\n\t\t} else {\n\t\t\tyoutubeModal.showModal();\n\t\t}\n\t\tsessionStorage.setItem(\"modalOpen\", true);\n\t\ttoggleAmbientVideo(false);\n\t}\n\n\t// Function - Close Youtube Modal\n\tfunction closeYoutubeModal() {\n\t\tsetSrc(unsetSrc);\n\t\tif (!isDialogSupported()) {\n\t\t\tyoutubeModal.removeAttribute(\"open\");\n\t\t} else {\n\t\t\tyoutubeModal.close();\n\t\t}\n\t}\n\n\t// Function - Set Youtube Src\n\tfunction setSrc(src) {\n\t\tyoutubeIframe.setAttribute(\"src\", src);\n\t}\n\n\t// Event : close event for when modal is open\n\tdocument.addEventListener(\"click\", function (event) {\n\t\tif (youtubeModal.contains(event.target) || (event.target === youtubeModal && youtubeModal.open)) {\n\t\t\tcloseYoutubeModal();\n\t\t}\n\t});\n\n\t// Event : close button click\n\tyoutubeModalClose.addEventListener(\"click\", () => {\n\t\tcloseYoutubeModal();\n\t});\n\n\t// Event : if escape key is pressed (but captures all close events)\n\tyoutubeModal.addEventListener(\"close\", () => {\n\t\tcloseYoutubeModal();\n\t\tsessionStorage.setItem(\"modalOpen\", false);\n\t\ttoggleAmbientVideo(true);\n\t});\n}\n","import { pushEvent, pushEventFacebook, pushEventBing, getBrowserDevice, saveUserCountryToLocalStorage } from \"../../../assets/js/utilities.js\";\nimport { callOpenModalAndVideoFunctions } from \"../../olark/_script.js\";\nimport { initSmarty } from \"../../../assets/js/smartypants.js\";\nimport { initJsFormatPhone, initJsFormatName, setOptsOnMarketoForm, isFormValid, isNewsletterChecked, setNewsletterCheckbox, pushUtmToMarketoForm, toggleButtonDisabled, isThisSpam } from \"../../../assets/js/global-form-functions.js\";\nimport { isChatOpen } from \"../../olark/_script.js\";\nimport { isSMSOptinChecked, setSMSOptsOnMarketoForm } from \"../../../assets/js/global-form-functions.js\";\nimport { toggleAmbientVideo } from \"../../../components/hero/_video.js\";\n\nexport function ebookCTAs() {\n\tlet marketoCampaignName;\n\tlet ebookUrl;\n\n\t// Function: do stuff to ebook modal\n\tasync function eBookModal(id) {\n\t\tlet campaignID = id;\n\t\tawait saveUserCountryToLocalStorage();\n\t\tlet userCountry = localStorage.getItem(\"country\") || \"unknown\";\n\n\t\tlet eBook = new Object();\n\t\teBook.formName = \"#form-ebook\";\n\t\teBook.newsletter = false;\n\t\teBook.firstInput = document.querySelector(\"#form-ebook-first_name\");\n\t\teBook.smsElementParent = document.querySelector(\".js-sms-checkbox-ebook\");\n\t\teBook.smsElement = document.querySelector(\"[js-ebook-sms]\");\n\t\teBook.phoneElementInput = document.querySelector(\"[js-ebook-phone-toggle]\");\n\t\teBook.phoneElementLabel = document.querySelector('[for~=\"form-ebook-phone\"]');\n\t\teBook.phoneElementLabelRequired = document.querySelector('[for~=\"form-ebook-phone\"] span');\n\n\t\tinitJsFormatPhone();\n\t\tinitJsFormatName();\n\n\t\tconst campaignData = {\n\t\t\ttu18oaqav9qkl5yfxsyv: {\n\t\t\t\tname: \"Fundamentals of Nature Photography\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nature_photography_fundamentals_ebook?fr=sZDYxNTYwMDUyMTM\"\n\t\t\t},\n\t\t\tvoupy8wdnwblul6vjl1y: {\n\t\t\t\tname: \"Fundamentals of Nature Photography\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nature_photography_fundamentals_ebook?fr=sZDYxNTYwMDUyMTM\"\n\t\t\t},\n\t\t\tyeiba6dgsj8zsivkhb9r: {\n\t\t\t\tname: \"Fundamentals of Nature Photography\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nature_photography_fundamentals_ebook?fr=sZDYxNTYwMDUyMTM\"\n\t\t\t},\n\t\t\turqd4tb4mtflhk3tzox6: {\n\t\t\t\tname: \"Polar Bear Photography Guide\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/polar_bear_photography_guide\"\n\t\t\t},\n\t\t\twjpuhgvxuo1nxcgrgfam: {\n\t\t\t\tname: \"Polar Bear Photography Guide\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/polar_bear_photography_guide\"\n\t\t\t},\n\t\t\tefc31udmczx1xgke399b: {\n\t\t\t\tname: \"Polar Bear Photography Guide\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/polar_bear_photography_guide\"\n\t\t\t},\n\t\t\top07bfqilfpg9akgzxvn: {\n\t\t\t\tname: \"Northern Lights Photography Guide\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/northern-lights-photography-guide\"\n\t\t\t},\n\t\t\tf2xtqvqoowiry2s3nobk: {\n\t\t\t\tname: \"Northern Lights Photography Guide\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/northern-lights-photography-guide\"\n\t\t\t},\n\t\t\tkeh38qepxheoakylxo51: {\n\t\t\t\tname: \"Northern Lights Photography Guide\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/northern-lights-photography-guide\"\n\t\t\t},\n\t\t\tquthwhoxff0adv3mp0fs: {\n\t\t\t\tname: \"Galapagos Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/feb_galapagos_brochure\"\n\t\t\t},\n\t\t\tw1wt5dat5x5oifhegi4e: {\n\t\t\t\tname: \"Galapagos Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/feb_galapagos_brochure\"\n\t\t\t},\n\t\t\tidk2qhidkqto1nflvijk: {\n\t\t\t\tname: \"Galapagos Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/feb_galapagos_brochure\"\n\t\t\t},\n\t\t\tjnurbdjfkiftde7yhpej: {\n\t\t\t\tname: \"Polar Bear Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/mar_polar_bear_brochure\"\n\t\t\t},\n\t\t\tyrl0yxl3nh3osfhtc4md: {\n\t\t\t\tname: \"Polar Bear Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/mar_polar_bear_brochure\"\n\t\t\t},\n\t\t\tnykcz442pm5nsa1lpxiu: {\n\t\t\t\tname: \"Polar Bear Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/mar_polar_bear_brochure\"\n\t\t\t},\n\t\t\th73zz2yn0ttzbpmquk3y: {\n\t\t\t\tname: \"Australia Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/jun_australia_brochure\"\n\t\t\t},\n\t\t\txiwob5l74j8n4ebcpvkz: {\n\t\t\t\tname: \"Australia Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/jun_australia_brochure\"\n\t\t\t},\n\t\t\tw2iaszbsouchpnwtw6di: {\n\t\t\t\tname: \"Australia Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/jun_australia_brochure\"\n\t\t\t},\n\t\t\tbroursnxugepvtqqpdqr: {\n\t\t\t\tname: \"World's Best Adventures For Every Season eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-adventureseveryseason?fr=sNDc3ZjYzMDAxMDM\"\n\t\t\t},\n\t\t\twklcy54e540vfozxeyuv: {\n\t\t\t\tname: \"World's Best Adventures For Every Season eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-adventureseveryseason?fr=sNDc3ZjYzMDAxMDM\"\n\t\t\t},\n\t\t\tahn14os85rjyamvmmbrv: {\n\t\t\t\tname: \"World's Best Adventures For Every Season eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-adventureseveryseason?fr=sNDc3ZjYzMDAxMDM\"\n\t\t\t},\n\t\t\tpmsnrvg18fxjsbhigwf3: {\n\t\t\t\tname: \"Africa's Big 5 eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-africasbigfive?fr=sNWVmNjYzMDAxMDM\"\n\t\t\t},\n\t\t\tr07jtlzjuxs7ydow9twf: {\n\t\t\t\tname: \"Africa's Big 5 eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-africasbigfive?fr=sNWVmNjYzMDAxMDM\"\n\t\t\t},\n\t\t\twectj42dfcwvp2aheia9: {\n\t\t\t\tname: \"Africa's Big 5 eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-africasbigfive?fr=sNWVmNjYzMDAxMDM\"\n\t\t\t},\n\t\t\tql9emap4ll16mpusswat: {\n\t\t\t\tname: \"Rainforest Adventures eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-rainforestadventures?fr=sZjk1MjYzMDAxMDM\"\n\t\t\t},\n\t\t\toahjmihvdz2hdhygl5t8: {\n\t\t\t\tname: \"Rainforest Adventures eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-rainforestadventures?fr=sZjk1MjYzMDAxMDM\"\n\t\t\t},\n\t\t\tuthayslur79fxnfrytee: {\n\t\t\t\tname: \"Rainforest Adventures eBook\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nathab-ebook-rainforestadventures?fr=sZjk1MjYzMDAxMDM\"\n\t\t\t},\n\t\t\typ4ppkps3xnxuq0gob59: {\n\t\t\t\tname: \"Iceland Greenland Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nat-hab-iceland-greenland-brochure-2025-2026?fr=sZmUxZjc2OTAwNDU\"\n\t\t\t},\n\t\t\tjliuagemgknzhoi39spv: {\n\t\t\t\tname: \"Iceland Greenland Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nat-hab-iceland-greenland-brochure-2025-2026?fr=sZmUxZjc2OTAwNDU\"\n\t\t\t},\n\t\t\tgnzxsrszzlgfpwhcg5tu: {\n\t\t\t\tname: \"Digital Catalog\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/2025-26_travel-catalog_nat-hab?fr=sYmI5YTc2OTAwNDU\"\n\t\t\t},\n\t\t\tgxxmu7xbywwvvoe7per4: {\n\t\t\t\tname: \"Digital Catalog\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/2025-26_travel-catalog_nat-hab?fr=sYmI5YTc2OTAwNDU\"\n\t\t\t},\n\t\t\taocmbipvtelfydacfgi1: {\n\t\t\t\tname: \"Digital Catalog\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/2025-26_travel-catalog_nat-hab?fr=sYmI5YTc2OTAwNDU\"\n\t\t\t},\n\t\t\tcsgufgguzlblnto2ltii: {\n\t\t\t\tname: \"Peru Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nov_peru_brochure?fr=xKAE9_zU1NQ\"\n\t\t\t},\n\t\t\tqormuafpdktnesbg6ywu: {\n\t\t\t\tname: \"Peru Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nov_peru_brochure?fr=xKAE9_zU1NQ\"\n\t\t\t},\n\t\t\tr0ualrp0xyyewrjzmeqw: {\n\t\t\t\tname: \"Alaska Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nov_alaska_brochure?fr=sNTYxMDc2OTAwNDU\"\n\t\t\t},\n\t\t\tf2nlxmywljhj8dxf4ttn: {\n\t\t\t\tname: \"Alaska Brochure\",\n\t\t\t\turl: \"https://issuu.com/natural-habitat-adventures/docs/nov_alaska_brochure?fr=sNTYxMDc2OTAwNDU\"\n\t\t\t}\n\t\t};\n\n\t\tif (campaignData[campaignID]) {\n\t\t\tmarketoCampaignName = campaignData[campaignID].name;\n\t\t\tebookUrl = campaignData[campaignID].url;\n\t\t}\n\n\t\tsessionStorage.setItem(\"modalOpen\", true);\n\n\t\t// pause ambient video when modal is opened\n\t\ttoggleAmbientVideo(false);\n\n\t\tpushEvent(\"Gated Content\", \"eBook\", \"Open\");\n\n\t\tsetTimeout(() => {\n\t\t\teBook.firstInput.focus();\n\t\t}, 1000);\n\n\t\t// if eBook shown on page, prevent itinerary (enews) modal from auto popping\n\t\tlet pageVisits = Cookies.get(\"itin\");\n\t\tif (pageVisits === 1) {\n\t\t\tCookies.set(\"itin\", 0);\n\t\t}\n\n\t\t//check eNews box for users in US, India, and Australia\n\t\tif (userCountry === \"US\") {\n\t\t\tsetNewsletterCheckbox();\n\t\t\tinitSmarty(eBook.formName);\n\t\t\teBook.smsElementParent.classList.remove(\"hide\");\n\t\t\tsmsCheckbox();\n\t\t} else if (userCountry === \"IN\" || userCountry === \"AU\") {\n\t\t\tsetNewsletterCheckbox();\n\t\t}\n\n\t\t// Event - When SMS checkbox changes do stuff\n\t\tfunction smsCheckbox() {\n\t\t\teBook.smsElement.addEventListener(\"input\", function () {\n\t\t\t\tif (this.checked) {\n\t\t\t\t\teBook.phoneElementInput.setAttribute(\"required\", \"\");\n\t\t\t\t\teBook.phoneElementLabel.setAttribute(\"ebook-form-label\", \"required\");\n\t\t\t\t\teBook.phoneElementLabelRequired.classList.remove(\"hide\");\n\t\t\t\t} else {\n\t\t\t\t\teBook.phoneElementInput.removeAttribute(\"required\");\n\t\t\t\t\teBook.phoneElementLabel.setAttribute(\"ebook-form-label\", \"\");\n\t\t\t\t\teBook.phoneElementInput.classList.remove(\"js-invalid\");\n\t\t\t\t\teBook.phoneElementLabelRequired.classList.add(\"hide\");\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// EVENT - Handle submit of required form\n\t\tdocument.querySelector(\".js-ebook-submit-button\").addEventListener(\"click\", function (e) {\n\t\t\te.preventDefault();\n\t\t\tpostFormEbook();\n\t\t});\n\n\t\tfunction copyEbookFieldsToMarketoForm() {\n\t\t\tlet fieldsToCopyArray = document.querySelectorAll(`${eBook.formName} [mrkto-field]`);\n\t\t\tfieldsToCopyArray.forEach((field) => {\n\t\t\t\tlet mrktoFieldSelector = field.getAttribute(\"mrkto-field\");\n\t\t\t\tif (field.value) {\n\t\t\t\t\tdocument.querySelector(mrktoFieldSelector).value = field.value;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tfunction postFormEbook() {\n\t\t\tlet retryLimit = 3,\n\t\t\t\tretryAttempt = 0;\n\t\t\t// Validate form\n\t\t\tlet isValid = isFormValid(eBook.formName);\n\t\t\tif (isValid === false) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Check for spam\n\t\t\tif (isThisSpam(eBook.formName) === true) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttoggleButtonDisabled(document.querySelector(\".js-ebook-submit-button\"));\n\t\t\t// Check if marketo form has been loaded, if not retry with limits\n\t\t\tif (checkMarketoForm() === false && retryAttempt < retryLimit) {\n\t\t\t\tinitMarketoForm(function () {\n\t\t\t\t\tretryAttempt++;\n\t\t\t\t\tpostFormEbook();\n\t\t\t\t});\n\t\t\t}\n\t\t\tMktoForms2.whenReady(function () {\n\t\t\t\tlet optins = \"\";\n\n\t\t\t\tpushUtmToMarketoForm(); // function lives in global\n\t\t\t\tdocument.querySelector(\"#requestedAt\").value = document.URL;\n\t\t\t\tdocument.querySelector(\"#LeadSource\").value = \"www.nathab.com\";\n\t\t\t\tdocument.querySelector(\"#sourceDetail\").value = \"eBook\";\n\t\t\t\tdocument.querySelector(\"#iseBookDownload\").value = \"true\";\n\t\t\t\tdocument.querySelector(\"#recentConversionAction\").value = \"eBook Download\";\n\t\t\t\tdocument.querySelector(\"#referringWebsite\").value = utmObject.referringWebsite || \"\";\n\t\t\t\tdocument.querySelector(\"#recenteBookRequest\").value = marketoCampaignName;\n\t\t\t\tdocument.querySelector(\"#recenteBookURL\").value = ebookUrl;\n\t\t\t\tcopyEbookFieldsToMarketoForm(eBook.formName);\n\n\t\t\t\tif (isNewsletterChecked(eBook.formName) === true) {\n\t\t\t\t\tdocument.querySelector(\"#isEmailSignup\").value = true;\n\t\t\t\t\toptins += \" eNews\";\n\t\t\t\t\tsetOptsOnMarketoForm();\n\t\t\t\t}\n\n\t\t\t\tif (isSMSOptinChecked(eBook.formName) === true) {\n\t\t\t\t\tdocument.querySelector(\"#isSMSSignup\").value = true;\n\t\t\t\t\toptins += \" SMS\";\n\t\t\t\t\tsetSMSOptsOnMarketoForm();\n\t\t\t\t}\n\n\t\t\t\t// stupid edge case just to get a comma in the string\n\t\t\t\toptins = optins.replace(\"eNews SMS\", \"eNews, SMS\");\n\n\t\t\t\toptins = optins || \" no optins\"; // if empty string, set to no optins\n\t\t\t\tlet pushEventString = `Submitted w/${optins}`;\n\n\t\t\t\tpushEvent(\"Gated Content\", \"eBook\", pushEventString);\n\n\t\t\t\tmarketoSubmitFormEbook();\n\t\t\t\tpushEventFacebook();\n\t\t\t\tpushEventBing();\n\n\t\t\t\t// click hidden OptinMonster button to advance to success screen\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tdocument.querySelector(\".js-ebook-goto-success button\").click();\n\t\t\t\t}, 2100);\n\t\t\t});\n\t\t}\n\n\t\tfunction marketoSubmitFormEbook() {\n\t\t\tif (checkMarketoForm() === false) {\n\t\t\t\tpushEvent(\"Marketo\", \"Form\", \"Not Loaded during marketoSubmitForm()\");\n\t\t\t}\n\t\t\tMktoForms2.whenReady(function (form) {\n\t\t\t\tform.submit();\n\t\t\t});\n\t\t}\n\n\t\t// resume ambient video play when modal is closed\n\t\tdocument.addEventListener(\"om.Campaign.afterClose\", function (event) {\n\t\t\tsessionStorage.setItem(\"modalOpen\", false);\n\t\t\ttoggleAmbientVideo(true);\n\t\t});\n\t}\n\n\t// Function: if campaign is removed above due to open chat, etc. remove these OM classes to make their overlay go away. Worked with OM tech and this was the only solution. Boo Monsty.\n\tfunction removeOmOverlay() {\n\t\tsetTimeout(function () {\n\t\t\ttry {\n\t\t\t\tdocument.querySelector(\"html\").classList.remove(\"om-position-popup\");\n\t\t\t\tdocument.querySelector(\"body\").classList.remove(\"om-effect-overlay\");\n\t\t\t} catch (error) {}\n\t\t}, 1500);\n\t}\n\n\t// Event: this runs right before a campaign screen is visible and for every view (yes/no, optin, success)\n\tdocument.addEventListener(\"om.Campaign.load\", (event) => {\n\t\tlet omCampaign = document.querySelector(\"#om-\" + event.detail.Campaign.id);\n\n\t\t// Check if any other modals are open or if inline Wistia video is playing\n\t\tif (event.detail.Campaign.view === \"optin\") {\n\t\t\tif (window.location.pathname.includes(\"/blog/\")) {\n\t\t\t\teBookModal(event.detail.Campaign.id);\n\t\t\t} else {\n\t\t\t\tlet isModalOpenOrVideoPlaying = callOpenModalAndVideoFunctions();\n\n\t\t\t\tif (isModalOpenOrVideoPlaying || isChatOpen()) {\n\t\t\t\t\tomCampaign.remove();\n\t\t\t\t\tremoveOmOverlay();\n\t\t\t\t} else eBookModal(event.detail.Campaign.id);\n\t\t\t}\n\t\t}\n\t\t// Event: when success screen loads, click on ebook link for user\n\t\tif (event.detail.Campaign.view === \"success\") {\n\t\t\tdocument.querySelector(\".js-ebook-goto-url\").click();\n\t\t}\n\n\t\t// Event: listen for click on bottom nav on mobile to close campaign\n\t\tlet browserDevice = getBrowserDevice();\n\n\t\tif (browserDevice === \"mobile\") {\n\t\t\tconst mobileMenuLinks = document.querySelectorAll(\"[nav-site-links--mobile] label\");\n\t\t\tmobileMenuLinks.forEach((link) => {\n\t\t\t\tlink.addEventListener(\"click\", function () {\n\t\t\t\t\tif (omCampaign) {\n\t\t\t\t\t\tomCampaign.remove();\n\t\t\t\t\t\tremoveOmOverlay();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t});\n}\n","import { getBrowserDevice } from \"../../../assets/js/utilities.js\";\n\nexport function magicCta() {\n\tconst magicCTA = document.querySelector(\"[magic]\");\n\tconst main = document.querySelector(\"[main]\");\n\tlet magicWrapper = document.querySelector(\"[js-magic-wrapper]\");\n\tlet magicClose = document.querySelector(\"[js-magic-close-button]\");\n\n\t// check it\n\tif (!magicWrapper) return;\n\tif (!magicClose) return;\n\n\t// check for cookie\n\tif (Cookies.get(\"magic\") == \"hide\") {\n\t\tmagicWrapper.setAttribute(\"hide\", \"all\");\n\t} else {\n\t\tmagicClose.addEventListener(\"click\", function () {\n\t\t\tsetCookie(\"magic\", \"hide\", 7);\n\t\t\tmagicWrapper.setAttribute(\"hide\", \"all\");\n\t\t});\n\t}\n\n\tif (!main) {\n\t\tmagicCTA.classList.add(\"js-default-magic-position\");\n\t}\n\n\tif (magicCTA.classList.contains(\"js-default-magic-position\")) return;\n\n\tfunction positionMagicCTA(direction) {\n\t\tlet mainPosition = ScrollTrigger.positionInViewport(main, \"bottom\");\n\n\t\t// scrolling down\n\t\tif (direction === 1 && mainPosition < 0.85) {\n\t\t\tmagicCTA.classList.add(\"js-reposition-magic\");\n\t\t}\n\n\t\t// scrolling up\n\t\tif (direction === -1 && mainPosition > 0.8) {\n\t\t\tmagicCTA.classList.remove(\"js-reposition-magic\");\n\t\t}\n\t}\n\n\tfunction setCookie(name, value, days) {\n\t\tconst date = new Date();\n\t\tdate.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\n\t\tconst expires = \"expires=\" + date.toUTCString();\n\t\tdocument.cookie = name + \"=\" + value + \";\" + expires + \";path=/\";\n\t}\n\n\tif (getBrowserDevice() === \"desktop\" && main) {\n\t\tScrollTrigger.create({\n\t\t\ttrigger: main,\n\t\t\tonUpdate: (self) => positionMagicCTA(self.direction)\n\t\t});\n\t}\n}\n","import { pushEvent } from \"../../../assets/js/utilities.js\";\n\nexport function manageFavorites() {\n\tconst favoritedTrips = get_favorites_from_local_storage();\n\tconst isFavoritesFlagPageload = localStorage.getItem(\"favoritesSubmitToMarketo\") === \"pageload\";\n\tconst repeaterHearts = document.querySelectorAll(\"[js-get-repeater-heart] svg[js-click-heart]\");\n\tconst tripPageHeart = document.querySelector(\"[js-get-trip-heart] svg[js-click-heart]\");\n\tlet heartData = [];\n\n\t// on page load: delete favorites feature flag, populate dropdown, monitor stuff\n\tlocalStorage.removeItem(\"favorites\");\n\tadd_all_favorites_to_dropdown(favoritedTrips);\n\tmonitor_dropdown_open_close_state();\n\tmonitor_favorite_changes_across_tabs();\n\n\t// submit to Marketo if flag set\n\tif (isFavoritesFlagPageload) {\n\t\tsubmit_updated_favorites_to_marketo(favoritedTrips);\n\t\tlocalStorage.setItem(\"favoritesSubmitToMarketo\", \"\");\n\t}\n\n\t// find all the hearts\n\tconst repeaterHeartsData = repeaterHearts.length > 0 ? get_repeater_hearts_trip_data(repeaterHearts) : [];\n\tconst tripPageHeartData = tripPageHeart ? get_trip_page_heart_trip_data(tripPageHeart) : [];\n\n\theartData = [...repeaterHeartsData, ...tripPageHeartData];\n\n\t// check if hearts on the page:\n\tif (heartData.length < 1) return;\n\n\t// add click listenter to all hearts\n\ttoggle_favorite_status_when_clicked(heartData);\n\n\t// compare favorited trips in local storage to hearts on the page\n\tconst favoritedHearts = get_favorited_hearts(favoritedTrips, heartData);\n\n\t// check if favorited hearts on the page:\n\tif (favoritedHearts.length < 1) return;\n\n\tconst heartElements = favoritedHearts.map((data) => data.heartElement);\n\tconst updatedTripList = favoritedHearts.map(({ tripPageID, tripName, tripUrl }) => ({ tripPageID, tripName, tripUrl }));\n\n\t// add class to favorited hearts\n\tadd_favorite_heart_class(heartElements);\n\n\t// reset local storage\n\treset_local_storage(updatedTripList);\n}\n\n// Heart functions\nfunction get_repeater_hearts_trip_data(hearts) {\n\tconst heartData = [];\n\n\thearts.forEach((heartElement) => {\n\t\tconst tripRepeater = heartElement.closest(\"[js-get-repeater-heart]\");\n\t\tif (!tripRepeater) return;\n\n\t\tconst tripPageIdElement = tripRepeater.querySelector(\"[js-get-trip-page-id]\") || tripRepeater;\n\t\tconst tripLink = tripRepeater.querySelector(\"[js-get-repeater-link]\");\n\n\t\tif (!tripPageIdElement || !tripLink) return;\n\n\t\tconst tripPageID = tripPageIdElement.getAttribute(\"js-get-trip-page-id\");\n\t\tconst tripUrl = tripLink.getAttribute(\"href\");\n\t\tconst tripName = tripLink.querySelector(\"[js-get-favorites-name]\").textContent.trim();\n\t\tconst heartType = \"Repeater\";\n\n\t\theartElement.setAttribute(\"js-set-heart-type\", heartType);\n\t\theartElement.setAttribute(\"js-set-heart-trip-id\", tripPageID);\n\n\t\theartData.push({ heartElement, tripPageID, tripName, tripUrl, heartType });\n\t});\n\n\treturn heartData;\n}\n\nfunction get_trip_page_heart_trip_data(heartElement) {\n\tconst tripPageIdElement = document.querySelector(\"[js-get-trip-overview-page-id]\");\n\tlet tripName = document.querySelector(\"[js-get-trip-heart]\");\n\tlet tripUrl = window.location.pathname;\n\tconst heartType = \"TripPage\";\n\tconst heartData = [];\n\n\tif (!tripPageIdElement || !tripName) return;\n\n\tconst tripPageID = tripPageIdElement.getAttribute(\"js-get-trip-overview-page-id\");\n\ttripName = tripName.textContent.trim();\n\n\t// if pathname longer than 2 levels deep, remove it = remembering trip overview pages only\n\tif (tripUrl.split(\"/\").length > 3) tripUrl = tripUrl.split(\"/\").slice(0, 3).join(\"/\") + \"/\";\n\n\theartElement.setAttribute(\"js-set-heart-type\", heartType);\n\theartElement.setAttribute(\"js-set-heart-trip-id\", tripPageID);\n\n\theartData.push({ heartElement, tripPageID, tripName, tripUrl, heartType });\n\n\treturn heartData;\n}\n\nfunction add_favorite_heart_class(favoritedHearts) {\n\tfavoritedHearts.forEach((heart) => {\n\t\tif (!heart) return;\n\t\theart.classList.add(\"js-favorite-trip\");\n\t});\n}\n\nfunction toggle_favorite_status_when_clicked(heartData) {\n\theartData.forEach(({ heartElement, tripPageID, tripName, tripUrl, heartType }) => {\n\t\tif (!heartElement) return;\n\n\t\theartElement.addEventListener(\"click\", () => {\n\t\t\tif (heartElement.classList.contains(\"js-favorite-trip\")) {\n\t\t\t\t// trip removed: set flag to submit to Marketo on next page load\n\t\t\t\tlocalStorage.setItem(\"favoritesSubmitToMarketo\", \"pageload\");\n\t\t\t\tremove_favorite_from_local_storage(tripPageID);\n\t\t\t\tremove_favorite_from_dropdown(tripPageID);\n\t\t\t\theartElement.classList.remove(\"js-favorite-trip\");\n\t\t\t\tpushEvent(\"Favorites\", `Removed_${tripName}`, heartType);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// trip added: from repeater, set flag to submit to Marketo on next page load; from trip page, submit immediately from local storage function\n\t\t\tlet submitToMarketo = \"pageload\"; // values for local storage: pageload, now, empty string\n\t\t\tif (heartType === \"TripPage\") submitToMarketo = \"now\";\n\t\t\tlocalStorage.setItem(\"favoritesSubmitToMarketo\", submitToMarketo);\n\n\t\t\tadd_favorite_to_local_storage(tripPageID, tripName, tripUrl);\n\t\t\theartElement.classList.add(\"js-favorite-trip\");\n\t\t\tpushEvent(\"Favorites\", `Added_${tripName}`, heartType);\n\n\t\t\t// for dramatic effect: open favorites dropdown, add trip, then close dropdown if masthead in viewport\n\t\t\tconst mastheadHeart = document.querySelector(\"[js-get-masthead-heart]\");\n\t\t\tconst isMastheadVisible = mastheadHeart && mastheadHeart.getBoundingClientRect().top > 0;\n\n\t\t\tif (!isMastheadVisible) {\n\t\t\t\tadd_favorite_to_dropdown(tripPageID, tripName, tripUrl);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst favoritesDropdown = document.querySelector(\"[js-click-masthead-favorites]\");\n\t\t\topen_close_favorites_dropdown(favoritesDropdown, true);\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tadd_favorite_to_dropdown(tripPageID, tripName, tripUrl);\n\t\t\t}, 1000);\n\n\t\t\tsetTimeout(() => {\n\t\t\t\topen_close_favorites_dropdown(favoritesDropdown, false);\n\t\t\t}, 3000);\n\t\t});\n\t});\n}\n\n// Local storage functions\nfunction get_favorites_from_local_storage() {\n\tlet favorites = JSON.parse(localStorage.getItem(\"favoritesList\")) || {};\n\tconst favoritedTrips = [];\n\n\tfor (let tripPageID in favorites) {\n\t\tconst { tripName, tripUrl } = favorites[tripPageID];\n\t\tfavoritedTrips.push({ tripPageID, tripName, tripUrl });\n\t}\n\treturn favoritedTrips;\n}\n\nfunction reset_local_storage(updatedTripList) {\n\tconst updatedFavorites = {};\n\n\tupdatedTripList.forEach(({ tripPageID, tripName, tripUrl }) => {\n\t\tupdatedFavorites[tripPageID] = { tripName, tripUrl };\n\t});\n\n\tlocalStorage.setItem(\"favoritesList\", JSON.stringify(updatedFavorites));\n}\n\nfunction add_favorite_to_local_storage(tripPageID, tripName, tripUrl) {\n\tlet favorites = JSON.parse(localStorage.getItem(\"favoritesList\")) || {};\n\tlet submitToMarketoNow = localStorage.getItem(\"favoritesSubmitToMarketo\") === \"now\";\n\n\t// Add trip to favorites object with tripPageID as the key\n\tfavorites[tripPageID] = { tripName, tripUrl };\n\tlocalStorage.setItem(\"favoritesList\", JSON.stringify(favorites));\n\n\t// submit immediately if fave saved from trip page\n\tif (!submitToMarketoNow) return;\n\n\tsubmit_updated_favorites_to_marketo(favorites);\n\tlocalStorage.setItem(\"favoritesSubmitToMarketo\", \"\");\n}\n\nfunction get_favorited_hearts(favoritedTrips, heartData) {\n\tconst favoritedHearts = [];\n\n\t// loop through favorited trips in local storage and compare to heart data on page\n\tfavoritedTrips.forEach(({ tripPageID, tripName, tripUrl }) => {\n\t\tconst heartDataTrip = heartData.find(({ tripPageID: heartTripPageID }) => tripPageID === heartTripPageID);\n\n\t\tlet heartElement = null;\n\t\tlet name = tripName;\n\t\tlet url = tripUrl;\n\n\t\t// If favorited trip is on page, use heartData tripName and tripUrl instead so any change to trip name or url is updated in local storage\n\t\tif (heartDataTrip) ({ heartElement, tripName: name, tripUrl: url } = heartDataTrip);\n\n\t\tfavoritedHearts.push({\n\t\t\theartElement,\n\t\t\ttripPageID,\n\t\t\ttripName: name,\n\t\t\ttripUrl: url\n\t\t});\n\t});\n\n\treturn favoritedHearts;\n}\n\nfunction monitor_favorite_changes_across_tabs() {\n\t// if favorites object changes in local storage, update dropdown and hearts in other open tabs on the fly = mind blown\n\twindow.addEventListener(\"storage\", (e) => {\n\t\tif (e.key === \"favoritesList\") {\n\t\t\t// parse old and new values, if null set to empty object\n\t\t\tconst oldFavorites = JSON.parse(e.oldValue) || {};\n\t\t\tconst newFavorites = JSON.parse(e.newValue) || {};\n\n\t\t\t// Determine what was added and removed by comparing keys of old and new objects\n\t\t\tconst addedFavorite = Object.keys(newFavorites).find((key) => !oldFavorites[key]);\n\t\t\tconst removedFavorite = Object.keys(oldFavorites).find((key) => !newFavorites[key]);\n\n\t\t\t// Update added favorite in other tabs\n\t\t\tif (addedFavorite) {\n\t\t\t\tconst { tripName, tripUrl } = newFavorites[addedFavorite];\n\t\t\t\tconst heart = document.querySelector(`[js-set-heart-trip-id=\"${addedFavorite}\"]`);\n\n\t\t\t\tif (heart) heart.classList.add(\"js-favorite-trip\");\n\t\t\t\tadd_favorite_to_dropdown(addedFavorite, tripName, tripUrl);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Update removed favorite in other tabs\n\t\t\tif (removedFavorite) {\n\t\t\t\tconst heart = document.querySelector(`[js-set-heart-trip-id=\"${removedFavorite}\"]`);\n\n\t\t\t\tif (heart) heart.classList.remove(\"js-favorite-trip\");\n\t\t\t\tremove_favorite_from_dropdown(removedFavorite);\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction remove_favorite_from_local_storage(tripPageID) {\n\tlet favorites = JSON.parse(localStorage.getItem(\"favoritesList\")) || {};\n\n\tdelete favorites[tripPageID];\n\tlocalStorage.setItem(\"favoritesList\", JSON.stringify(favorites));\n}\n\nfunction submit_updated_favorites_to_marketo(favorites) {\n\t// create a string of tripNames and submit to Marketo\n\tconst favoritedTrips = [];\n\n\tfor (let key in favorites) {\n\t\tconst { tripName } = favorites[key];\n\t\tfavoritedTrips.push(tripName);\n\t}\n\n\tlet favoritedTripsString = favoritedTrips.join(\", \");\n\n\tfunction postFormFavorites() {\n\t\tlet retryLimit = 3,\n\t\t\tretryAttempt = 0;\n\n\t\tif (checkMarketoForm() === false && retryAttempt < retryLimit) {\n\t\t\tinitMarketoForm(function () {\n\t\t\t\tretryAttempt++;\n\t\t\t\tpostFormFavorites();\n\t\t\t});\n\t\t}\n\n\t\tMktoForms2.whenReady(function () {\n\t\t\tconst marketoFavoriteTripsField = document.querySelector(\"#favoritedTrips\");\n\n\t\t\tif (!marketoFavoriteTripsField) return;\n\n\t\t\tmarketoFavoriteTripsField.value = favoritedTripsString;\n\t\t\tmarketoSubmitFormFavorites();\n\n\t\t\tfunction marketoSubmitFormFavorites() {\n\t\t\t\tif (checkMarketoForm() === false) {\n\t\t\t\t\tpushEvent(\"Marketo\", \"Form\", \"Not Loaded during marketoSubmitForm()\");\n\t\t\t\t}\n\n\t\t\t\tMktoForms2.whenReady(function (form) {\n\t\t\t\t\tform.submit();\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\tpostFormFavorites();\n}\n\n// Dropdown functions\nfunction add_all_favorites_to_dropdown(favoritedTrips) {\n\tconst favoritesSavedDropdown = document.querySelector(\"[js-show-if-favorites-saved]\");\n\tif (!favoritesSavedDropdown) return;\n\n\tlet allFavoritesHTML = \"\";\n\n\tfavoritedTrips.forEach(({ tripPageID, tripName, tripUrl }) => {\n\t\tallFavoritesHTML += create_favorite_html(tripPageID, tripName, tripUrl);\n\t});\n\n\t// Insert all favorites HTML into the DOM at once\n\tfavoritesSavedDropdown.insertAdjacentHTML(\"beforeend\", allFavoritesHTML);\n\n\t// Add event listeners to all dropdown elements\n\tfavoritedTrips.forEach(({ tripPageID, tripName }) => {\n\t\tconst newLink = document.querySelector(`[js-favorite-trip-name=\"${tripName}\"] [js-click-favorite-link]`);\n\t\tconst newDeleteButton = document.querySelector(`[js-favorite-trip-name=\"${tripName}\"] [js-delete-favorite]`);\n\n\t\tadd_click_listener_to_dropdown_link(newLink);\n\t\tadd_click_listener_to_delete_button(tripPageID, tripName, newDeleteButton);\n\t});\n\n\talphabetize_favorites_dropdown();\n}\n\nfunction add_favorite_to_dropdown(tripPageID, tripName, tripUrl) {\n\t// check if trip is already in dropdown\n\t// tripPageID = tripPageID.trim();\n\tif (document.querySelector(`[js-favorite-trip-id=\"${tripPageID}\"]`)) return;\n\n\tconst favoritesSavedDropdown = document.querySelector(\"[js-show-if-favorites-saved]\");\n\tconst newFavoriteHTML = create_favorite_html(tripPageID, tripName, tripUrl);\n\n\tfavoritesSavedDropdown.insertAdjacentHTML(\"beforeend\", newFavoriteHTML);\n\n\tconst newLink = document.querySelector(`[js-favorite-trip-name=\"${tripName}\"] [js-click-favorite-link]`);\n\tconst newDeleteButton = document.querySelector(`[js-favorite-trip-name=\"${tripName}\"] [js-delete-favorite]`);\n\n\tadd_click_listener_to_dropdown_link(newLink);\n\tadd_click_listener_to_delete_button(tripPageID, tripName, newDeleteButton);\n\talphabetize_favorites_dropdown();\n}\n\nfunction create_favorite_html(tripPageID, tripName, tripUrl) {\n\treturn `\n