PageSourceSearch

https://www.viceroyhotelsandresorts.com/sites/default/files/js/js_…0TGpUWM7ROBuI4Vdvy3ySRn_rttwVoh_9Y_jjt8hOHS

js viceroyhotelsandresorts.com collected 2026-10-02 05:59:22 UTC 8,236 bytes, 120 lines download raw bytes

1/* @license GPL-2.0-or-later https://www.drupal.org/licensing/faq */
2(function(Drupal,once,drupalSettings){'use strict';const visibleBodyClass='conversion-banner-visible';const revealThreshold=75;function getPreferredBanner(wrapper){return wrapper.querySelector('.js-conversion-banner[data-property-specific="true"]')||wrapper.querySelector('.js-conversion-banner');}function prepareMobileMessages(banner){banner.querySelectorAll('.js-conversion-banner-message').forEach((message)=>{const links=message.querySelectorAll('a[href]');const link=links.length===1?links[0]:null;const hasMobileMessage=link&&link.getAttribute('href').trim()!==''&&link.textContent.trim()!=='';message.classList.toggle('has-mobile-message',hasMobileMessage);if(!hasMobileMessage)return;const fullMessage=document.createElement('div');fullMessage.classList.add('conversion-banner__full-message');while(message.firstChild)fullMessage.appendChild(message.firstChild);const mobileMessage=document.createElement('a');mobileMessage.classList.add('conversion-banner__mobile-message');mobileMessage.setAttribute('href',link.getAttribute('href'));mobileMessage.textContent=link.textContent.trim();['hreflang','target','rel'].forEach((attribute)=>{const value=link.getAttribute(attribute);if(value)mobileMessage.setAttribute(attribute,value);});message.append(fullMessage,mobileMessage);});}function mountCarousel(banner){const carousel=banner.querySelector('.js-conversion-banner-carousel');if(!carousel||typeof Splide==='undefined')return;const slider=new Splide(carousel,{type:'loop',pagination:false,keyboard:'focused',speed:850,i18n:{prev:Drupal.t('Previous promotion'),next:Drupal.t('Next promotion')}});slider.mount();}function showPreview(banner){const wrapper=banner.closest('.c-site-alerts');if(wrapper)wrapper.style.display='block';banner.style.display='block';banner.classList.add('conversion-banner--preview','is-visible');banner.setAttribute('aria-hidden','false');}function initializeReveal(banner){let frameRequested=false;const update=()=>{frameRequested=false;const isRendered=banner.getClientRects().length>0;const scrollPosition=window.scrollY||window.pageYOffset;const hasFocus=banner.contains(document.activeElement);const isVisible=isRendered&&(scrollPosition>=revealThreshold||hasFocus);banner.classList.toggle('is-visible',isVisible);banner.setAttribute('aria-hidden',isVisible?'false':'true');document.body.classList.toggle(visibleBodyClass,isVisible);};const requestUpdate=()=>{if(frameRequested)return;frameRequested=true;window.requestAnimationFrame(update);};window.addEventListener('scroll',requestUpdate,{passive:true});window.addEventListener('resize',requestUpdate);window.addEventListener('pageshow',requestUpdate);banner.addEventListener('focusout',requestUpdate);requestUpdate();}Drupal.behaviors.conversionBanner={attach(context){once('conversionBanner','.js-conversion-banner',context).forEach((banner)=>{const wrapper=banner.closest('.c-site-alerts')||document;if(getPreferredBanner(wrapper)!==banner){once.remove('conversionBanner',banner);return;}prepareMobileMessages(banner);const previewMode=Boolean(drupalSettings.verb_site_alert&&drupalSettings.verb_site_alert.previewMode);if(previewMode){showPreview(banner);mountCarousel(banner);return;}mountCarousel(banner);initializeReveal(banner);});}};})(Drupal,once,drupalSettings);;
3(function (Drupal, once) {
4  'use strict';
5
6  // Booking links Drupal does not build: anything an editor pasted into a
7  // WYSIWYG or link field still points at SynXis or AZDS. When that link is
8  // for a Dolli property, its href is rewritten to /book/{hotelCode} so a
9  // right-click or "open in new tab" reaches Dolli too, and the dolliBookingLinks
10  // behavior in dollieBooking.js then opens the widget on a left-click.
11  // Links for non-Dolli properties are left alone.
12  //
13  // Runs on every page (attached with drupalSettings.dolli_properties in
14  // viceroy_preprocess_region__header()), and must attach before
15  // dolliBookingLinks, which is why dollieBookingWidget depends on it.
16  Drupal.behaviors.dolliLinkRewrite = {
17    attach: function (context, settings) {
18      const dolliProperties = settings?.dolli_properties;
19      if (!dolliProperties) return;
20
21      once(
22        'dolli-link-rewrite',
23        'a[href*="reservations.viceroyhotelsandresorts.com"], a[href*="be.synxis.com"], a[href*="#/booking/step-1"]',
24        context
25      ).forEach((link) => {
26        const url = new URL(link.href, window.location.origin);
27        const isAzds = url.hash.indexOf('#/booking/step-1') !== -1;
28
29        // Only SynXis booking searches, which live at the root. Leaves other
30        // SynXis pages alone, e.g. the Manage Reservations /signin link.
31        if (!isAzds && url.pathname !== '/') return;
32        const property = isAzds
33          ? this.propertyFromPath(url, dolliProperties)
34          : this.propertyFromHotelCode(url.searchParams.get('hotel'), dolliProperties);
35
36        if (!property) return;
37
38        const params = isAzds ? this.parseAzdsParams(url) : this.parseSynxisParams(url);
39        if (!params.startDate) {
40          params.startDate = property.arrive;
41          params.endDate = property.depart;
42        }
43
44        link.href = '/book/' + encodeURIComponent(property.hotel_code) + '?' + new URLSearchParams(params).toString();
45      });
46    },
47
48    propertyFromHotelCode: function (hotelCode, dolliProperties) {
49      if (!hotelCode) return null;
50      return Object.values(dolliProperties).find((property) => String(property.hotel_code) === hotelCode.trim()) ?? null;
51    },
52
53    // AZDS links point at the property page itself (/{slug}/#/booking/step-1,
54    // or a page beneath it), so the slug is the first path segment that
55    // matches a Dolli property. Skips a language prefix such as /e
55s/.
56    propertyFromPath: function (url, dolliProperties) {
57      const slug = url.pathname.split('/').filter(Boolean).find((segment) => dolliProperties[segment]);
58      return slug ? dolliProperties[slug] : null;
59    },
60
61    parseSynxisParams: function (url) {
62      const params = {};
63      const room = url.searchParams.get('room');
64      const promo = url.searchParams.get('promo');
65      const arrive = url.searchParams.get('arrive');
66      const depart = url.searchParams.get('depart');
67      if (arrive) {
68        params.startDate = arrive;
69        params.endDate = this.fixEndDate(arrive, depart);
70      }
71      if (promo) params.promoCode = promo;
72      // SynXis prepends a tab char (%09) to room codes.
73      if (room) params.roomTypeCode = room.trim();
74      return params;
75    },
76
77    parseAzdsParams: function (url) {
78      const params = {};
79      if (url.hash.indexOf('?') === -1) return params;
80      const hashParams = new URLSearchParams(url.hash.split('?')[1]);
81      const promo = hashParams.get('promo');
82      const arrive = hashParams.get('arrive');
83      const depart = hashParams.get('depart');
84      if (arrive) {
85        params.startDate = this.azdsDateToIso(arrive);
86        params.endDate = this.fixEndDate(params.startDate, depart ? this.azdsDateToIso(depart) : null);
87      }
88      if (promo) params.promoCode = promo;
89      return params;
90    },
91
92    // AZDS dates are m/d/Y; Dolli expects YYYY-MM-DD.
93    azdsDateToIso: function (dateStr) {
94      const parts = dateStr.split('/');
95      if (parts.length !== 3) return dateStr;
96      return parts[2] + '-' + parts[0].padStart(2, '0') + '-' + parts[1].padStart(2, '0');
97    },
98
99    // Returns endDate if it is at least one day after startDate; otherwise returns startDate + 1 day.
100    // Both dates must be YYYY-MM-DD strings. endDate may be null/undefined.
101    fixEndDate: function (startDate, endDate) {
102      const s = startDate.split('-').map(Number);
103      const startObj = new Date(s[0], s[1] - 1, s[2]);
104      let useEnd = new Date(s[0], s[1] - 1, s[2] + 1);
105
106      if (endDate) {
107        const e = endDate.split('-').map(Number);
108        const endObj = new Date(e[0], e[1] - 1, e[2]);
109        if (endObj > startObj) useEnd = endObj;
110      }
111
112      const y = useEnd.getFullYear();
113      const m = String(useEnd.getMonth() + 1).padStart(2, '0');
114      const d = String(useEnd.getDate()).padStart(2, '0');
115      return y + '-' + m + '-' + d;
116    }
117  };
118
119})(Drupal, once);
120;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.