{"version":3,"mappings":";stFA6CI,MAAMA,EAAQC,EAORC,EAAwC,CAC1C,OAAQ,GACR,WAAY,MACZ,QAAS,GACT,MAAO,SACP,IAAK,EACL,QAAS,CAAC,MAAO,MAAO,EACxB,WAAY,QACZ,YAAY,CACR,KACI,CACI,QAAS,EACb,CACR,GAGEC,EAAmBC,EAAe,gBAAgB,EAClDC,EAA6BL,EAAM,QAAQ,kBAAoBA,EAAM,QAAQ,2BAEnF,OAAAM,EAAS,IAAM,CACXC,EAAaJ,EAAiB,KAAK,EACtC,0lGCpBK,MAAAK,EAAwB,KAAK,OAfrBP,EAekC,gBAAgB,MAAM,OAAS,GAAK,CAAC,EAAI,8yDCpCzF,MAAMD,EAAQC,EAWRQ,EAAaC,EAAI,EAAK,EACtBC,EAAkBD,EAAmB,EAAE,EAE7CE,EAAYZ,EAAM,cAAc,EAC3B,KAAMa,GAAiB,CAEhBA,EAAa,SAAS,OACtBC,EAAqBD,EAAa,QAAQ,GAE1C,QAAQ,IAAI,6DAA6D,EAE7DD,EAAA,CACR,aAAc,CAAC,sBAAsB,EACrC,MAAO,EACP,KAAM,oCACT,EAAE,KAAMG,GAAyB,CAE1BA,EAAqB,SAAS,QAC9BD,EAAqBC,EAAqB,QAAQ,CACtD,EAED,IAAM,CAEL,QAAQ,MAAM,kCAAkC,EACnD,EACL,EAED,IAAM,CAEL,QAAQ,MAAM,mCAAmC,EACpD,EAGL,SAASD,EAAqBE,EAAwC,CAClE,MAAMC,EAAeD,EAAS,OAErBA,EAAA,QAAQ,CAACE,EAAqCC,IAAyB,CAC5ER,EAAgB,MAAM,KAAK,CACvB,WAAYO,EAAQ,WACpB,eAAiBA,EAAQ,sBAAyBA,EAAQ,sBAAwB,SAClF,SAAUE,EAAoBF,EAAQ,aAAc,CAAE,MAAO,IAAK,EAClE,cAAgBA,EAAQ,qBAAuB,IAAO,YAAc,GACpE,MAAOA,EAAQ,SACf,IAAKG,EAAY,oBAAoBH,EAAQ,UAAU,EAAE,EACzD,WAAaD,IAAiB,GAAMA,IAAiB,GAAKE,GAAgB,EAAM,UAAY,GAC/F,EACJ,EAEDV,EAAW,MAAQ,EACvB,+XClEA,MAAMT,EAAQC,EAWRqB,EAAoBC,EAAW,IAAI,EACnCC,EAAgCd,EAAI,IAAI,EAExCe,MAAmB,IAAoE,CACzF,CAAC,2CACA,CACI,UAAWC,EAAqB,IAAMC,GAAA,WAAO,gEAA6E,yBAAC,EAC3H,MAAO,CAAE,eAAgB,0CAA2C,CACxE,CACD,EACH,EAEsB,OAAAC,EAAA,EAClB,QAAQ,IAAM,CACP,GAAAC,EAAe,uDAAuD,IAAM,IACjE,UAAAC,KAAO9B,EAAM,KAChB,GAAAyB,EAAa,IAAIK,CAAG,EAAG,CACLR,EAAA,MAAQG,EAAa,IAAIK,CAAG,EAC9C,KACJ,EAKHR,EAAkB,QACnBE,EAA8B,MAAQO,GAA0B/B,EAAM,KAAK,KAAK,EAAGA,EAAM,UAAU,EACvG,CACH,mRCnCL,MAAMgC,EAA2B,OAAO,SAAS,OAAO,SAAS,eAAe,EAE1EC,EAA2C,CAC7C,aAAc,CAAC,sBAAsB,EACrC,KAAMD,EAA2B,eAAiB,4YCRtD,MAAMhC,EAAQC,EAeRiC,EAAelC,EAAM,MAASA,EAAM,MAAQ,qlCC8E5CmC,GAAc,6CANd,MAAAjB,EAAUR,EAAI,EAAkB,EAChC0B,EAAgB1B,EAAI,EAAmB,EACvC2B,EAAc3B,EAAI,EAAc,EAChC4B,EAAU5B,EAAI,EAAK,EACnB6B,EAAkB7B,EAAI,EAAK,EAC3B8B,EAAe9B,EAAI,EAAK,EAExB+B,EAAsB/B,EAAI,EAA4B,EACtDgC,EAAmBhC,EAAI,EAAsB,EAC7CiC,EAAiBjC,EAAI,EAAE,EACvBkC,EAAWlC,EAAI,EAAmB,EAClCmC,EAAoBnC,EAAI,EAAK,EAC7BoC,EAAgB1C,EAA4B,gBAAgB,EAE5D2C,EAAWC,EAAS,IAAM9B,EAAQ,MAAM,YAAc,MAAQ,KAAK,EAEnEgB,EAAcc,EAAS,IAAM,CACzB,MAAAC,EAAmB/B,EAAQ,MAAM,YAAY,OAAQgC,GAAUA,EAAK,WAAY,EAAE,OAClFC,EAAiBjC,EAAQ,MAAM,YAAY,OAAQgC,GAAUA,EAAK,aAAa,QAAS,EAAE,OAEhG,OAAQD,EAAmB,GAAKE,EAAiB,EAAK,sCAAwC,GACjG,EAEKC,EAAcJ,EAAS,IAAM,WAE/B,IAAIK,EAAqB,GAEzB,QAASC,EAAI,EAAGA,GAAK,EAAGA,IACpB,IAAIC,EAAAX,EAAS,MAAMU,CAAC,IAAhB,MAAAC,EAAmB,UAAWC,EAAAZ,EAAS,MAAMU,CAAC,IAAhB,MAAAE,EAAmB,WAAYC,EAAAb,EAAS,MAAMU,CAAC,IAAhB,MAAAG,EAAmB,MAAO,CAClEJ,EAAA,GACrB,KACJ,CAGG,OAAAA,CAAA,CACV,EAED,OAAAK,GAAW,OAAO,SAAS,UAAU,EAAE,KAAMC,GAAoB,OAEzDnB,EAAa,MAAQmB,EAAgB,aAE7BzC,EAAA,MAAQ0C,GAAyBD,CAAe,EAE1CvB,EAAA,MAAQyB,GAA+BF,CAAe,EAExDtB,EAAA,MAASsB,EAAgB,KAAQA,EAAgB,KAAK,MAAM,GAAG,EAAI,GAE9DjB,EAAA,MAAQoB,GAAyCH,CAAe,EAExEf,EAAA,MAAQmB,GAAgCJ,CAAe,EACjDhB,EAAA,MAAQgB,EAAgB,mBAAqB,GAExDzC,EAAQ,MAAM,YAAY,OAAS,IACnCuB,EAAoB,MAAQvB,EAAQ,MAAM,YAAY,MAAM,CAAC,GAIjE,MAAM8C,EAAWC,KACCpB,EAAA,MAAQmB,EAAS,oBAAsB,IAGzD1B,EAAQ,MAAQ,GAEhBhC,EAAS,IAAM,CACX4D,GAA4BpB,EAAc,KAAK,EAC/CqB,GAAarB,EAAc,KAAK,EACpBsB,IAAA,CACf,EAED,MAAMC,IAAqBd,EAAAnB,EAAc,MAAM,OAApB,YAAAmB,EAA0B,MAAM,KAAK,OAAQzB,GAAQA,EAAI,WAAW,kBAAkB,KAAM,GAEvHwC,GAAW,YACH,CACI,QAASpD,EAAQ,MAAM,WACvB,UAAWkB,EAAc,MAAM,SAC/B,cAAe,cACf,eAAgBA,EAAc,MAAM,OACpC,eAAiBlB,EAAQ,MAAM,YAAe,YAAc,gBAC5D,eAAgBkB,EAAc,MAAM,WAAW,KAAK,IAAI,EAExD,GAAKiC,EAAmB,QAAU,CAAE,eAAgBA,EAAmB,KAAK,IAAI,CAAE,CACtF,EAAC,EAEV,IAAM,CACLE,GAAW,uBAAuB,EAClChC,EAAgB,MAAQ,GAC3B,ouHClLHiC,GAAMC,GAAUC,EAAqB,EAE3CC,GAASH,GAAK,UAAU","names":["props","__props","carouselConfig","articleHeaderRef","useTemplateRef","shouldUseWideHeroOnDesktop","nextTick","enableHearts","lastItemInFirstColumn","hasContent","ref","relatedArticles","getArticles","articlesJSON","populateContentTiles","fallbackArticlesJSON","articles","articleCount","article","articleIndex","generateCmsImageUrl","cobrandLink","componentToRender","shallowRef","relatedArticlesSearchCriteria","componentMap","defineAsyncComponent","__vitePreload","initializeFeatureFlags","getFeatureFlag","tag","buildRelatedArticlesQuery","shouldSortByModifiedDate","articleSearchCriteria","adZoneLabel","topAdZoneId","articleHeader","articleTags","isReady","displayFallback","useTopAdZone","extendedBodyContent","findAnAdvisorCta","productsHeader","products","hideFindAnAdvisor","componentRoot","adZoneId","computed","numArticleFields","item","numImageFields","hasProducts","isProductPopulated","i","_a","_b","_c","getArticle","articleResponse","transformCmsBasicArticle","transformCmsBasicArticleHeader","transformCmsBasicArticleFindAnAdvisorCta","transformCmsArticleProductCards","qsParams","parseURLParameters","translateLinksToConsumerUrl","cobrandLinks","goToURLHash","destinationHubTags","trackEvent","toastError","app","createApp","ArticleBasicComponent","mountApp"],"ignoreList":[],"sources":["../../../scripts/components/article/article-header.vue","../../../scripts/components/article/article-itinerary.vue","../../../scripts/components/article/related-articles.vue","../../../scripts/components/article/related-content.vue","../../../scripts/components/pages/articles-landing.vue","../../../scripts/components/shared/ad-zone.vue","../../../scripts/components/pages/article-basic.vue","../../../scripts/entry-points/articles.ts"],"sourcesContent":["<template>\r\n <div ref=\"article-header\" data-testid=\"article-header\" :class=\"['container p-0 mb-3 article-header', {'extra-wide-1920 text-center': content.useWideHeroImage}, content.useWideHeroHeadlineOverlay ? '-overlay mt-0' : 'mt-2']\">\r\n <div class=\"position-relative\">\r\n <div :class=\"['title-container px-2 p-md-0 mb-2', {'context-dark': content.useWideHeroHeadlineOverlay}]\">\r\n <h1 v-html=\"content.headline\"></h1>\r\n <template v-if=\"!content.useWideHeroImage\">\r\n <div v-if=\"content.author\" class=\"article-author weglot-exclude\">{{ content.author }}</div>\r\n <div v-if=\"content.date\" class=\"article-date\">{{ content.date }}</div>\r\n <button class=\"wl-heartable -save-this d-xl-none mt-1 ps-0\" data-wl-type=\"article\" :data-wl-id=\"content.identifier\" :data-wl-title=\"content.headline\"></button>\r\n </template>\r\n <div class=\"position-relative\">\r\n <button v-if=\"!content.useWideHeroImage\" class=\"wl-heartable -save-this -right d-none d-xl-block\" data-wl-type=\"article\" :data-wl-id=\"content.identifier\" :data-wl-title=\"content.headline\"></button>\r\n <ul v-if=\"content.categories.length && !isEmbeddedMode()\" class=\"category-links mt-1 context-dark\" aria-label=\"Article Categories\">\r\n <li v-for=\"(category, index) in content.categories\" :key=\"index\">\r\n <a :href=\"getCategoryLink(category)\" :class=\"['-tag', {'-emphasis' : !content.useWideHeroHeadlineOverlay}]\">{{ category }}</a>\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n\r\n <captioned-image-carousel-component v-if=\"content.heroImages.length === 3\" carousel-class=\"carousel-responsive-3vert\" :slides=\"content.heroImages\" :carousel-config=\"carouselConfig\" data-testid=\"captioned-image-carousel\"></captioned-image-carousel-component>\r\n <captioned-image-component v-if=\"content.heroImages.length === 1\" :caption-class=\"content.useWideHeroImage ? '-cozy mx-2' : 'mx-2'\" container-class=\"mb-3 hero-horizontal\" :content=\"content.heroImages[0]\" data-testid=\"captioned-image\" :should-use-wide-hero-on-desktop=\"shouldUseWideHeroOnDesktop\"></captioned-image-component>\r\n </div>\r\n <template v-if=\"content.useWideHeroImage\">\r\n <div class=\"d-flex flex-column flex-md-row gap-md-2 align-items-center justify-content-center px-2\">\r\n <span v-if=\"content.author\" class=\"article-author weglot-exclude text-emphasis\">{{ content.author }}</span>\r\n <span class=\"text--small d-none d-md-block\">•</span>\r\n <span v-if=\"content.date\" class=\"article-date\">{{ content.date }}</span>\r\n <span class=\"text--small d-none d-md-block\">•</span>\r\n <button class=\"wl-heartable -save-this p-1\" data-wl-type=\"article\" :data-wl-id=\"content.identifier\" :data-wl-title=\"content.headline\"></button>\r\n </div>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import CaptionedImageCarouselComponent from \"components/shared/captioned-image-carousel.vue\";\r\n import CaptionedImageComponent from \"components/shared/captioned-image.vue\";\r\n import { ArticleHeader } from \"interfaces/article\";\r\n import { CarouselConfigOptions } from \"interfaces/carousel\";\r\n import { getCategoryLink } from \"services/helpers/categories\";\r\n import { isEmbeddedMode } from \"services/layout/environment\";\r\n import { enableHearts } from \"services/wanderlist\";\r\n import { nextTick, PropType, useTemplateRef } from \"vue\";\r\n\r\n const props = defineProps({\r\n content: {\r\n type: Object as PropType<ArticleHeader>,\r\n default: undefined\r\n }\r\n });\r\n\r\n const carouselConfig: CarouselConfigOptions = {\r\n arrows: false,\r\n mediaQuery: \"max\",\r\n destroy: true,\r\n focus: \"center\",\r\n gap: 0,\r\n padding: {right: \"3rem\" },\r\n fixedWidth: \"300px\",\r\n breakpoints:{\r\n 1200:\r\n {\r\n destroy: false\r\n }\r\n }\r\n };\r\n\r\n const articleHeaderRef = useTemplateRef(\"article-header\");\r\n const shouldUseWideHeroOnDesktop = props.content.useWideHeroImage && props.content.useWideHeroHeadlineOverlay;\r\n\r\n nextTick(() => {\r\n enableHearts(articleHeaderRef.value);\r\n });\r\n</script>\r\n","<template>\r\n <div class=\"editorial-itinerary\">\r\n <div class=\"table-of-contents\">\r\n <h3>{{ tableOfContents.header }}</h3>\r\n\r\n <ul :class=\"['list-unstyled', {'short-list': tableOfContents.items.length < 6 } ]\">\r\n <li v-for=\"(item, idx) in tableOfContents.items\" :key=\"idx\" :class=\"['my-1 gap-1', {'break-column': idx === lastItemInFirstColumn} ]\">\r\n <span v-if=\"item.label\" class=\"fw-bold text--small text--sans-serif text-nowrap item-label\">{{ item.label }}</span>\r\n <a :href=\"`#${item.jumpLinkId}`\" class=\"-no-decoration-idle\">{{ item.text }}</a>\r\n </li>\r\n </ul>\r\n </div>\r\n\r\n <div class=\"itinerary-section\">\r\n <template v-for=\"(item, idx) in content\" :key=\"idx\">\r\n <div class=\"itinerary-item\">\r\n <CaptionedImagePair :left-image=\"item.imageLeft\" :right-image=\"item.imageRight\"></CaptionedImagePair>\r\n\r\n <h3 :id=\"item.jumpLinkId\" class=\"section-header\">{{ item.header }}</h3>\r\n\r\n <div class=\"section-content\" v-html=\"item.text\"></div>\r\n </div>\r\n \r\n <FindAnAdvisorCtaComponent v-if=\"idx == 2 && !isEmbeddedMode()\" :button-text=\"advisorCta.buttonText\" :custom-button-link=\"advisorCta.buttonLink\" :custom-content-text=\"advisorCta.contentText\" :custom-header-text=\"advisorCta.header\" :option-index=\"1\"></FindAnAdvisorCtaComponent>\r\n </template>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import FindAnAdvisorCtaComponent from \"components/advisor/find-an-advisor-cta.vue\";\r\n import CaptionedImagePair from \"components/shared/captioned-image-pair.vue\";\r\n import { FindAnAdvisorCTA } from \"interfaces/advisor\";\r\n import { ItineraryItem, ItineraryTableOfContents } from \"interfaces/article\";\r\n import { isEmbeddedMode } from \"services/layout/environment\";\r\n import { PropType } from \"vue\";\r\n\r\n \r\n const props = defineProps({\r\n tableOfContents: {\r\n type: Object as PropType<ItineraryTableOfContents>,\r\n default: () => ({})\r\n },\r\n content: {\r\n type: Array as PropType<ItineraryItem[]>,\r\n default: () => [] as ItineraryItem[]\r\n },\r\n advisorCta: {\r\n type: Object as PropType<FindAnAdvisorCTA>,\r\n default: () => ({})\r\n }\r\n });\r\n\r\n const lastItemInFirstColumn = Math.floor((props.tableOfContents.items.length + 1) / 2) - 1;\r\n\r\n \r\n</script>\r\n","<template>\r\n <div v-if=\"hasContent\" class=\"container px-lg-0\">\r\n <h2 v-if=\"header\" class=\"text--serif mb-2\" v-html=\"header\"></h2>\r\n <content-tiles :content-tiles=\"relatedArticles\" layout-class=\"-mixed\" :should-track-content-tile-views=\"true\"></content-tiles>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import ContentTiles from \"components/shared/content-tiles.vue\";\r\n import { DotCMSBasicArticleResponse } from \"interfaces/responses/dotcms-responses\";\r\n import { ContentTile } from \"interfaces/card\";\r\n import { CmsSearchCriteria } from \"interfaces/cms\";\r\n import { getArticles } from \"services/api/articles\";\r\n import { generateCmsImageUrl } from \"services/helpers/images\";\r\n import { cobrandLink } from \"virtuoso-shared-web-ui\";\r\n import { PropType, ref } from \"vue\";\r\n\r\n const props = defineProps({\r\n header: {\r\n type: String,\r\n default: \"\"\r\n },\r\n searchCriteria: {\r\n type: Object as PropType<CmsSearchCriteria>,\r\n default: () => ({})\r\n }\r\n });\r\n\r\n const hasContent = ref(false);\r\n const relatedArticles = ref<ContentTile[]>([]);\r\n\r\n getArticles(props.searchCriteria)\r\n .then((articlesJSON) => {\r\n\r\n if (articlesJSON.articles.length) {\r\n populateContentTiles(articlesJSON.articles);\r\n } else {\r\n console.log(\"No related articles found, getting latest articles instead.\");\r\n\r\n getArticles({\r\n contentTypes: [\"ConsumerArticleBasic\"],\r\n limit: 5,\r\n sort: \"ConsumerArticleBasic.publish desc\"\r\n }).then((fallbackArticlesJSON) => {\r\n\r\n if (fallbackArticlesJSON.articles.length) {\r\n populateContentTiles(fallbackArticlesJSON.articles);\r\n }\r\n\r\n }, () => {\r\n // Don't need to display an error on screen\r\n console.error(\"Error retrieving latest articles\");\r\n });\r\n }\r\n\r\n }, () => {\r\n // Don't need to display an error on screen\r\n console.error(\"Error retrieving related articles\");\r\n });\r\n\r\n\r\n function populateContentTiles(articles: DotCMSBasicArticleResponse[]) {\r\n const articleCount = articles.length;\r\n\r\n articles.forEach((article: DotCMSBasicArticleResponse, articleIndex: number) => {\r\n relatedArticles.value.push({\r\n identifier: article.identifier,\r\n imageCropFocus: (article.previewImageCropFocus) ? article.previewImageCropFocus : \"center\",\r\n imageUrl: generateCmsImageUrl(article.previewImage, { width: 576 }),\r\n sponsoredText: (article.isSponsoredContent === \"1\") ? \"Sponsored\" : \"\",\r\n title: article.headline,\r\n url: cobrandLink(`/travel/articles/${article.articleUrl}`),\r\n tileLayout: (articleCount === 3 || (articleCount === 5 && articleIndex >= 2)) ? \"-square\" : \"\"\r\n });\r\n });\r\n\r\n hasContent.value = true;\r\n }\r\n</script>\r\n","<template>\r\n <component :is=\"componentToRender.component\" v-if=\"componentToRender\" v-bind=\"componentToRender.props\"></component>\r\n <RelatedArticles v-else-if=\"relatedArticlesSearchCriteria\" header=\"More Stories\" :search-criteria=\"relatedArticlesSearchCriteria\"></RelatedArticles>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import RelatedArticles from \"components/article/related-articles.vue\";\r\n import { buildRelatedArticlesQuery } from \"services/transformers/article\";\r\n import { getFeatureFlag, initializeFeatureFlags } from \"services/feature-flags\";\r\n import { defineAsyncComponent, ref, shallowRef, type Component, type PropType } from \"vue\";\r\n\r\n const props = defineProps({\r\n tags: {\r\n type: Array as PropType<string[]>,\r\n default: (): string[] => []\r\n },\r\n identifier: {\r\n type: String,\r\n default: \"\"\r\n }\r\n });\r\n\r\n const componentToRender = shallowRef(null);\r\n const relatedArticlesSearchCriteria = ref(null);\r\n\r\n const componentMap = new Map<string, {component: Component; props: Record<string, unknown>}>([\r\n [\"destination-hub:|south-pacific|australia\",\r\n {\r\n component: defineAsyncComponent(() => import(\"components/destination/custom/australia-destination-hub-interactive-map.vue\")),\r\n props: { destinationTag: \"destination-hub:|south-pacific|australia\" }\r\n }\r\n ]\r\n ]);\r\n\r\n initializeFeatureFlags()\r\n .finally(() => {\r\n if (getFeatureFlag(\"consumer-2025-02-article-dde-map-related-content-temp\") === true ) {\r\n for (const tag of props.tags) {\r\n if (componentMap.has(tag)) {\r\n componentToRender.value = componentMap.get(tag);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // If no matching components are found, fallback to the relatedArticles\r\n if (!componentToRender.value) {\r\n relatedArticlesSearchCriteria.value = buildRelatedArticlesQuery(props.tags.join(), props.identifier);\r\n }\r\n });\r\n</script>","<template>\r\n <section>\r\n <div class=\"container mt-3 px-lg-0\">\r\n <ArticleCards header-text=\"Articles\" :search-criteria=\"articleSearchCriteria\" :articles-per-page=\"6\" :show-more=\"true\" page-name=\"Article Landing Page\"></ArticleCards>\r\n </div>\r\n </section>\r\n</template>\r\n\r\n\r\n<script setup lang=\"ts\">\r\n import ArticleCards from \"components/article/article-cards.vue\";\r\n import { CmsSearchCriteria } from \"interfaces/cms\";\r\n\r\n // Special secret query string paramter to sort by modified date rather than published date\r\n const shouldSortByModifiedDate = window.location.search.includes(\"sort=modified\");\r\n\r\n const articleSearchCriteria: CmsSearchCriteria = {\r\n contentTypes: [\"ConsumerArticleBasic\"],\r\n sort: shouldSortByModifiedDate ? \"modDate desc\" : \"ConsumerArticleBasic.publish desc\"\r\n };\r\n\r\n</script>\r\n","<template>\r\n <div v-if=\"adZoneId\" :class=\"['ad-zone', (isFancy) ? '-fancy' : '']\">\r\n <div v-if=\"isFancy\" class=\"-top-line\" data-testid=\"ad-zone-label\" v-html=\"adZoneLabel\"></div>\r\n <broadstreet-zone :zone-id=\"adZoneId\"></broadstreet-zone>\r\n </div>\r\n</template>\r\n\r\n\r\n<script setup lang=\"ts\">\r\n\r\n const props = defineProps({\r\n adZoneId: {\r\n type: Number,\r\n default: undefined\r\n },\r\n isFancy: {\r\n type: Boolean,\r\n default: false\r\n },\r\n label: {\r\n type: String,\r\n default: undefined\r\n }\r\n });\r\n\r\n const adZoneLabel = (props.label) ? props.label : \"Advertisement\";\r\n\r\n</script>\r\n","<template>\r\n <section v-if=\"isReady\" ref=\"component-root\" class=\"px-lg-0\">\r\n <article class=\"vc-article\">\r\n <!-- Ad Zone 1 -->\r\n <ad-zone-component v-if=\"useTopAdZone\" :ad-zone-id=\"topAdZoneId\" :label=\"adZoneLabel\" :is-fancy=\"true\"></ad-zone-component>\r\n\r\n <article-header-component :content=\"articleHeader\"></article-header-component>\r\n\r\n <div class=\"container row mt-3 px-0\">\r\n <div class=\"col-12\">\r\n <h2 v-if=\"article.subhead\" class=\"article-section\" v-html=\"article.subhead\"></h2>\r\n\r\n <div v-if=\"article.articleTextIntro\" class=\"article-section\" v-html=\"article.articleTextIntro\"></div>\r\n\r\n <!-- Advisor Tip -->\r\n <AdvisorTipComponent v-if=\"article.advisorTipText && !article.itineraryContent\" class=\"article-section\" :tip-text=\"article.advisorTipText\" :attribution=\"article.advisorTipAttribution\" :show-button=\"!article.hideFindAnAdvisor\"></AdvisorTipComponent>\r\n\r\n <captioned-media-component v-if=\"article.articleBody[0] && article.articleBody[0].articleMedia\" :media-data=\"article.articleBody[0].articleMedia\" container-class=\"my-3\"></captioned-media-component>\r\n <div v-if=\"article.articleBody[0] && article.articleBody[0].articleText\" class=\"article-section\"\r\n v-html=\"article.articleBody[0].articleText\"></div>\r\n\r\n <!-- Ad Zone 2 -->\r\n <ad-zone-component :ad-zone-id=\"adZoneId\" :label=\"adZoneLabel\" :is-fancy=\"true\"></ad-zone-component>\r\n\r\n <captioned-media-component v-if=\"article.articleBody[1] && article.articleBody[1].articleMedia\" :media-data=\"article.articleBody[1].articleMedia\" container-class=\"my-3\"></captioned-media-component>\r\n <div v-if=\"article.articleBody[1] && article.articleBody[1].articleText\" class=\"article-section\"\r\n v-html=\"article.articleBody[1].articleText\"></div>\r\n\r\n <captioned-media-component v-if=\"article.articleBody[2] && article.articleBody[2].articleMedia\" :media-data=\"article.articleBody[2].articleMedia\" container-class=\"my-3\"></captioned-media-component>\r\n <div v-if=\"article.articleBody[2] && article.articleBody[2].articleText\" class=\"article-section\"\r\n v-html=\"article.articleBody[2].articleText\"></div>\r\n\r\n <!-- Find an Advisor -->\r\n <find-an-advisor-cta-component v-if=\"!article.hideFindAnAdvisor && !isEmbeddedMode() && !article.itineraryContent\" :button-text=\"findAnAdvisorCta.buttonText\" :custom-button-link=\"findAnAdvisorCta.buttonLink\" :custom-content-text=\"findAnAdvisorCta.contentText\" :custom-header-text=\"findAnAdvisorCta.header\" :option-index=\"1\"></find-an-advisor-cta-component>\r\n\r\n <captioned-media-component v-if=\"article.articleBody[3] && article.articleBody[3].articleMedia\" :media-data=\"article.articleBody[3].articleMedia\" container-class=\"my-3\"></captioned-media-component>\r\n <div v-if=\"article.articleBody[3] && article.articleBody[3].articleText\" class=\"article-section\"\r\n v-html=\"article.articleBody[3].articleText\"></div>\r\n\r\n <!-- Extended captioned image and article text pairs -->\r\n <template v-if=\"extendedBodyContent\">\r\n <template v-for=\"(mediaTextPair, index) in extendedBodyContent\">\r\n <captioned-media-component v-if=\"mediaTextPair.articleMedia\" :key=\"'m-'+index\" :media-data=\"mediaTextPair.articleMedia\" container-class=\"my-3\"></captioned-media-component>\r\n <div v-if=\"mediaTextPair.articleText\" :key=\"'t='+index\" class=\"article-section\" v-html=\"mediaTextPair.articleText\"></div>\r\n </template>\r\n </template>\r\n\r\n <template v-if=\"article.itineraryContent\">\r\n <ArticleItinerary :table-of-contents=\"article.itineraryContent.toc\" :content=\"article.itineraryContent.body\" :advisor-cta=\"findAnAdvisorCta\"></ArticleItinerary>\r\n <AdvisorTipComponent v-if=\"article.advisorTipText\" class=\"article-section\" :tip-text=\"article.advisorTipText\" :attribution=\"article.advisorTipAttribution\" :show-button=\"!article.hideFindAnAdvisor\"></AdvisorTipComponent>\r\n </template>\r\n\r\n <!-- Ad Zone 3 -->\r\n <ad-zone-component :ad-zone-id=\"adZoneId\" :is-fancy=\"true\"></ad-zone-component>\r\n\r\n <div v-if=\"hasProducts\" class=\"article-product-cards-container\">\r\n <h2 class=\"mt-5 mb-2\" v-html=\"productsHeader\"></h2>\r\n <article-product-cards-component :content=\"products\"></article-product-cards-component>\r\n </div>\r\n </div>\r\n </div>\r\n </article>\r\n <RelatedContent :tags=\"articleTags\" :identifier=\"article.identifier\"></RelatedContent>\r\n </section>\r\n <section v-else-if=\"displayFallback\" class=\"container my-3 px-lg-0\">\r\n We couldn't find the article you're looking for, but these stories might inspire you.\r\n <ArticlesLanding />\r\n </section>\r\n <LogoSplash v-else />\r\n</template>\r\n\r\n\r\n<script setup lang=\"ts\">\r\n import AdvisorTipComponent from \"components/advisor/advisor-tip.vue\";\r\n import FindAnAdvisorCtaComponent from \"components/advisor/find-an-advisor-cta.vue\";\r\n import ArticleHeaderComponent from \"components/article/article-header.vue\";\r\n import ArticleItinerary from \"components/article/article-itinerary.vue\";\r\n import ArticleProductCardsComponent from \"components/article/article-product-cards.vue\";\r\n import RelatedContent from \"components/article/related-content.vue\";\r\n import ArticlesLanding from \"components/pages/articles-landing.vue\";\r\n import AdZoneComponent from \"components/shared/ad-zone.vue\";\r\n import CaptionedMediaComponent from \"components/shared/captioned-media.vue\";\r\n import LogoSplash from \"components/shared/logo-splash.vue\";\r\n import { FindAnAdvisorCTA } from \"interfaces/advisor\";\r\n import { ArticleBasic, ArticleHeader } from \"interfaces/article\";\r\n import { ContentCard } from \"interfaces/card\";\r\n import { ArticleMediaTextPair } from \"interfaces/image\";\r\n import { getArticle } from \"services/api/articles\";\r\n import { toastError } from \"services/helpers/toasts\";\r\n import { isEmbeddedMode } from \"services/layout/environment\";\r\n import { goToURLHash } from \"services/layout/navigation\";\r\n import { transformCmsBasicArticle, transformCmsBasicArticleFindAnAdvisorCta, transformCmsBasicArticleHeader } from \"services/transformers/article\";\r\n import { transformCmsArticleProductCards, translateLinksToConsumerUrl } from \"services/transformers/products\";\r\n import { trackEvent } from \"services/analytics\";\r\n import { cobrandLinks, parseURLParameters } from \"virtuoso-shared-web-ui\";\r\n import { computed, nextTick, ref, useTemplateRef } from \"vue\";\r\n\r\n const article = ref({} as ArticleBasic);\r\n const articleHeader = ref({} as ArticleHeader);\r\n const articleTags = ref([] as string[]);\r\n const isReady = ref(false);\r\n const displayFallback = ref(false);\r\n const useTopAdZone = ref(false);\r\n const topAdZoneId = 163084;\r\n const extendedBodyContent = ref([] as ArticleMediaTextPair[]);\r\n const findAnAdvisorCta = ref({} as FindAnAdvisorCTA);\r\n const productsHeader = ref(\"\");\r\n const products = ref([] as ContentCard[]);\r\n const hideFindAnAdvisor = ref(false);\r\n const componentRoot = useTemplateRef<HTMLElement>(\"component-root\");\r\n\r\n const adZoneId = computed(() => article.value.isSponsored ? 97491 : 78463); // Sponsored articles use a separate ad zone ID\r\n\r\n const adZoneLabel = computed(() => {\r\n const numArticleFields = article.value.articleBody.filter((item) => (item.articleText)).length;\r\n const numImageFields = article.value.articleBody.filter((item) => (item.articleMedia.imageUrl)).length;\r\n\r\n return (numArticleFields > 1 || numImageFields > 1) ? \"Story continues below advertisement\" : \"\";\r\n });\r\n\r\n const hasProducts = computed(() => {\r\n // This array of objects is populated with empty values by default, so we can't just check length\r\n let isProductPopulated = false;\r\n\r\n for (let i = 0; i <= 5; i++) {\r\n if (products.value[i]?.content || products.value[i]?.imageUrl || products.value[i]?.title) {\r\n isProductPopulated = true;\r\n break;\r\n }\r\n }\r\n\r\n return isProductPopulated;\r\n });\r\n\r\n getArticle(window.VIRTUOSO.articleKey).then((articleResponse) => {\r\n \r\n useTopAdZone.value = articleResponse.useTopAdZone;\r\n\r\n article.value = transformCmsBasicArticle(articleResponse);\r\n\r\n articleHeader.value = transformCmsBasicArticleHeader(articleResponse);\r\n\r\n articleTags.value = (articleResponse.tags) ? articleResponse.tags.split(\",\") : [];\r\n\r\n findAnAdvisorCta.value = transformCmsBasicArticleFindAnAdvisorCta(articleResponse);\r\n\r\n products.value = transformCmsArticleProductCards(articleResponse);\r\n productsHeader.value = articleResponse.productHeaderText ?? \"\";\r\n\r\n if (article.value.articleBody.length > 4) {\r\n extendedBodyContent.value = article.value.articleBody.slice(4);\r\n }\r\n\r\n // Suppress the Find an Advisor component if needed\r\n const qsParams = parseURLParameters();\r\n hideFindAnAdvisor.value = qsParams.HideFindAnAdvisor === \"1\";\r\n\r\n // At this point we can render things\r\n isReady.value = true;\r\n\r\n nextTick(() => { \r\n translateLinksToConsumerUrl(componentRoot.value);\r\n cobrandLinks(componentRoot.value);\r\n goToURLHash(); // Scroll to an anchor/ID in the content if there's a hash in the URL\r\n });\r\n\r\n const destinationHubTags = articleHeader.value.tags?.split(\",\").filter((tag) => tag.startsWith(\"destination-hub:\")) || [];\r\n // Track article with GA4\r\n trackEvent(\"view_item\",\r\n {\r\n item_id: article.value.identifier,\r\n item_name: articleHeader.value.headline,\r\n item_category: \"web_article\",\r\n item_category2: articleHeader.value.author,\r\n item_category3: (article.value.isSponsored) ? \"Sponsored\" : \"Not sponsored\",\r\n item_category4: articleHeader.value.categories.join(\", \"),\r\n // Conditional only added properties\r\n ...((destinationHubTags.length && { item_list_name: destinationHubTags.join(\", \") }))\r\n });\r\n\r\n }, () => {\r\n toastError(\"Error retrieving data\");\r\n displayFallback.value = true;\r\n });\r\n\r\n</script>\r\n","import ArticleBasicComponent from \"components/pages/article-basic.vue\";\r\nimport { createApp } from \"vue\";\r\nimport { mountApp } from \"vue-app\";\r\n\r\n\r\nconst app = createApp(ArticleBasicComponent);\r\n\r\nmountApp(app, \"page-app\");\r\n"],"file":"scripts/articles-B_w0Hsw2.js"}